Skip to content

Commit bd24023

Browse files
authored
New layout: Remove floating buttons (#8059)
2 parents bc8f17e + a9b3479 commit bd24023

File tree

13 files changed

+351
-124
lines changed

13 files changed

+351
-124
lines changed

apps/client/src/stylesheets/style.css

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,9 +521,7 @@ body.mobile .dropdown .dropdown-submenu > span {
521521
.cm-editor {
522522
height: 100%;
523523
outline: none !important;
524-
border-radius: 6px;
525524
overflow: hidden;
526-
margin: 4px;
527525
font-size: var(--monospace-font-size);
528526
}
529527

@@ -629,6 +627,11 @@ pre:not(.hljs) {
629627
padding: var(--padding-size);
630628
}
631629

630+
pre:has(> .cm-editor) {
631+
padding: 0;
632+
margin: 0;
633+
}
634+
632635
pre > button.copy-button {
633636
position: absolute;
634637
top: var(--copy-button-margin-size);
@@ -2471,6 +2474,11 @@ footer.webview-footer button {
24712474
inset-inline-start: 10px;
24722475
}
24732476

2477+
.content-floating-buttons.top-right {
2478+
top: 10px;
2479+
inset-inline-end: 10px;
2480+
}
2481+
24742482
.content-floating-buttons.bottom-left {
24752483
bottom: 10px;
24762484
inset-inline-start: 10px;

apps/client/src/stylesheets/theme-next/base.css

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,30 @@ body.desktop .dropdown-submenu .dropdown-menu {
166166
--menu-item-end-padding: 22px;
167167
--menu-item-vertical-padding: 2px;
168168

169+
/* Note: the right padding should also accommodate the submenu arrow. */
170+
border-radius: 6px;
171+
cursor: default !important;
172+
}
173+
174+
.dropdown-item:not(.dropdown-submenu),
175+
body.desktop .dropdown-item.dropdown-submenu .dropdown-toggle,
176+
.excalidraw .context-menu .context-menu-item {
169177
padding-top: var(--menu-item-vertical-padding) !important;
170178
padding-bottom: var(--menu-item-vertical-padding) !important;
171179
padding-inline-start: var(--menu-item-start-padding) !important;
172180
padding-inline-end: var(--menu-item-end-padding) !important;
181+
}
173182

174-
/* Note: the right padding should also accommodate the submenu arrow. */
175-
border-radius: 6px;
176-
cursor: default !important;
183+
.dropdown-item.dropdown-submenu {
184+
padding: 0 !important;
185+
186+
.dropdown-toggle {
187+
flex-grow: 1;
188+
}
177189
}
178190

179-
body.desktop .dropdown-menu:has(> .dropdown-submenu.dropstart) > .dropdown-item {
191+
body.desktop .dropdown-menu:has(> .dropdown-submenu.dropstart) > .dropdown-item:not(.dropdown-submenu),
192+
body.desktop .dropdown-menu:has(> .dropdown-submenu.dropstart) > .dropdown-item.dropdown-submenu .dropdown-toggle {
180193
padding-inline-end: var(--menu-item-start-padding) !important;
181194
padding-inline-start: var(--menu-item-end-padding) !important;
182195
}

apps/client/src/translations/en/translation.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@
696696
"convert_into_attachment_successful": "Note '{{title}}' has been converted to attachment.",
697697
"convert_into_attachment_prompt": "Are you sure you want to convert note '{{title}}' into an attachment of the parent note?",
698698
"print_pdf": "Export as PDF...",
699+
"export_as_image": "Export as image",
700+
"export_as_image_png": "PNG (raster)",
701+
"export_as_image_svg": "SVG (vector)",
699702
"note_map": "Note map"
700703
},
701704
"onclick_button": {

apps/client/src/widgets/FloatingButtonsDefinitions.tsx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export const POPUP_HIDDEN_FLOATING_BUTTONS: FloatingButtonsList = [
8181
const isNewLayout = isExperimentalFeatureEnabled("new-layout");
8282

8383
function RefreshBackendLogButton({ note, parentComponent, noteContext, isDefaultViewMode }: FloatingButtonContext) {
84-
const isEnabled = (note.noteId === "_backendLog" || note.type === "render") && isDefaultViewMode;
84+
const isEnabled = !isNewLayout && (note.noteId === "_backendLog" || note.type === "render") && isDefaultViewMode;
8585
return isEnabled && <FloatingButton
8686
text={t("backend_log.refresh")}
8787
icon="bx bx-refresh"
@@ -90,7 +90,7 @@ function RefreshBackendLogButton({ note, parentComponent, noteContext, isDefault
9090
}
9191

9292
function SwitchSplitOrientationButton({ note, isReadOnly, isDefaultViewMode }: FloatingButtonContext) {
93-
const isEnabled = note.type === "mermaid" && note.isContentAvailable() && !isReadOnly && isDefaultViewMode;
93+
const isEnabled = !isNewLayout && note.type === "mermaid" && note.isContentAvailable() && !isReadOnly && isDefaultViewMode;
9494
const [ splitEditorOrientation, setSplitEditorOrientation ] = useTriliumOption("splitEditorOrientation");
9595
const upcomingOrientation = splitEditorOrientation === "horizontal" ? "vertical" : "horizontal";
9696

@@ -103,7 +103,7 @@ function SwitchSplitOrientationButton({ note, isReadOnly, isDefaultViewMode }: F
103103

104104
function ToggleReadOnlyButton({ note, viewType, isDefaultViewMode }: FloatingButtonContext) {
105105
const [ isReadOnly, setReadOnly ] = useNoteLabelBoolean(note, "readOnly");
106-
const isEnabled = ([ "mermaid", "mindMap", "canvas" ].includes(note.type) || viewType === "geoMap")
106+
const isEnabled = !isNewLayout && ([ "mermaid", "mindMap", "canvas" ].includes(note.type) || viewType === "geoMap")
107107
&& note.isContentAvailable() && isDefaultViewMode;
108108

109109
return isEnabled && <FloatingButton
@@ -173,7 +173,7 @@ function ShowHighlightsListWidgetButton({ note, noteContext, isDefaultViewMode }
173173
}
174174

175175
function RunActiveNoteButton({ note }: FloatingButtonContext) {
176-
const isEnabled = note.mime.startsWith("application/javascript") || note.mime === "text/x-sqlite;schema=trilium";
176+
const isEnabled = !isNewLayout && (note.mime.startsWith("application/javascript") || note.mime === "text/x-sqlite;schema=trilium");
177177
return isEnabled && <FloatingButton
178178
icon="bx bx-play"
179179
text={t("code_buttons.execute_button_title")}
@@ -182,7 +182,7 @@ function RunActiveNoteButton({ note }: FloatingButtonContext) {
182182
}
183183

184184
function OpenTriliumApiDocsButton({ note }: FloatingButtonContext) {
185-
const isEnabled = note.mime.startsWith("application/javascript;env=");
185+
const isEnabled = !isNewLayout && note.mime.startsWith("application/javascript;env=");
186186
return isEnabled && <FloatingButton
187187
icon="bx bx-help-circle"
188188
text={t("code_buttons.trilium_api_docs_button_title")}
@@ -191,25 +191,29 @@ function OpenTriliumApiDocsButton({ note }: FloatingButtonContext) {
191191
}
192192

193193
function SaveToNoteButton({ note }: FloatingButtonContext) {
194-
const isEnabled = note.mime === "text/x-sqlite;schema=trilium" && note.isHiddenCompletely();
194+
const isEnabled = !isNewLayout && note.mime === "text/x-sqlite;schema=trilium" && note.isHiddenCompletely();
195195
return isEnabled && <FloatingButton
196196
icon="bx bx-save"
197197
text={t("code_buttons.save_to_note_button_title")}
198-
onClick={async (e) => {
199-
e.preventDefault();
200-
const { notePath } = await server.post<SaveSqlConsoleResponse>("special-notes/save-sql-console", { sqlConsoleNoteId: note.noteId });
201-
if (notePath) {
202-
toast.showMessage(t("code_buttons.sql_console_saved_message", { "note_path": await tree.getNotePathTitle(notePath) }));
203-
// TODO: This hangs the navigation, for some reason.
204-
//await ws.waitForMaxKnownEntityChangeId();
205-
await appContext.tabManager.getActiveContext()?.setNote(notePath);
206-
}
207-
}}
198+
onClick={buildSaveSqlToNoteHandler(note)}
208199
/>;
209200
}
210201

202+
export function buildSaveSqlToNoteHandler(note: FNote) {
203+
return async (e: MouseEvent) => {
204+
e.preventDefault();
205+
const { notePath } = await server.post<SaveSqlConsoleResponse>("special-notes/save-sql-console", { sqlConsoleNoteId: note.noteId });
206+
if (notePath) {
207+
toast.showMessage(t("code_buttons.sql_console_saved_message", { "note_path": await tree.getNotePathTitle(notePath) }));
208+
// TODO: This hangs the navigation, for some reason.
209+
//await ws.waitForMaxKnownEntityChangeId();
210+
await appContext.tabManager.getActiveContext()?.setNote(notePath);
211+
}
212+
};
213+
}
214+
211215
function RelationMapButtons({ note, isDefaultViewMode, triggerEvent }: FloatingButtonContext) {
212-
const isEnabled = (note.type === "relationMap" && isDefaultViewMode);
216+
const isEnabled = (!isNewLayout && note.type === "relationMap" && isDefaultViewMode);
213217
return isEnabled && (
214218
<>
215219
<FloatingButton
@@ -242,7 +246,7 @@ function RelationMapButtons({ note, isDefaultViewMode, triggerEvent }: FloatingB
242246
}
243247

244248
function GeoMapButtons({ triggerEvent, viewType, isReadOnly }: FloatingButtonContext) {
245-
const isEnabled = viewType === "geoMap" && !isReadOnly;
249+
const isEnabled = !isNewLayout && viewType === "geoMap" && !isReadOnly;
246250
return isEnabled && (
247251
<FloatingButton
248252
icon="bx bx-plus-circle"
@@ -283,7 +287,7 @@ function CopyImageReferenceButton({ note, isDefaultViewMode }: FloatingButtonCon
283287
}
284288

285289
function ExportImageButtons({ note, triggerEvent, isDefaultViewMode }: FloatingButtonContext) {
286-
const isEnabled = ["mermaid", "mindMap"].includes(note?.type ?? "")
290+
const isEnabled = !isNewLayout && ["mermaid", "mindMap"].includes(note?.type ?? "")
287291
&& note?.isContentAvailable() && isDefaultViewMode;
288292
return isEnabled && (
289293
<>
@@ -304,7 +308,7 @@ function ExportImageButtons({ note, triggerEvent, isDefaultViewMode }: FloatingB
304308

305309
function InAppHelpButton({ note }: FloatingButtonContext) {
306310
const helpUrl = getHelpUrlForNote(note);
307-
const isEnabled = !!helpUrl && (!isNewLayout || (note?.type !== "book"));
311+
const isEnabled = !!helpUrl && !isNewLayout;
308312

309313
return isEnabled && (
310314
<FloatingButton

apps/client/src/widgets/buttons/global_menu.tsx

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
3838
text={<>
3939
{isVerticalLayout && <VerticalLayoutIcon />}
4040
{isUpdateAvailable && <div class="global-menu-button-update-available">
41-
<span className="bx bxs-down-arrow-alt global-menu-button-update-available-button" title={t("update_available.update_available")}></span>
41+
<span className="bx bxs-down-arrow-alt global-menu-button-update-available-button" title={t("update_available.update_available")} />
4242
</div>}
4343
</>}
4444
noDropdownListStyle
@@ -57,7 +57,7 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
5757

5858
<SwitchToOptions />
5959
<MenuItem command="showLaunchBarSubtree" icon={`bx ${isMobile() ? "bx-mobile" : "bx-sidebar"}`} text={t("global_menu.configure_launchbar")} />
60-
<AdvancedMenu />
60+
<AdvancedMenu dropStart={!isVerticalLayout} />
6161
<MenuItem command="showOptions" icon="bx bx-cog" text={t("global_menu.options")} />
6262
<FormDropdownDivider />
6363

@@ -68,19 +68,19 @@ export default function GlobalMenu({ isHorizontalLayout }: { isHorizontalLayout:
6868
{isUpdateAvailable && <>
6969
<FormListHeader text={t("global_menu.new-version-available")} />
7070
<MenuItem command={() => window.open("https://github.com/TriliumNext/Trilium/releases/latest")}
71-
icon="bx bx-download"
72-
text={t("global_menu.download-update", {latestVersion})} />
71+
icon="bx bx-download"
72+
text={t("global_menu.download-update", {latestVersion})} />
7373
</>}
7474

7575
{!isElectron() && <BrowserOnlyOptions />}
76-
{glob.isDev && <DevelopmentOptions />}
76+
{glob.isDev && <DevelopmentOptions dropStart={!isVerticalLayout} />}
7777
</Dropdown>
7878
);
7979
}
8080

81-
function AdvancedMenu() {
81+
function AdvancedMenu({ dropStart }: { dropStart: boolean }) {
8282
return (
83-
<FormDropdownSubmenu icon="bx bx-chip" title={t("global_menu.advanced")}>
83+
<FormDropdownSubmenu icon="bx bx-chip" title={t("global_menu.advanced")} dropStart={dropStart}>
8484
<MenuItem command="showHiddenSubtree" icon="bx bx-hide" text={t("global_menu.show_hidden_subtree")} />
8585
<MenuItem command="showSearchHistory" icon="bx bx-search-alt" text={t("global_menu.open_search_history")} />
8686
<FormDropdownDivider />
@@ -103,13 +103,11 @@ function BrowserOnlyOptions() {
103103
</>;
104104
}
105105

106-
function DevelopmentOptions() {
107-
const [ layoutOrientation ] = useTriliumOption("layoutOrientation");
108-
106+
function DevelopmentOptions({ dropStart }: { dropStart: boolean }) {
109107
return <>
110108
<FormDropdownDivider />
111109
<FormListItem disabled>Development Options</FormListItem>
112-
<FormDropdownSubmenu icon="bx bx-test-tube" title="Experimental features" dropStart={layoutOrientation === "horizontal"}>
110+
<FormDropdownSubmenu icon="bx bx-test-tube" title="Experimental features" dropStart={dropStart}>
113111
{experimentalFeatures.map((feature) => (
114112
<ExperimentalFeatureToggle key={feature.id} experimentalFeature={feature as ExperimentalFeature} />
115113
))}
@@ -136,10 +134,10 @@ function SwitchToOptions() {
136134
if (isElectron()) {
137135
return;
138136
} else if (!isMobile()) {
139-
return <MenuItem command="switchToMobileVersion" icon="bx bx-mobile" text={t("global_menu.switch_to_mobile_version")} />
140-
} else {
141-
return <MenuItem command="switchToDesktopVersion" icon="bx bx-desktop" text={t("global_menu.switch_to_desktop_version")} />
142-
}
137+
return <MenuItem command="switchToMobileVersion" icon="bx bx-mobile" text={t("global_menu.switch_to_mobile_version")} />;
138+
}
139+
return <MenuItem command="switchToDesktopVersion" icon="bx bx-desktop" text={t("global_menu.switch_to_desktop_version")} />;
140+
143141
}
144142

145143
function MenuItem({ icon, text, title, command, disabled, active }: MenuItemProps<KeyboardActionNames | CommandNames | (() => void)>) {
@@ -150,15 +148,15 @@ function MenuItem({ icon, text, title, command, disabled, active }: MenuItemProp
150148
onClick={typeof command === "function" ? command : undefined}
151149
disabled={disabled}
152150
active={active}
153-
>{text}</FormListItem>
151+
>{text}</FormListItem>;
154152
}
155153

156154
function KeyboardActionMenuItem({ text, command, ...props }: MenuItemProps<KeyboardActionNames>) {
157155
return <MenuItem
158156
{...props}
159157
command={command}
160158
text={<>{text} <KeyboardShortcut actionName={command as KeyboardActionNames} /></>}
161-
/>
159+
/>;
162160
}
163161

164162
function VerticalLayoutIcon() {
@@ -181,7 +179,7 @@ function VerticalLayoutIcon() {
181179
<path className="st8" d="m66.3 52.2c15.3 12.8 23.3 33.6 26.1 48.9l-50.6-22 48.8 24.9c-12.2 6-29.6 11.8-46.5 10-19.8-16.4-40.2-46.4-42.6-61.5 12.4-6.5 41.5-5.8 64.8-0.3z"/>
182180
</g>
183181
</svg>
184-
)
182+
);
185183
}
186184

187185
function ZoomControls({ parentComponent }: { parentComponent?: Component | null }) {
@@ -205,7 +203,7 @@ function ZoomControls({ parentComponent }: { parentComponent?: Component | null
205203
}}
206204
className={`dropdown-item-button ${icon}`}
207205
>{children}</a>
208-
)
206+
);
209207
}
210208

211209
return isElectron() ? (
@@ -246,7 +244,7 @@ function ToggleWindowOnTop() {
246244
setIsAlwaysOnTop(newState);
247245
}}
248246
/>
249-
)
247+
);
250248
}
251249

252250
function useTriliumUpdateStatus() {
@@ -257,7 +255,7 @@ function useTriliumUpdateStatus() {
257255
async function updateVersionStatus() {
258256
const RELEASES_API_URL = "https://api.github.com/repos/TriliumNext/Trilium/releases/latest";
259257

260-
let latestVersion: string | undefined = undefined;
258+
let latestVersion: string | undefined;
261259
try {
262260
const resp = await fetch(RELEASES_API_URL);
263261
const data = await resp.json();

apps/client/src/widgets/react/FormList.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -217,22 +217,19 @@ export function FormDropdownSubmenu({ icon, title, children, dropStart, onDropdo
217217
const [ openOnMobile, setOpenOnMobile ] = useState(false);
218218

219219
return (
220-
<li
221-
className={clsx("dropdown-item dropdown-submenu", { "submenu-open": openOnMobile, "dropstart": dropStart })}
222-
onClick={(e) => {
223-
e.stopPropagation();
224-
225-
if (!isMobile() && onDropdownToggleClicked) {
226-
onDropdownToggleClicked();
227-
}
228-
}}
229-
>
230-
<span className="dropdown-toggle" onClick={(e) => {
231-
if (isMobile()) {
220+
<li className={clsx("dropdown-item dropdown-submenu", { "submenu-open": openOnMobile, "dropstart": dropStart })}>
221+
<span
222+
className="dropdown-toggle"
223+
onClick={(e) => {
232224
e.stopPropagation();
233-
setOpenOnMobile(!openOnMobile);
234-
}
235-
}}>
225+
226+
if (isMobile()) {
227+
setOpenOnMobile(!openOnMobile);
228+
} else if (onDropdownToggleClicked) {
229+
onDropdownToggleClicked();
230+
}
231+
}}
232+
>
236233
<Icon icon={icon} />{" "}
237234
{title}
238235
</span>

0 commit comments

Comments
 (0)