Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions apps/client/src/translations/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,32 @@
"continue_anyway": "Continue Anyway",
"dont_show_again": "Don't show this warning again"
},
"toolbar_customization": {
"title": "Toolbar items",
"description": "Customize the classic editor toolbar. Drag items to reorder, click available items to add them, or drag to the trash zone to remove.",
"current_toolbar": "Current toolbar",
"available_items": "Available items — click to add",
"add_to_group": "Click an item to add it to the group",
"all_used": "All items are already in the toolbar",
"click_to_add": "Click to add to toolbar",
"add_separator": "Add separator",
"separator_hint": "Adds a visual divider between toolbar items",
"add_group": "Add group",
"new_group_label": "Group",
"group_name": "Group name",
"group_empty": "No items — click an available item to add",
"expand_group": "Edit group items",
"collapse_group": "Collapse group",
"remove_item": "Remove",
"drop_to_remove": "Drop here to remove",
"empty": "No items — click an available item to add",
"reset_default": "Reset to default",
"unsaved_changes": "Unsaved changes — click Save & Apply to reload the editor",
"no_changes": "No unsaved changes",
"discard": "Discard",
"save_apply": "Save & Apply",
"saving": "Saving…"
},
"editorfeatures": {
"title": "Features",
"emoji_completion_enabled": "Enable Emoji auto-completion",
Expand Down
2 changes: 2 additions & 0 deletions apps/client/src/widgets/type_widgets/options/text_notes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ import { getHtml } from "../../react/RawHtml";
import AutoReadOnlySize from "./components/AutoReadOnlySize";
import CheckboxList from "./components/CheckboxList";
import OptionsSection from "./components/OptionsSection";
import ToolbarCustomization from "./toolbar_customization";

const isNewLayout = isExperimentalFeatureEnabled("new-layout");

export default function TextNoteSettings() {
return (
<>
<FormattingToolbar />
<ToolbarCustomization />
<EditorFeatures />
<HeadingStyle />
<CodeBlockStyle />
Expand Down
307 changes: 307 additions & 0 deletions apps/client/src/widgets/type_widgets/options/toolbar_customization.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
.toolbar-editor {
display: flex;
flex-direction: column;
gap: 10px;
}

/* ── Two-column layout ────────────────────────────────────────────────── */

.toolbar-columns {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
align-items: start;
}

@media (max-width: 700px) {
.toolbar-columns {
grid-template-columns: 1fr;
}
}

/* ── Panel (shared by both columns) ──────────────────────────────────── */

.toolbar-panel {
display: flex;
flex-direction: column;
gap: 6px;
border: 1px solid var(--main-border-color);
border-radius: var(--bs-border-radius);
overflow: hidden;
}

.toolbar-panel-header {
padding: 5px 10px;
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
background: var(--accented-background-color);
border-bottom: 1px solid var(--main-border-color);
color: var(--muted-text-color);
}

/* ── Vertical item list ───────────────────────────────────────────────── */

.toolbar-list {
display: flex;
flex-direction: column;
min-height: 60px;
}

.toolbar-list.available-list {
max-height: 360px;
overflow-y: auto;
}

/* ── A single row ─────────────────────────────────────────────────────── */

.toolbar-row-wrapper {
display: flex;
flex-direction: column;
}

.toolbar-row-wrapper.drop-above > .toolbar-row:first-child {
border-top: 2px solid var(--main-text-color);
}

.toolbar-row {
display: flex;
align-items: center;
gap: 6px;
padding: 5px 8px;
font-size: 0.85rem;
border-bottom: 1px solid var(--main-border-color);
user-select: none;
min-height: 32px;
cursor: default;
}

.toolbar-row:last-child {
border-bottom: none;
}

.toolbar-row[draggable="true"] {
cursor: grab;
}

.toolbar-row[draggable="true"]:active {
cursor: grabbing;
}

/* Group header row */
.toolbar-row.group-header {
background: var(--accented-background-color);
font-weight: 600;
transition: background 0.12s, outline 0.12s;
}

/* Drop-into-group highlight: shown when dragging an item over a group header */
.toolbar-row.group-header.drop-into-group {
outline: 2px solid var(--main-text-color);
outline-offset: -2px;
background: var(--hover-item-background-color);
}

/* Separator row */
.toolbar-row.separator {
color: var(--muted-text-color);
font-size: 0.78rem;
font-style: italic;
justify-content: center;
padding-block: 3px;
}

/* Sub-item row (inside an expanded group) */
.toolbar-row.sub {
padding-left: 28px;
background: var(--more-accented-background-color);
font-size: 0.82rem;
}

.toolbar-row.sub.drop-above {
border-top: 2px solid var(--main-text-color);
}

/* Available-item row */
.toolbar-row.available {
cursor: pointer;
}

.toolbar-row.available:hover {
background: var(--hover-item-background-color);
}

/* ── Row internals ────────────────────────────────────────────────────── */

.drag-handle {
color: var(--muted-text-color);
font-size: 1rem;
flex-shrink: 0;
cursor: grab;
}

.row-label {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
}

.row-add-icon {
color: var(--muted-text-color);
font-size: 1rem;
flex-shrink: 0;
}

.toolbar-row.available:hover .row-add-icon {
color: var(--main-text-color);
}

.row-btn {
display: inline-flex;
align-items: center;
justify-content: center;
border: none;
background: transparent;
padding: 2px;
cursor: pointer;
color: var(--muted-text-color);
line-height: 1;
font-size: 1rem;
border-radius: 2px;
flex-shrink: 0;
}

.row-btn:hover {
color: var(--main-text-color);
background: var(--hover-item-background-color);
}

.row-btn.remove:hover {
color: var(--danger-text-color, #dc3545);
}

/* ── Expanded group panel ─────────────────────────────────────────────── */

.group-expanded {
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--main-border-color);
}

.group-name-row {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px 6px 28px;
background: var(--more-accented-background-color);
border-bottom: 1px solid var(--main-border-color);
}

.group-name-label {
font-size: 0.78rem;
font-weight: 500;
color: var(--muted-text-color);
white-space: nowrap;
flex-shrink: 0;
}

.group-name-input {
flex: 1;
max-width: 180px;
}

/* ── Trash zone ───────────────────────────────────────────────────────── */

.toolbar-trash {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 6px 10px;
border-top: 1px dashed var(--main-border-color);
color: var(--muted-text-color);
font-size: 0.82rem;
transition: background 0.12s, color 0.12s;
}

.toolbar-trash.active {
background: color-mix(in srgb, var(--danger-text-color, #dc3545) 12%, transparent);
color: var(--danger-text-color, #dc3545);
border-color: var(--danger-text-color, #dc3545);
}
Comment on lines +230 to +235
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The color-mix() CSS function is a modern feature with support limited to recent browser versions (e.g., Chrome 111+, Firefox 113+). Depending on the target Electron/Chromium version for this project, this might lead to inconsistent styling. For broader compatibility, you might consider using rgba() or hex colors with alpha transparency. For instance, background: color-mix(in srgb, var(--danger-text-color, #dc3545) 12%, transparent); could be replaced with background: #dc35451f; (which corresponds to ~12% opacity).


/* ── Action bar ───────────────────────────────────────────────────────── */

.toolbar-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 5px;
padding: 6px 8px;
border-top: 1px solid var(--main-border-color);
background: var(--accented-background-color);
}

/* ── Save / Discard bar ───────────────────────────────────────────────── */

.toolbar-save-bar {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 10px;
border: 1px solid var(--main-border-color);
border-radius: var(--bs-border-radius);
background: var(--accented-background-color);
font-size: 0.82rem;
margin-bottom: 8px;
}

.toolbar-save-bar.has-changes {
border-color: var(--bs-warning, #ffc107);
background: color-mix(in srgb, var(--bs-warning, #ffc107) 8%, var(--accented-background-color));
}

.toolbar-save-status {
flex: 1;
color: var(--muted-text-color);
}

.toolbar-save-bar.has-changes .toolbar-save-status {
color: var(--main-text-color);
font-weight: 500;
}

/* ── Item icons ───────────────────────────────────────────────────────── */

.toolbar-item-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--muted-text-color);
}

.toolbar-item-icon svg {
width: 16px;
height: 16px;
fill: currentColor;
pointer-events: none;
}

/* ── Misc ─────────────────────────────────────────────────────────────── */

.toolbar-empty-hint {
font-size: 0.8rem;
color: var(--muted-text-color);
padding: 8px 10px;
font-style: italic;
}

.toolbar-empty-hint.indented {
padding-left: 28px;
}
Loading