web: more compact and unified action bar

This commit is contained in:
Abdullah Atta
2025-02-01 12:18:47 +05:00
parent 3b86e51c49
commit 3bcd288bc7
2 changed files with 184 additions and 168 deletions

View File

@@ -29,6 +29,7 @@ import {
FocusMode, FocusMode,
Fullscreen, Fullscreen,
Lock, Lock,
NewTab,
NormalMode, NormalMode,
Note, Note,
NoteRemove, NoteRemove,
@@ -107,6 +108,12 @@ export function EditorActionBar() {
const isTablet = useTablet(); const isTablet = useTablet();
const tools = [ const tools = [
{
title: strings.newTab(),
icon: NewTab,
enabled: true,
onClick: () => useEditorStore.getState().addTab()
},
{ {
title: strings.undo(), title: strings.undo(),
icon: Undo, icon: Undo,
@@ -244,7 +251,10 @@ export function EditorActionBar() {
mr: mr:
hasNativeWindowControls && !isMac() && !isMobile && !isTablet hasNativeWindowControls && !isMac() && !isMobile && !isTablet
? `calc(100vw - env(titlebar-area-width))` ? `calc(100vw - env(titlebar-area-width))`
: 0 : 1,
pl: 1,
borderLeft: "1px solid var(--border)",
flexShrink: 0
}} }}
> >
{tools.map((tool) => ( {tools.map((tool) => (
@@ -255,14 +265,13 @@ export function EditorActionBar() {
title={tool.title} title={tool.title}
key={tool.title} key={tool.title}
sx={{ sx={{
height: "100%", p: 1,
alignItems: "center", alignItems: "center",
bg: "transparent", bg: "transparent",
display: [ display: [
"hideOnMobile" in tool && tool.hideOnMobile ? "none" : "flex", "hideOnMobile" in tool && tool.hideOnMobile ? "none" : "flex",
tool.hidden ? "none" : "flex" tool.hidden ? "none" : "flex"
], ],
borderRadius: 0,
flexShrink: 0, flexShrink: 0,
"&:hover svg path": { "&:hover svg path": {
fill: fill:
@@ -273,7 +282,7 @@ export function EditorActionBar() {
}} }}
onClick={tool.onClick} onClick={tool.onClick}
> >
<tool.icon size={18} /> <tool.icon size={16} />
</Button> </Button>
))} ))}
</Flex> </Flex>
@@ -288,6 +297,35 @@ function TabStrip() {
const canGoForward = useEditorStore((store) => store.canGoForward); const canGoForward = useEditorStore((store) => store.canGoForward);
return ( return (
<Flex sx={{ flex: 1 }}>
<Flex
sx={{
px: 1,
borderRight: "1px solid var(--border)",
alignItems: "center",
flexShrink: 0
}}
onDoubleClick={(e) => e.stopPropagation()}
>
<Button
disabled={!canGoBack}
onClick={() => useEditorStore.getState().goBack()}
variant="secondary"
sx={{ p: 1, bg: "transparent" }}
data-test-id="go-back"
>
<ArrowLeft size={16} />
</Button>
<Button
disabled={!canGoForward}
onClick={() => useEditorStore.getState().goForward()}
variant="secondary"
sx={{ p: 1, bg: "transparent" }}
data-test-id="go-forward"
>
<ArrowRight size={16} />
</Button>
</Flex>
<ScrollContainer <ScrollContainer
className="tabsScroll" className="tabsScroll"
suppressScrollY suppressScrollY
@@ -315,33 +353,6 @@ function TabStrip() {
}} }}
data-test-id="tabs" data-test-id="tabs"
> >
<Flex
sx={{
px: 1,
borderRight: "1px solid var(--border)",
alignItems: "center"
}}
onDoubleClick={(e) => e.stopPropagation()}
>
<Button
disabled={!canGoBack}
onClick={() => useEditorStore.getState().goBack()}
variant="secondary"
sx={{ p: 1, bg: "transparent" }}
data-test-id="go-back"
>
<ArrowLeft size={15} />
</Button>
<Button
disabled={!canGoForward}
onClick={() => useEditorStore.getState().goForward()}
variant="secondary"
sx={{ p: 1, bg: "transparent" }}
data-test-id="go-forward"
>
<ArrowRight size={15} />
</Button>
</Flex>
<ReorderableList <ReorderableList
items={tabs} items={tabs}
moveItem={(from, to) => { moveItem={(from, to) => {
@@ -362,7 +373,9 @@ function TabStrip() {
useEditorStore.setState({ tabs }); useEditorStore.setState({ tabs });
}} }}
renderItem={({ item: tab, index: i }) => { renderItem={({ item: tab, index: i }) => {
const session = useEditorStore.getState().getSession(tab.sessionId); const session = useEditorStore
.getState()
.getSession(tab.sessionId);
if (!session) return null; if (!session) return null;
const isUnsaved = const isUnsaved =
@@ -375,7 +388,9 @@ function TabStrip() {
key={tab.sessionId} key={tab.sessionId}
title={ title={
session.title || session.title ||
("note" in session ? session.note.title : "Untitled") ("note" in session
? session.note.title
: strings.untitled())
} }
isUnsaved={isUnsaved} isUnsaved={isUnsaved}
isActive={tab.id === currentTab} isActive={tab.id === currentTab}
@@ -445,16 +460,9 @@ function TabStrip() {
); );
}} }}
/> />
<Button
variant="secondary"
sx={{ p: 1, bg: "transparent", alignSelf: "center", ml: 1 }}
onClick={() => useEditorStore.getState().addTab()}
data-test-id="new-tab"
>
<Plus size={18} />
</Button>
</Flex> </Flex>
</ScrollContainer> </ScrollContainer>
</Flex>
); );
} }
@@ -530,8 +538,9 @@ function Tab(props: TabProps) {
sx={{ sx={{
height: "100%", height: "100%",
cursor: "pointer", cursor: "pointer",
px: 2, pl: 2,
borderRight: "1px solid var(--border)", borderRight: "1px solid var(--border)",
":last-of-type": { borderRight: 0 },
transform: CSS.Transform.toString(transform), transform: CSS.Transform.toString(transform),
transition, transition,
@@ -543,7 +552,7 @@ function Tab(props: TabProps) {
flexShrink: 0, flexShrink: 0,
":hover": { ":hover": {
"& .closeTabButton": { "& .closeTabButton": {
visibility: "visible" opacity: 1
}, },
bg: isActive ? "hover-selected" : "hover" bg: isActive ? "hover-selected" : "hover"
} }
@@ -607,14 +616,13 @@ function Tab(props: TabProps) {
{...attributes} {...attributes}
> >
<Flex <Flex
mr={1}
onMouseUp={(e) => { onMouseUp={(e) => {
if (e.button == 0) onFocus(); if (e.button == 0) onFocus();
}} }}
> >
<Icon <Icon
data-test-id={`tab-icon${isUnsaved ? "-unsaved" : ""}`} data-test-id={`tab-icon${isUnsaved ? "-unsaved" : ""}`}
size={16} size={14}
color={ color={
isUnsaved ? "accent-error" : isActive ? "accent-selected" : "icon" isUnsaved ? "accent-error" : isActive ? "accent-selected" : "icon"
} }
@@ -640,7 +648,8 @@ function Tab(props: TabProps) {
sx={{ sx={{
":hover": { bg: "border" }, ":hover": { bg: "border" },
borderRadius: "default", borderRadius: "default",
flexShrink: 0 flexShrink: 0,
ml: 1
}} }}
size={14} size={14}
onMouseUp={(e) => { onMouseUp={(e) => {
@@ -653,10 +662,14 @@ function Tab(props: TabProps) {
) : ( ) : (
<Cross <Cross
sx={{ sx={{
visibility: isActive && active?.id !== id ? "visible" : "hidden",
":hover": { bg: "border" },
borderRadius: "default", borderRadius: "default",
flexShrink: 0 flexShrink: 0,
opacity: isActive || active?.id === id ? 1 : 0,
ml: "small",
mr: 1,
"&:hover": {
bg: "hover-secondary"
}
}} }}
onMouseUp={(e) => { onMouseUp={(e) => {
if (e.button == 0) { if (e.button == 0) {
@@ -665,7 +678,7 @@ function Tab(props: TabProps) {
}} }}
className="closeTabButton" className="closeTabButton"
data-test-id={"tab-close-button"} data-test-id={"tab-close-button"}
size={16} size={14}
/> />
)} )}
</Flex> </Flex>

View File

@@ -219,7 +219,8 @@ import {
mdiOpenInNew, mdiOpenInNew,
mdiTagOutline, mdiTagOutline,
mdiChatQuestionOutline, mdiChatQuestionOutline,
mdiNoteRemoveOutline mdiNoteRemoveOutline,
mdiTabPlus
} from "@mdi/js"; } from "@mdi/js";
import { useTheme } from "@emotion/react"; import { useTheme } from "@emotion/react";
import { Theme } from "@notesnook/theme"; import { Theme } from "@notesnook/theme";
@@ -273,7 +274,8 @@ const MDIIconWrapper = memo(
(prev, next) => (prev, next) =>
prev.rotate === next.rotate && prev.rotate === next.rotate &&
prev.color === next.color && prev.color === next.color &&
prev.title === next.title prev.title === next.title &&
prev.size === next.size
); );
export type IconProps = FlexProps & Omit<MDIIconWrapperProps, "path">; export type IconProps = FlexProps & Omit<MDIIconWrapperProps, "path">;
@@ -560,3 +562,4 @@ export const ClearCache = createIcon(mdiBroom);
export const OpenInNew = createIcon(mdiOpenInNew); export const OpenInNew = createIcon(mdiOpenInNew);
export const Coupon = createIcon(mdiTagOutline); export const Coupon = createIcon(mdiTagOutline);
export const Support = createIcon(mdiChatQuestionOutline); export const Support = createIcon(mdiChatQuestionOutline);
export const NewTab = createIcon(mdiTabPlus);