diff --git a/backend/api/system.ts b/backend/api/system.ts index 51370e7e8..a54a5f69f 100644 --- a/backend/api/system.ts +++ b/backend/api/system.ts @@ -105,6 +105,9 @@ async function routes(app: FastifyInstance) { dbHost: { type: 'string' }, + dbVersion: { + type: 'string' + }, groupsTotal: { type: 'number' }, @@ -160,7 +163,7 @@ async function routes(app: FastifyInstance) { type: 'string' }, tagsTotal: { - type: 'string' + type: 'number' }, upgradeCapable: { type: 'boolean' diff --git a/blocks/block-index/component.js b/blocks/block-index/component.js index f1913def2..1d3e5aa88 100644 --- a/blocks/block-index/component.js +++ b/blocks/block-index/component.js @@ -235,6 +235,18 @@ export class BlockIndexElement extends LitElement { font-weight: normal; pointer-events: none; } + /* + On a dark row the writing takes the app's lightened brand shade, the same one the interface + gives a heading over a dark surface: primary is a mid-tone picked to read on white and is + too dim against #161b22. --color-primary-light is a mix of --q-primary, so a re-themed + site's own hue comes with it. + + On .text rather than on the anchor, so it is the title alone that lightens: the icon and the + arrow are drawn with currentColor precisely so they keep the link's normal primary. + */ + :host([dark]) .text { + color: var(--color-primary-light); + } /* The page's own icon. Sized in em so it keeps its place beside writing at whatever size the diff --git a/blocks/block-tabs/component.js b/blocks/block-tabs/component.js index 5a184495b..37b387d72 100644 --- a/blocks/block-tabs/component.js +++ b/blocks/block-tabs/component.js @@ -114,7 +114,7 @@ Content of the second tab. } .tab:hover:not(.is-active) { background-color: rgb(255 255 255 / 0.5); - color: var(--tabs-active-fg); + color: var(--tabs-active-label); } :host([dark]) .tab:hover:not(.is-active) { background-color: rgb(255 255 255 / 0.05); @@ -130,7 +130,7 @@ Content of the second tab. border-bottom-color: var(--tabs-panel-bg); background-color: var(--tabs-panel-bg); background-image: none; - color: var(--tabs-active-fg); + color: var(--tabs-active-label); } .tab svg { @@ -170,12 +170,21 @@ Content of the second tab. --tabs-strip-bg: linear-gradient(to bottom, #fdfdfd, #eeeeee); --tabs-inactive-fg: #424242; --tabs-active-fg: var(--q-primary, #1976d2); + /* + The label of the tab being pointed at or opened. The active foreground, except on dark, + where writing in a mid-tone picked to read on white is too dim -- the strip and the panel + both sit near #1b212a. The edge that marks the open tab and the focus ring keep the plain + brand colour: they are shapes rather than writing, and read at that weight. + */ + --tabs-active-label: var(--tabs-active-fg); --tabs-panel-bg: #fff; } :host([dark]) { --tabs-border: rgba(255, 255, 255, 0.15); --tabs-strip-bg: linear-gradient(to bottom, #1b212a, #12161d); --tabs-inactive-fg: rgba(255, 255, 255, 0.7); + /* -> A mix of --q-primary, so a re-themed site's own hue comes with it. See block-index. */ + --tabs-active-label: var(--color-primary-light); --tabs-panel-bg: #1e232a; } ` diff --git a/frontend/src/components/EditorMarkdown.vue b/frontend/src/components/EditorMarkdown.vue index 4bff86bf6..67d79de9e 100644 --- a/frontend/src/components/EditorMarkdown.vue +++ b/frontend/src/components/EditorMarkdown.vue @@ -440,21 +440,27 @@ const HEADER_ICONS = [ ] /* - How the preview follows the caret: the line being edited goes to the TOP of the pane. - - `start` rather than `nearest`, which was tried and is wrong here -- `nearest` leaves a line alone as - long as it is visible anywhere, so a line sitting on the last row of the pane stays there, with what is - being written pinned to the bottom edge and nothing after it in view. - - Asking for the top on every caret move costs nothing when the caret stays put: the element is already - there, so the browser computes the same offset and there is no movement. What used to make this thrash - was the pane losing its scroll position to the re-render -- see `processContent` -- and animating up - from the top of the document each time, not the alignment asked for here. - - `inline: 'nearest'` only so that a wide block -- a table, a diagram -- is never scrolled sideways as a - side effect of following the caret down the page. + How the preview follows the caret: the line being edited is put a SHORT WAY down the pane. + + Not at its top, which is what this replaces. The top is exact, and that is the problem with it -- it + scrolls away everything written just above the caret, which is the paragraph the next one is being + written against, so the author is left editing at the edge of a pane with no context on one side of + it. Expressed as a fraction of the pane rather than a fixed inset so that a preview half the height + gives up half as much of itself to the lines already written. + + `nearest` is not the answer either, at any offset: it leaves a line alone as long as it is visible + anywhere, so a line sitting on the last row of the pane stays there, with what is being written pinned + to the bottom edge and nothing after it in view. The position is computed and applied on every caret + move, and costs nothing when the caret stays put -- the arithmetic lands on the offset the pane is + already scrolled to and nothing moves. What used to make this thrash was the pane losing its scroll + position to the re-render -- see `processContent` -- and animating up from the top of the document each + time, not the alignment asked for here. + + Scrolling the container rather than asking an element to bring itself into view also means a wide block + -- a table, a diagram -- is never scrolled sideways as a side effect of following the caret down the + page. */ -const SYNC_SCROLL = { behavior: 'smooth', block: 'start', inline: 'nearest' } +const PREVIEW_CONTEXT_ABOVE = 0.2 /** * Whether the window is wide enough to open the preview beside the source. @@ -1162,6 +1168,24 @@ function previewAnchorFor(container, line) { return best ?? panel } +/** + * Scroll the preview so that `el` sits `PREVIEW_CONTEXT_ABOVE` of the way down the pane. + * + * Measured through `getBoundingClientRect` rather than `offsetTop`, because what is wanted is the + * distance to the SCROLL container and `offsetTop` answers to the nearest positioned ancestor -- which + * inside rendered page content is whatever a block happened to put around it. + * + * A negative result is clamped by `scrollTo`, so an anchor near the top of the document puts the + * document's own top in view rather than leaving a gap above it. + */ +function scrollPreviewTo(container, el) { + const offset = el.getBoundingClientRect().top - container.getBoundingClientRect().top + container.scrollTo({ + top: container.scrollTop + offset - container.clientHeight * PREVIEW_CONTEXT_ABOVE, + behavior: 'smooth' + }) +} + function processContent(newContent) { /* A render that throws must not become a render that is empty. @@ -1569,7 +1593,10 @@ onMounted(async () => { container.scrollTo({ top: 0, behavior: 'smooth' }) return } - previewAnchorFor(container, currentLine)?.scrollIntoView(SYNC_SCROLL) + const anchor = previewAnchorFor(container, currentLine) + if (anchor) { + scrollPreviewTo(container, anchor) + } }, 500) ) diff --git a/frontend/src/components/PagePropertiesDialog.vue b/frontend/src/components/PagePropertiesDialog.vue index 739747d87..a47a16859 100644 --- a/frontend/src/components/PagePropertiesDialog.vue +++ b/frontend/src/components/PagePropertiesDialog.vue @@ -252,7 +252,7 @@
{{ t('editor.props.social') }}
-
+
-
+
-
{{ t('admin.api.title') }}
+
{{ t('admin.api.title') }}
{{ t('admin.api.subtitle') }}
diff --git a/frontend/src/pages/AdminApprovals.vue b/frontend/src/pages/AdminApprovals.vue index d8f084bfb..254b47e17 100644 --- a/frontend/src/pages/AdminApprovals.vue +++ b/frontend/src/pages/AdminApprovals.vue @@ -5,7 +5,7 @@
-
{{ t('admin.approval.title') }}
+
{{ t('admin.approval.title') }}
{{ t('admin.approval.subtitle') }}
diff --git a/frontend/src/pages/AdminAuth.vue b/frontend/src/pages/AdminAuth.vue index 4d74d97f6..a6355f4ad 100644 --- a/frontend/src/pages/AdminAuth.vue +++ b/frontend/src/pages/AdminAuth.vue @@ -5,7 +5,7 @@
-
{{ t('admin.auth.title') }}
+
{{ t('admin.auth.title') }}
{{ t('admin.auth.subtitle') }}
diff --git a/frontend/src/pages/AdminBlocks.vue b/frontend/src/pages/AdminBlocks.vue index 1e45b6c48..67c9f2097 100644 --- a/frontend/src/pages/AdminBlocks.vue +++ b/frontend/src/pages/AdminBlocks.vue @@ -5,7 +5,7 @@
-
{{ t('admin.blocks.title') }}
+
{{ t('admin.blocks.title') }}
{{ t('admin.blocks.subtitle') }}
diff --git a/frontend/src/pages/AdminDashboard.vue b/frontend/src/pages/AdminDashboard.vue index 96f7a5ab4..644dfa92e 100644 --- a/frontend/src/pages/AdminDashboard.vue +++ b/frontend/src/pages/AdminDashboard.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-apps-tab-animated.svg" />
-
{{ t('admin.dashboard.title') }}
+
{{ t('admin.dashboard.title') }}
{{ t('admin.dashboard.subtitle') }}
diff --git a/frontend/src/pages/AdminEditors.vue b/frontend/src/pages/AdminEditors.vue index f777ba847..8793c6b16 100644 --- a/frontend/src/pages/AdminEditors.vue +++ b/frontend/src/pages/AdminEditors.vue @@ -5,7 +5,7 @@
-
{{ t('admin.editors.title') }}
+
{{ t('admin.editors.title') }}
{{ t('admin.editors.subtitle') }}
diff --git a/frontend/src/pages/AdminExtensions.vue b/frontend/src/pages/AdminExtensions.vue index 726237a17..333b16e65 100644 --- a/frontend/src/pages/AdminExtensions.vue +++ b/frontend/src/pages/AdminExtensions.vue @@ -5,7 +5,7 @@
-
+
{{ t('admin.extensions.title') }}
diff --git a/frontend/src/pages/AdminFlags.vue b/frontend/src/pages/AdminFlags.vue index ea998947d..f114d491c 100644 --- a/frontend/src/pages/AdminFlags.vue +++ b/frontend/src/pages/AdminFlags.vue @@ -5,7 +5,7 @@
-
{{ t('admin.flags.title') }}
+
{{ t('admin.flags.title') }}
{{ t('admin.flags.subtitle') }}
diff --git a/frontend/src/pages/AdminGeneral.vue b/frontend/src/pages/AdminGeneral.vue index 8f8a23781..a606a439e 100644 --- a/frontend/src/pages/AdminGeneral.vue +++ b/frontend/src/pages/AdminGeneral.vue @@ -5,7 +5,7 @@
-
{{ t('admin.general.title') }}
+
{{ t('admin.general.title') }}
{{ t('admin.general.subtitle') }}
@@ -185,19 +185,21 @@ - - - - {{ t(`admin.general.allowComments`) }} - {{ t(`admin.general.allowCommentsHint`) }} - - - - - - + @@ -211,23 +213,25 @@ - - - - {{ t(`admin.general.allowRatings`) }} - {{ t(`admin.general.allowRatingsHint`) }} - - - - - - + @@ -290,6 +294,24 @@ + + + + + {{ t('admin.general.discovery') }} + + + + {{ t(`admin.general.discoverable`) }} + {{ t(`admin.general.discoverableHint`) }} + + + + + +
@@ -464,24 +486,6 @@ - - - - {{ t('admin.general.discovery') }} - - - - {{ t(`admin.general.discoverable`) }} - {{ t(`admin.general.discoverableHint`) }} - - - - - - - @@ -585,6 +589,7 @@ import { notify } from '@/composables/notify' import { loading } from '@/composables/loading' import { useAdminStore } from '@/stores/admin' +import { useFlagsStore } from '@/stores/flags' import { useSiteStore } from '@/stores/site' import UtilCodeEditor from '@/components/UtilCodeEditor.vue' @@ -601,6 +606,7 @@ import { toMerged } from 'es-toolkit/object' // STORES const adminStore = useAdminStore() +const flagsStore = useFlagsStore() const siteStore = useSiteStore() // I18N diff --git a/frontend/src/pages/AdminGroups.vue b/frontend/src/pages/AdminGroups.vue index e379d938b..0d8ff020b 100644 --- a/frontend/src/pages/AdminGroups.vue +++ b/frontend/src/pages/AdminGroups.vue @@ -5,7 +5,7 @@
-
{{ t('admin.groups.title') }}
+
{{ t('admin.groups.title') }}
{{ t('admin.groups.subtitle') }}
diff --git a/frontend/src/pages/AdminIcons.vue b/frontend/src/pages/AdminIcons.vue index 66c98aac8..b7e14a6b3 100644 --- a/frontend/src/pages/AdminIcons.vue +++ b/frontend/src/pages/AdminIcons.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-spring.svg" />
-
{{ t('admin.icons.title') }}
+
{{ t('admin.icons.title') }}
{{ t('admin.icons.subtitle') }}
diff --git a/frontend/src/pages/AdminInstances.vue b/frontend/src/pages/AdminInstances.vue index f2c9f14d3..c12ccc4e1 100644 --- a/frontend/src/pages/AdminInstances.vue +++ b/frontend/src/pages/AdminInstances.vue @@ -5,7 +5,7 @@
-
{{ t('admin.instances.title') }}
+
{{ t('admin.instances.title') }}
{{ t('admin.instances.subtitle') }}
diff --git a/frontend/src/pages/AdminLocale.vue b/frontend/src/pages/AdminLocale.vue index c29023df6..ee6e268c1 100644 --- a/frontend/src/pages/AdminLocale.vue +++ b/frontend/src/pages/AdminLocale.vue @@ -5,7 +5,7 @@
-
{{ t('admin.locale.title') }}
+
{{ t('admin.locale.title') }}
{{ t('admin.locale.subtitle') }}
diff --git a/frontend/src/pages/AdminLogin.vue b/frontend/src/pages/AdminLogin.vue index ec4a5f976..b001eef81 100644 --- a/frontend/src/pages/AdminLogin.vue +++ b/frontend/src/pages/AdminLogin.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-bunch-of-keys-animated.svg" />
-
{{ t('admin.login.title') }}
+
{{ t('admin.login.title') }}
{{ t('admin.login.subtitle') }}
diff --git a/frontend/src/pages/AdminMail.vue b/frontend/src/pages/AdminMail.vue index 99bc68387..411818d71 100644 --- a/frontend/src/pages/AdminMail.vue +++ b/frontend/src/pages/AdminMail.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-message-settings-animated.svg" />
-
{{ t('admin.mail.title') }}
+
{{ t('admin.mail.title') }}
{{ t('admin.mail.subtitle') }}
diff --git a/frontend/src/pages/AdminMetrics.vue b/frontend/src/pages/AdminMetrics.vue index d5bc12c7b..f37f227f3 100644 --- a/frontend/src/pages/AdminMetrics.vue +++ b/frontend/src/pages/AdminMetrics.vue @@ -5,7 +5,7 @@
-
{{ t('admin.metrics.title') }}
+
{{ t('admin.metrics.title') }}
{{ t('admin.metrics.subtitle') }}
diff --git a/frontend/src/pages/AdminNavigation.vue b/frontend/src/pages/AdminNavigation.vue index d68af4bf1..94d8c92ca 100644 --- a/frontend/src/pages/AdminNavigation.vue +++ b/frontend/src/pages/AdminNavigation.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-tree-structure.svg" />
-
+
{{ t('admin.navigation.title') }}
diff --git a/frontend/src/pages/AdminRendering.vue b/frontend/src/pages/AdminRendering.vue index 4669d0523..45704baf5 100644 --- a/frontend/src/pages/AdminRendering.vue +++ b/frontend/src/pages/AdminRendering.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-rich-text-converter.svg" />
-
+
{{ $t('admin.rendering.title') }}
diff --git a/frontend/src/pages/AdminScheduler.vue b/frontend/src/pages/AdminScheduler.vue index 26df8d0e2..621bbf820 100644 --- a/frontend/src/pages/AdminScheduler.vue +++ b/frontend/src/pages/AdminScheduler.vue @@ -5,7 +5,7 @@
-
{{ t('admin.scheduler.title') }}
+
{{ t('admin.scheduler.title') }}
{{ t('admin.scheduler.subtitle') }}
diff --git a/frontend/src/pages/AdminSearch.vue b/frontend/src/pages/AdminSearch.vue index af15717b1..06bb1453e 100644 --- a/frontend/src/pages/AdminSearch.vue +++ b/frontend/src/pages/AdminSearch.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-find-and-replace-animated.svg" />
-
{{ t('admin.search.title') }}
+
{{ t('admin.search.title') }}
{{ t('admin.search.subtitle') }}
diff --git a/frontend/src/pages/AdminSecurity.vue b/frontend/src/pages/AdminSecurity.vue index fc64d2d22..751c3966f 100644 --- a/frontend/src/pages/AdminSecurity.vue +++ b/frontend/src/pages/AdminSecurity.vue @@ -5,7 +5,7 @@
-
{{ t('admin.security.title') }}
+
{{ t('admin.security.title') }}
{{ t('admin.security.subtitle') }}
diff --git a/frontend/src/pages/AdminSites.vue b/frontend/src/pages/AdminSites.vue index 197d974f6..1fb84a10f 100644 --- a/frontend/src/pages/AdminSites.vue +++ b/frontend/src/pages/AdminSites.vue @@ -5,7 +5,7 @@
-
{{ t('admin.sites.title') }}
+
{{ t('admin.sites.title') }}
{{ t('admin.sites.subtitle') }}
diff --git a/frontend/src/pages/AdminStorage.vue b/frontend/src/pages/AdminStorage.vue index 6eff54182..a801738c0 100644 --- a/frontend/src/pages/AdminStorage.vue +++ b/frontend/src/pages/AdminStorage.vue @@ -5,7 +5,7 @@
-
{{ t('admin.storage.title') }}
+
{{ t('admin.storage.title') }}
{{ t('admin.storage.subtitle') }}
diff --git a/frontend/src/pages/AdminSystem.vue b/frontend/src/pages/AdminSystem.vue index 6f5a4c0de..1492516b5 100644 --- a/frontend/src/pages/AdminSystem.vue +++ b/frontend/src/pages/AdminSystem.vue @@ -5,7 +5,7 @@
-
{{ t('admin.system.title') }}
+
{{ t('admin.system.title') }}
{{ t('admin.system.subtitle') }}
diff --git a/frontend/src/pages/AdminTerminal.vue b/frontend/src/pages/AdminTerminal.vue index 2bd532b33..7aff6ec2f 100644 --- a/frontend/src/pages/AdminTerminal.vue +++ b/frontend/src/pages/AdminTerminal.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-linux-terminal-animated.svg" />
-
{{ t('admin.terminal.title') }}
+
{{ t('admin.terminal.title') }}
{{ t('admin.terminal.subtitle') }}
@@ -15,7 +15,8 @@
{{ t('admin.terminal.instance') }}
-
+
{{ state.instance }}
diff --git a/frontend/src/pages/AdminTheme.vue b/frontend/src/pages/AdminTheme.vue index eb28c1d6f..20b73506f 100644 --- a/frontend/src/pages/AdminTheme.vue +++ b/frontend/src/pages/AdminTheme.vue @@ -7,7 +7,7 @@ src="/_assets/icons/fluent-paint-roller-animated.svg" />
-
{{ t('admin.theme.title') }}
+
{{ t('admin.theme.title') }}
{{ t('admin.theme.subtitle') }}
@@ -217,7 +217,7 @@ - + {{ t('admin.theme.fonts') }}