diff --git a/apps/web/src/components/editor/action-bar.tsx b/apps/web/src/components/editor/action-bar.tsx
index 606cfdc9c..8b91914af 100644
--- a/apps/web/src/components/editor/action-bar.tsx
+++ b/apps/web/src/components/editor/action-bar.tsx
@@ -29,6 +29,7 @@ import {
FocusMode,
Fullscreen,
Lock,
+ NewTab,
NormalMode,
Note,
NoteRemove,
@@ -107,6 +108,12 @@ export function EditorActionBar() {
const isTablet = useTablet();
const tools = [
+ {
+ title: strings.newTab(),
+ icon: NewTab,
+ enabled: true,
+ onClick: () => useEditorStore.getState().addTab()
+ },
{
title: strings.undo(),
icon: Undo,
@@ -244,7 +251,10 @@ export function EditorActionBar() {
mr:
hasNativeWindowControls && !isMac() && !isMobile && !isTablet
? `calc(100vw - env(titlebar-area-width))`
- : 0
+ : 1,
+ pl: 1,
+ borderLeft: "1px solid var(--border)",
+ flexShrink: 0
}}
>
{tools.map((tool) => (
@@ -255,14 +265,13 @@ export function EditorActionBar() {
title={tool.title}
key={tool.title}
sx={{
- height: "100%",
+ p: 1,
alignItems: "center",
bg: "transparent",
display: [
"hideOnMobile" in tool && tool.hideOnMobile ? "none" : "flex",
tool.hidden ? "none" : "flex"
],
- borderRadius: 0,
flexShrink: 0,
"&:hover svg path": {
fill:
@@ -273,7 +282,7 @@ export function EditorActionBar() {
}}
onClick={tool.onClick}
>
-
+
))}
@@ -288,173 +297,172 @@ function TabStrip() {
const canGoForward = useEditorStore((store) => store.canGoForward);
return (
- ({
- backgroundColor: "transparent",
- "--ms-track-size": "6px"
- })}
- thumbStyle={() => ({ height: 3 })}
- onWheel={(e) => {
- const scrollcontainer = document.querySelector(".tabsScroll");
- if (!scrollcontainer) return;
- if (e.deltaY > 0) scrollcontainer.scrollLeft += 100;
- else if (e.deltaY < 0) scrollcontainer.scrollLeft -= 100;
- }}
- >
+
{
- e.stopPropagation();
- useEditorStore.getState().addTab();
+ onDoubleClick={(e) => e.stopPropagation()}
+ >
+
+
+
+ ({
+ backgroundColor: "transparent",
+ "--ms-track-size": "6px"
+ })}
+ thumbStyle={() => ({ height: 3 })}
+ onWheel={(e) => {
+ const scrollcontainer = document.querySelector(".tabsScroll");
+ if (!scrollcontainer) return;
+ if (e.deltaY > 0) scrollcontainer.scrollLeft += 100;
+ else if (e.deltaY < 0) scrollcontainer.scrollLeft -= 100;
}}
- data-test-id="tabs"
>
e.stopPropagation()}
+ onDoubleClick={async (e) => {
+ e.stopPropagation();
+ useEditorStore.getState().addTab();
+ }}
+ data-test-id="tabs"
>
-
-
-
- {
- if (from === to) return;
- const tabs = useEditorStore.getState().tabs.slice();
- const isToPinned = tabs[to].pinned;
- const [fromTab] = tabs.splice(from, 1);
+ {
+ if (from === to) return;
+ const tabs = useEditorStore.getState().tabs.slice();
+ const isToPinned = tabs[to].pinned;
+ const [fromTab] = tabs.splice(from, 1);
- // if the tab where this tab is being dropped is pinned,
- // let's pin our tab too.
- if (isToPinned) {
- fromTab.pinned = true;
- }
- // unpin the tab if it is moved.
- else if (fromTab.pinned) fromTab.pinned = false;
+ // if the tab where this tab is being dropped is pinned,
+ // let's pin our tab too.
+ if (isToPinned) {
+ fromTab.pinned = true;
+ }
+ // unpin the tab if it is moved.
+ else if (fromTab.pinned) fromTab.pinned = false;
- tabs.splice(to, 0, fromTab);
- useEditorStore.setState({ tabs });
- }}
- renderItem={({ item: tab, index: i }) => {
- const session = useEditorStore.getState().getSession(tab.sessionId);
- if (!session) return null;
+ tabs.splice(to, 0, fromTab);
+ useEditorStore.setState({ tabs });
+ }}
+ renderItem={({ item: tab, index: i }) => {
+ const session = useEditorStore
+ .getState()
+ .getSession(tab.sessionId);
+ if (!session) return null;
- const isUnsaved =
- session.type === "default" &&
- session.saveState === SaveState.NotSaved;
+ const isUnsaved =
+ session.type === "default" &&
+ session.saveState === SaveState.NotSaved;
- return (
- {
- if (tab.id !== currentTab) {
- useEditorStore.getState().focusTab(tab.id);
+ return (
+ useEditorStore.getState().closeTabs(tab.id)}
- onCloseAll={() =>
- useEditorStore
- .getState()
- .closeTabs(
- ...tabs.filter((s) => !s.pinned).map((s) => s.id)
- )
- }
- onCloseOthers={() =>
- useEditorStore
- .getState()
- .closeTabs(
- ...tabs
- .filter((s) => s.id !== tab.id && !s.pinned)
- .map((s) => s.id)
- )
- }
- onCloseToTheRight={() =>
- useEditorStore
- .getState()
- .closeTabs(
- ...tabs
- .filter((s, index) => index > i && !s.pinned)
- .map((s) => s.id)
- )
- }
- onCloseToTheLeft={() =>
- useEditorStore
- .getState()
- .closeTabs(
- ...tabs
- .filter((s, index) => index < i && !s.pinned)
- .map((s) => s.id)
- )
- }
- onRevealInList={
- "note" in session
- ? () =>
- AppEventManager.publish(
- AppEvents.revealItemInList,
- session.note.id,
- true
- )
- : undefined
- }
- onPin={() => {
- useEditorStore.setState((state) => {
- // preview tabs can never be pinned.
- state.tabs[i].pinned = !tab.pinned;
- state.tabs.sort((a, b) =>
- a.pinned === b.pinned ? 0 : a.pinned ? -1 : 1
- );
- });
- }}
- />
- );
- }}
- />
-
-
-
+ isUnsaved={isUnsaved}
+ isActive={tab.id === currentTab}
+ isPinned={!!tab.pinned}
+ isLocked={isLockedSession(session)}
+ type={session.type}
+ onFocus={() => {
+ if (tab.id !== currentTab) {
+ useEditorStore.getState().focusTab(tab.id);
+ }
+ }}
+ onClose={() => useEditorStore.getState().closeTabs(tab.id)}
+ onCloseAll={() =>
+ useEditorStore
+ .getState()
+ .closeTabs(
+ ...tabs.filter((s) => !s.pinned).map((s) => s.id)
+ )
+ }
+ onCloseOthers={() =>
+ useEditorStore
+ .getState()
+ .closeTabs(
+ ...tabs
+ .filter((s) => s.id !== tab.id && !s.pinned)
+ .map((s) => s.id)
+ )
+ }
+ onCloseToTheRight={() =>
+ useEditorStore
+ .getState()
+ .closeTabs(
+ ...tabs
+ .filter((s, index) => index > i && !s.pinned)
+ .map((s) => s.id)
+ )
+ }
+ onCloseToTheLeft={() =>
+ useEditorStore
+ .getState()
+ .closeTabs(
+ ...tabs
+ .filter((s, index) => index < i && !s.pinned)
+ .map((s) => s.id)
+ )
+ }
+ onRevealInList={
+ "note" in session
+ ? () =>
+ AppEventManager.publish(
+ AppEvents.revealItemInList,
+ session.note.id,
+ true
+ )
+ : undefined
+ }
+ onPin={() => {
+ useEditorStore.setState((state) => {
+ // preview tabs can never be pinned.
+ state.tabs[i].pinned = !tab.pinned;
+ state.tabs.sort((a, b) =>
+ a.pinned === b.pinned ? 0 : a.pinned ? -1 : 1
+ );
+ });
+ }}
+ />
+ );
+ }}
+ />
+
+
+
);
}
@@ -530,8 +538,9 @@ function Tab(props: TabProps) {
sx={{
height: "100%",
cursor: "pointer",
- px: 2,
+ pl: 2,
borderRight: "1px solid var(--border)",
+ ":last-of-type": { borderRight: 0 },
transform: CSS.Transform.toString(transform),
transition,
@@ -543,7 +552,7 @@ function Tab(props: TabProps) {
flexShrink: 0,
":hover": {
"& .closeTabButton": {
- visibility: "visible"
+ opacity: 1
},
bg: isActive ? "hover-selected" : "hover"
}
@@ -607,14 +616,13 @@ function Tab(props: TabProps) {
{...attributes}
>
{
if (e.button == 0) onFocus();
}}
>
{
@@ -653,10 +662,14 @@ function Tab(props: TabProps) {
) : (
{
if (e.button == 0) {
@@ -665,7 +678,7 @@ function Tab(props: TabProps) {
}}
className="closeTabButton"
data-test-id={"tab-close-button"}
- size={16}
+ size={14}
/>
)}
diff --git a/apps/web/src/components/icons/index.tsx b/apps/web/src/components/icons/index.tsx
index 20b486974..2ce356863 100644
--- a/apps/web/src/components/icons/index.tsx
+++ b/apps/web/src/components/icons/index.tsx
@@ -219,7 +219,8 @@ import {
mdiOpenInNew,
mdiTagOutline,
mdiChatQuestionOutline,
- mdiNoteRemoveOutline
+ mdiNoteRemoveOutline,
+ mdiTabPlus
} from "@mdi/js";
import { useTheme } from "@emotion/react";
import { Theme } from "@notesnook/theme";
@@ -273,7 +274,8 @@ const MDIIconWrapper = memo(
(prev, next) =>
prev.rotate === next.rotate &&
prev.color === next.color &&
- prev.title === next.title
+ prev.title === next.title &&
+ prev.size === next.size
);
export type IconProps = FlexProps & Omit;
@@ -560,3 +562,4 @@ export const ClearCache = createIcon(mdiBroom);
export const OpenInNew = createIcon(mdiOpenInNew);
export const Coupon = createIcon(mdiTagOutline);
export const Support = createIcon(mdiChatQuestionOutline);
+export const NewTab = createIcon(mdiTabPlus);