@morphemecms/cms 0.11.0 → 0.13.0-next-20261106203613
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/astro.mjs +2 -1
- package/defaults/blockTexts.ts +9 -9
- package/defaults/collections.ts +257 -257
- package/defaults/colors.ts +74 -74
- package/defaults/company.ts +9 -9
- package/defaults/editor.ts +65 -65
- package/defaults/i18n/da-DK/blockTexts.ts +12 -0
- package/defaults/i18n/da-DK/collections.ts +220 -0
- package/defaults/i18n/da-DK/colors.ts +102 -0
- package/defaults/i18n/da-DK/company.ts +7 -0
- package/defaults/i18n/da-DK/editor.ts +13 -0
- package/defaults/i18n/da-DK/index.ts +31 -0
- package/defaults/i18n/da-DK/internalLinks.ts +12 -0
- package/defaults/i18n/da-DK/opens.ts +7 -0
- package/defaults/i18n/da-DK/popup.ts +9 -0
- package/defaults/i18n/da-DK/privacy.ts +38 -0
- package/defaults/i18n/da-DK/rules.ts +56 -0
- package/defaults/i18n/da-DK/sitedata.ts +8 -0
- package/defaults/i18n/da-DK/standard.ts +8 -0
- package/defaults/i18n/da-DK/standardPages.ts +17 -0
- package/defaults/internalLinks.ts +8 -8
- package/defaults/opens.ts +2 -2
- package/defaults/popup.tsx +7 -7
- package/defaults/privacy.ts +37 -37
- package/defaults/rules.ts +68 -66
- package/defaults/schema.ts +1 -1
- package/defaults/sitedata.ts +4 -4
- package/defaults/standard.ts +9 -6
- package/defaults/standardPages.ts +14 -14
- package/defaults/texts.ts +7 -510
- package/lib/appId.d.mts +1 -0
- package/lib/appId.mjs +6 -0
- package/lib/appRoute.d.mts +2 -2
- package/lib/appRoute.mjs +3 -3
- package/lib/appRoute.test.mjs +8 -8
- package/lib/apps.mjs +13 -3
- package/lib/apps.test.mjs +10 -1
- package/lib/contracts.d.mts +3 -2
- package/lib/contracts.mjs +3 -2
- package/lib/folderChanges.d.mts +29 -0
- package/lib/folderChanges.mjs +34 -0
- package/lib/licenses.mjs +2 -2
- package/lib/licenses.owner.test.mjs +9 -0
- package/lib/menu.mjs +4 -4
- package/lib/menu.test.mjs +101 -101
- package/lib/scheduled.mjs +1 -1
- package/lib/section-ranges.d.mts +1 -1
- package/lib/section-ranges.mjs +8 -14
- package/lib/section-ranges.test.mjs +26 -5
- package/lib/storeEntries.d.mts +3 -1
- package/lib/storeEntries.mjs +22 -8
- package/lib/storeEntries.test.mjs +59 -7
- package/lib/text-sections.d.mts +11 -1
- package/lib/text-sections.mjs +18 -8
- package/lib/text-sections.test.mjs +34 -1
- package/lib/translate.d.mts +11 -0
- package/lib/translate.mjs +13 -1
- package/lib/translate.test.mjs +23 -2
- package/lib/video-id.d.mts +6 -2
- package/lib/video-id.mjs +5 -1
- package/lib/video.d.mts +6 -2
- package/lib/video.mjs +5 -1
- package/lib/without-h1.d.mts +1 -0
- package/lib/without-h1.mjs +19 -4
- package/lib/without-h1.test.mjs +30 -1
- package/package.json +3 -2
- package/scripts/app-screenshots.mjs +9 -8
- package/scripts/check-content.mjs +12 -2
- package/scripts/check-language.mjs +0 -1
- package/scripts/check-site-types.mjs +26 -0
- package/scripts/editor-screens.mjs +3 -3
- package/scripts/site-types.mjs +14 -0
- package/scripts/site-types.test.mjs +21 -0
- package/site/activeTheme.test.mjs +52 -0
- package/site/appSelf.d.mts +2 -0
- package/site/appSelf.mjs +23 -0
- package/site/appSelf.test.mjs +35 -0
- package/site/content.ts +5 -2
- package/site/defineSite.mjs +2 -2
- package/site/schema.ts +3 -3
- package/site/siteModules.mjs +2 -1
- package/site/theme.mjs +19 -8
- package/src/Advanced.tsx +2 -2
- package/src/App.tsx +79 -78
- package/src/AppAdds.tsx +1 -1
- package/src/AppList.tsx +39 -24
- package/src/BlockDialog.tsx +39 -18
- package/src/BlockParts.tsx +6 -6
- package/src/BlockSettings.tsx +2 -2
- package/src/BrandForm.tsx +2 -2
- package/src/Colors.tsx +6 -6
- package/src/CompanyForm.tsx +1 -1
- package/src/Consents.tsx +3 -3
- package/src/CreateFab.tsx +8 -0
- package/src/DataForm.tsx +10 -20
- package/src/Deleted.tsx +3 -3
- package/src/EditorFooter.tsx +2 -2
- package/src/EntryForm.tsx +3 -3
- package/src/FooterSettings.tsx +2 -2
- package/src/FormFrame.tsx +4 -3
- package/src/HeaderSettings.tsx +3 -3
- package/src/Keywords.tsx +5 -5
- package/src/Library.tsx +75 -82
- package/src/Licenses.tsx +8 -8
- package/src/ListFab.tsx +13 -0
- package/src/MainDrawerParts.tsx +3 -3
- package/src/MainMenu.tsx +1 -1
- package/src/MarkdownEditor.tsx +88 -47
- package/src/Media.tsx +11 -20
- package/src/MediaTags.tsx +2 -2
- package/src/Notifications.tsx +2 -2
- package/src/Parts.tsx +17 -17
- package/src/Redirects.tsx +14 -22
- package/src/Screen.tsx +16 -6
- package/src/SeoScores.tsx +6 -6
- package/src/SideColumn.tsx +2 -2
- package/src/StartFab.tsx +6 -8
- package/src/ThemeStore.tsx +37 -16
- package/src/Tokens.tsx +2 -2
- package/src/apps.ts +7 -8
- package/src/checkSite.ts +86 -20
- package/src/drawerYield.d.mts +3 -0
- package/src/drawerYield.mjs +10 -0
- package/src/drawerYield.test.mjs +22 -0
- package/src/editor.css +59 -38
- package/src/examples.ts +1 -1
- package/src/fabScreens.test.mjs +28 -0
- package/src/fabScreens.ts +16 -0
- package/src/i18n/da-DK/library.ts +2 -2
- package/src/i18n/da-DK/text.ts +1 -1
- package/src/i18n/en-US/apps.ts +1 -1
- package/src/i18n/en-US/common.ts +8 -8
- package/src/i18n/en-US/library.ts +5 -5
- package/src/i18n/en-US/parts.ts +3 -3
- package/src/i18n/en-US/text.ts +1 -1
- package/src/i18n/index.ts +4 -8
- package/src/images.ts +2 -2
- package/src/legacyMove.test.mjs +137 -0
- package/src/legacyMove.ts +131 -0
- package/src/licenseData.ts +3 -3
- package/src/markdown.mjs +10 -7
- package/src/markdown.test.mjs +16 -2
- package/src/menuChildren.ts +5 -5
- package/src/menuOpen.ts +20 -4
- package/src/movedRoutes.d.mts +8 -1
- package/src/movedRoutes.mjs +102 -21
- package/src/movedRoutes.test.mjs +128 -6
- package/src/nav.ts +1 -1
- package/src/notificationData.ts +1 -1
- package/src/pageH1Panel.d.mts +4 -0
- package/src/pageH1Panel.mjs +31 -0
- package/src/pageH1Panel.test.mjs +56 -0
- package/src/pagePreview.tsx +22 -12
- package/src/schema.ts +2 -2
- package/src/sectionFrame.ts +3 -3
- package/src/sectionState.d.mts +3 -3
- package/src/sectionState.mjs +6 -6
- package/src/sectionState.test.mjs +14 -2
- package/src/sheetPlacement.d.mts +6 -4
- package/src/sheetPlacement.mjs +15 -10
- package/src/sheetPlacement.test.mjs +16 -9
- package/src/sidePanel.ts +38 -0
- package/src/site.ts +37 -13
- package/src/standard/accordion/index.tsx +1 -1
- package/src/standard/accordion/shared.ts +1 -1
- package/src/standard/buttons/index.tsx +1 -1
- package/src/standard/cards/index.tsx +1 -1
- package/src/standard/cards/shared.ts +1 -1
- package/src/standard/cookies/index.tsx +1 -1
- package/src/standard/posts/index.tsx +1 -1
- package/src/standard/testimonials/index.tsx +1 -1
- package/src/standard/testimonials/list.ts +1 -1
- package/src/store.ts +36 -31
- package/src/tagUses.d.mts +1 -1
- package/src/tagUses.mjs +2 -2
- package/src/tagUses.test.mjs +1 -1
- package/src/topBarSlot.tsx +7 -15
- package/src/ui.tsx +33 -22
- package/src/virtual.d.ts +6 -0
- package/starter/package.json +1 -1
- package/theme/components/PageHeading.astro +22 -0
- package/theme/layouts/Base.astro +2 -2
- package/theme/layouts/PageLayout.astro +37 -20
- package/theme/styles/global.css +2 -1
- package/theme/styles/ui.css +40 -10
package/src/Library.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// and posts can be filtered by their status and by what they pick (a post's tags), a list of what is
|
|
6
6
|
// shown on pages (Promovering) by a page, its kind and whether it is on, as "Filer" (Filters). In a list that can be deleted from, the clock in the top bar ("Slettede …") opens
|
|
7
7
|
// what was deleted (Deleted.tsx), as in "Filer". The tabs the apps installed add to a list (AppDefinition.tabs, Cookiescanner's
|
|
8
|
-
// "Problemer" on "Cookies") are in its top app bar after the list's own, each at #
|
|
8
|
+
// "Problemer" on "Cookies") are in its top app bar after the list's own, each at #list/<list>/<app>. "Use theme" and the move arrows show the
|
|
9
9
|
// loading indicator while they run (only the pressed one).
|
|
10
10
|
import { Fragment, useEffect, useMemo, useState, type ReactNode } from 'react';
|
|
11
11
|
import {
|
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
ListBullets,
|
|
22
22
|
Moon,
|
|
23
23
|
Palette,
|
|
24
|
-
Plus,
|
|
25
24
|
Ruler,
|
|
26
25
|
Shapes,
|
|
27
26
|
SignOut,
|
|
@@ -33,6 +32,7 @@ import { config, countsOf, header, relationsOf, siteName } from '@site/editor';
|
|
|
33
32
|
import { iconPack, iconPacks } from './iconPacks';
|
|
34
33
|
import { theme, themes, type ThemeInfo } from './themes';
|
|
35
34
|
import { StartFab } from './StartFab';
|
|
35
|
+
import { ListFab } from './ListFab';
|
|
36
36
|
import { StartStatus } from './StartStatus';
|
|
37
37
|
import {
|
|
38
38
|
appearance,
|
|
@@ -60,14 +60,12 @@ import {
|
|
|
60
60
|
Group,
|
|
61
61
|
IconButton,
|
|
62
62
|
LeadingIcon,
|
|
63
|
-
NewChoice,
|
|
64
63
|
SearchRow,
|
|
65
64
|
useKept,
|
|
66
65
|
SegmentedButton,
|
|
67
66
|
UnfoldButton,
|
|
68
67
|
GroupTitle,
|
|
69
68
|
SwitchRow,
|
|
70
|
-
IconLink,
|
|
71
69
|
ScoreRing,
|
|
72
70
|
scoreOf,
|
|
73
71
|
Button,
|
|
@@ -118,7 +116,7 @@ import { offBlocks } from './registry';
|
|
|
118
116
|
import { sideChoicesOf, sideSettingOf } from './SideColumn';
|
|
119
117
|
|
|
120
118
|
// Where a part opens: its list, or the file itself when it is one file (the menu).
|
|
121
|
-
export const hrefOf = (c: Collection) => (c.kind === 'files' && c.files.length === 1 ? `#${c.files[0].file}` : `#
|
|
119
|
+
export const hrefOf = (c: Collection) => (c.kind === 'files' && c.files.length === 1 ? `#${c.files[0].file}` : `#list/${c.id}`);
|
|
122
120
|
|
|
123
121
|
const countOf = (c: Collection, files: RepoFile[]): number =>
|
|
124
122
|
c.kind === 'files' ? c.files.length : files.filter((f) => f.path.startsWith(`${c.folder}/`)).length;
|
|
@@ -126,39 +124,39 @@ const countOf = (c: Collection, files: RepoFile[]): number =>
|
|
|
126
124
|
// A part's name, where it opens, and how many entries it has (null for one file): for the main drawer (MainMenu.tsx).
|
|
127
125
|
export function partOf(id: string, files: RepoFile[]): { label: string; href: string; count: number | null } {
|
|
128
126
|
const { parts } = t.common;
|
|
129
|
-
if (id === '
|
|
130
|
-
if (id === 'header') return { label: parts.header, href: '#
|
|
131
|
-
if (id === 'footer') return { label: parts.footer, href: '#
|
|
132
|
-
if (id === '
|
|
133
|
-
if (id === '
|
|
134
|
-
if (id === '
|
|
135
|
-
if (id === '
|
|
136
|
-
if (id === '
|
|
127
|
+
if (id === 'company') return { label: parts.company, href: '#company', count: null };
|
|
128
|
+
if (id === 'header') return { label: parts.header, href: '#appearance/header', count: null };
|
|
129
|
+
if (id === 'footer') return { label: parts.footer, href: '#appearance/footer', count: null };
|
|
130
|
+
if (id === 'lists') return { label: parts.lists, href: '#lists', count: listsShown(files).length };
|
|
131
|
+
if (id === 'blocks') return { label: parts.blocks, href: '#blocks', count: blockParts.length };
|
|
132
|
+
if (id === 'files') return { label: parts.media, href: '#files', count: mediaOf(files).length + filesOf(files).length };
|
|
133
|
+
if (id === 'appearance') return { label: parts.appearance, href: '#appearance', count: null };
|
|
134
|
+
if (id === 'block-settings') return { label: parts.blockSettings, href: '#block-settings', count: null };
|
|
137
135
|
if (id === 'apps') return { label: parts.apps, href: '#apps', count: null };
|
|
138
136
|
if (id === 'appstore') return { label: t.apps.find, href: `#${STORE_ROUTE}`, count: null };
|
|
139
|
-
if (id === '
|
|
137
|
+
if (id === 'redirects') return { label: parts.redirects, href: `#${REDIRECTS_ROUTE}`, count: null };
|
|
140
138
|
const seoPart = seoParts.find((p) => p.id === id);
|
|
141
139
|
if (seoPart) return { label: seoPart.label, href: `#seo/${id}`, count: null };
|
|
142
140
|
// The screens under "Udseende" (Theme): the ones the editor has, then the site's own (appearance).
|
|
143
141
|
const appearanceLabel = {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
themes: parts.themes,
|
|
143
|
+
'icon-packs': parts.iconPacks,
|
|
144
|
+
motion: parts.motion,
|
|
145
|
+
'side-column': parts.sideColumn,
|
|
146
|
+
colors: parts.colors,
|
|
149
147
|
logo: parts.brand,
|
|
150
|
-
|
|
148
|
+
parts: parts.editorParts,
|
|
151
149
|
}[id];
|
|
152
150
|
const appearancePart = appearanceLabel ?? appearance.find((p) => p.id === id)?.label;
|
|
153
|
-
if (appearancePart) return { label: appearancePart, href: `#
|
|
151
|
+
if (appearancePart) return { label: appearancePart, href: `#appearance/${id}`, count: null };
|
|
154
152
|
// The parts of a screen with parts ("Privatliv"): where each opens, or its screen's address with its id.
|
|
155
153
|
for (const screen of partScreens) {
|
|
156
154
|
const own = screen.parts.find((p) => p.id === id);
|
|
157
155
|
if (own) return { label: own.label, href: own.href ?? `#${screen.id}/${id}`, count: null };
|
|
158
156
|
}
|
|
159
157
|
if (id === 'morpheme') return { label: parts.morpheme, href: `#${CMS_ROUTE}`, count: null };
|
|
160
|
-
if (id === '
|
|
161
|
-
if (id === '
|
|
158
|
+
if (id === 'advanced') return { label: parts.advanced, href: '#advanced', count: null };
|
|
159
|
+
if (id === 'licenses') return { label: parts.licenses, href: '#licenses', count: null };
|
|
162
160
|
const screen = partScreens.find((s) => s.id === id);
|
|
163
161
|
if (screen) return { label: screen.label, href: `#${id}`, count: null };
|
|
164
162
|
if (id === 'seo') return { label: parts.seo, href: '#seo', count: null };
|
|
@@ -178,7 +176,7 @@ function PartRow({ id, label, href, count }: { id: string } & ReturnType<typeof
|
|
|
178
176
|
}
|
|
179
177
|
|
|
180
178
|
// The start screen: the site's name, the CMS version and when the site was last updated (built on Cloudflare, App.tsx), as StartStatus.tsx shows them, under it, and the FAB
|
|
181
|
-
// menu for a new page or post (StartFab.tsx). The parts of the site are in the main drawer (MainMenu.tsx); the rest is left empty for now.
|
|
179
|
+
// menu for a new page or post (StartFab.tsx); each list has its own FAB for a new entry (ListFab.tsx). The parts of the site are in the main drawer (MainMenu.tsx); the rest is left empty for now.
|
|
182
180
|
export function Start({ builtAt }: { builtAt: Date | null }) {
|
|
183
181
|
return (
|
|
184
182
|
<Screen
|
|
@@ -201,12 +199,12 @@ export function Company({ part, files }: { part?: Part; files: RepoFile[] }) {
|
|
|
201
199
|
return (
|
|
202
200
|
<Parts
|
|
203
201
|
title={part.label}
|
|
204
|
-
route={`
|
|
202
|
+
route={`company/${part.id}`}
|
|
205
203
|
parts={[...part.parts, ...appPartsIn(part, files)]}
|
|
206
|
-
back={{ href: '#
|
|
204
|
+
back={{ href: '#company', label: t.common.parts.company }}
|
|
207
205
|
/>
|
|
208
206
|
);
|
|
209
|
-
return <Parts title={t.common.parts.company} route="
|
|
207
|
+
return <Parts title={t.common.parts.company} route="company" parts={companyParts} />;
|
|
210
208
|
}
|
|
211
209
|
|
|
212
210
|
// "Udseende": first "Temaer" (Themes), with the theme the site is built with at the end of its row (or, after a swap,
|
|
@@ -220,28 +218,28 @@ export function Company({ part, files }: { part?: Part; files: RepoFile[] }) {
|
|
|
220
218
|
export function Theme({ files }: { files: RepoFile[] }) {
|
|
221
219
|
const chosen = themes.find((x) => x.id === chosenTheme(files)) ?? theme;
|
|
222
220
|
const parts: Part[] = [
|
|
223
|
-
{ id: '
|
|
221
|
+
{ id: 'themes', label: t.common.parts.themes, icon: icons.themes, detail: chosen.name },
|
|
224
222
|
{
|
|
225
|
-
id: '
|
|
223
|
+
id: 'icon-packs',
|
|
226
224
|
label: t.common.parts.iconPacks,
|
|
227
|
-
icon: icons
|
|
225
|
+
icon: icons['icon-packs'],
|
|
228
226
|
detail: iconPacks.find((x) => x.id === chosenPack(files))?.name,
|
|
229
227
|
},
|
|
230
|
-
{ id: '
|
|
228
|
+
{ id: 'motion', label: t.common.parts.motion, icon: icons.motion, detail: t.library.motionSchemes[motionOf(files)] },
|
|
231
229
|
{
|
|
232
|
-
id: '
|
|
230
|
+
id: 'side-column',
|
|
233
231
|
label: t.common.parts.sideColumn,
|
|
234
|
-
icon: icons
|
|
232
|
+
icon: icons['side-column'],
|
|
235
233
|
detail: sideChoicesOf(files).find((x) => x.type === sideSettingOf(files))?.label ?? t.library.sideNone,
|
|
236
234
|
},
|
|
237
|
-
{ id: '
|
|
235
|
+
{ id: 'colors', label: t.common.parts.colors, icon: icons.colors, trailing: <ThemeColors files={files} /> },
|
|
238
236
|
{ id: 'logo', label: t.common.parts.brand, icon: icons.logo },
|
|
239
237
|
{ id: 'header', label: t.common.parts.header, icon: icons.header },
|
|
240
238
|
{ id: 'footer', label: t.common.parts.footer, icon: icons.footer },
|
|
241
239
|
...appearance,
|
|
242
|
-
{ id: '
|
|
240
|
+
{ id: 'parts', label: t.common.parts.editorParts, icon: icons.parts },
|
|
243
241
|
];
|
|
244
|
-
return <Parts title={t.common.parts.appearance} route="
|
|
242
|
+
return <Parts title={t.common.parts.appearance} route="appearance" parts={parts} back={backFrom('appearance')} />;
|
|
245
243
|
}
|
|
246
244
|
|
|
247
245
|
/** By "Farver": the site's primary, secondary and tertiary colours (accent, secondary, tertiary) in the mode the editor
|
|
@@ -254,8 +252,8 @@ function ThemeColors({ files }: { files: RepoFile[] }) {
|
|
|
254
252
|
);
|
|
255
253
|
}
|
|
256
254
|
|
|
257
|
-
const backToAppearance = { href: '#
|
|
258
|
-
const backToThemes = { href: '#
|
|
255
|
+
const backToAppearance = { href: '#appearance', label: t.common.parts.appearance };
|
|
256
|
+
const backToThemes = { href: '#appearance/themes', label: t.common.parts.themes };
|
|
259
257
|
|
|
260
258
|
/** Under a theme's name: whether the site is built with it ("I brug") or is changing to it ("Skifter hertil"). */
|
|
261
259
|
function themeStatus(id: string, files: RepoFile[]): string | undefined {
|
|
@@ -263,7 +261,7 @@ function themeStatus(id: string, files: RepoFile[]): string | undefined {
|
|
|
263
261
|
if (id === chosenTheme(files)) return t.library.themeNext;
|
|
264
262
|
}
|
|
265
263
|
|
|
266
|
-
/** "Temaer" (#
|
|
264
|
+
/** "Temaer" (#appearance/themes): the themes installed (src/themes/, packages/editor/src/themes.ts; and one from the store the site's build
|
|
267
265
|
* does not have yet, as "Installeres…"), by name, each with its picture, its version and who made it, and whether it is
|
|
268
266
|
* in use or the store has a newer version, opening its page (ThemePage). More are in "Appstore", under "Indstillinger". */
|
|
269
267
|
export function Themes({ env, files }: { env: Env; files: RepoFile[] }) {
|
|
@@ -283,7 +281,7 @@ export function Themes({ env, files }: { env: Env; files: RepoFile[] }) {
|
|
|
283
281
|
return (
|
|
284
282
|
<ListItem
|
|
285
283
|
key={x.id}
|
|
286
|
-
href={`#
|
|
284
|
+
href={`#appearance/themes/${x.id}`}
|
|
287
285
|
leading={<ThemePicture src={x.icon} />}
|
|
288
286
|
headline={x.name}
|
|
289
287
|
supporting={t.library.themeByline(x.version, x.author)}
|
|
@@ -298,7 +296,7 @@ export function Themes({ env, files }: { env: Env; files: RepoFile[] }) {
|
|
|
298
296
|
);
|
|
299
297
|
}
|
|
300
298
|
|
|
301
|
-
/** "Ikonpakker" (#
|
|
299
|
+
/** "Ikonpakker" (#appearance/icon-packs): the icon packs installed (the system's own, packages/editor/icons/, and those the themes
|
|
302
300
|
* installed bring; iconPacks.ts), by name, each with who made it, its licence, the theme it came with and a few of its
|
|
303
301
|
* icons as they are, the one chosen ticked (chosenPack), with "I brug" by the one the site and the editor are built with
|
|
304
302
|
* and "Skifter hertil …" by the one chosen until they are. A tap on another asks first and then saves it in the site's
|
|
@@ -367,7 +365,7 @@ export function motionOf(files: RepoFile[]): MotionScheme {
|
|
|
367
365
|
return schemeInUse(scheme, theme.motion, themes.find((x) => x.id === STANDARD_THEME)?.motion);
|
|
368
366
|
}
|
|
369
367
|
|
|
370
|
-
/** "Bevægelse" (#
|
|
368
|
+
/** "Bevægelse" (#appearance/motion): Material 3's motion schemes and our calm one (lib/motion.ts), each with how it
|
|
371
369
|
* moves, the one in use ticked (motionOf) and "Temaets valg" by the theme's own. A tap on another asks first and then
|
|
372
370
|
* saves it in the site's file (config.motion) at once, in its own commit, as an icon pack is; the editor moves by it at
|
|
373
371
|
* once (applyMotion, App.tsx), the site after it is built. */
|
|
@@ -424,7 +422,7 @@ export function MotionSchemes({ env, files }: { env: Env; files: RepoFile[] }) {
|
|
|
424
422
|
);
|
|
425
423
|
}
|
|
426
424
|
|
|
427
|
-
/** A theme's page (#
|
|
425
|
+
/** A theme's page (#appearance/themes/<id>), the same for every theme, made to show what it would make of the site, so
|
|
428
426
|
* it can be chosen or not: its picture, name, version and who made it, and whether it is in use; "Brug temaet", for any
|
|
429
427
|
* other than the one chosen, which asks first and then saves it in the site's file (config.theme) at once, in its own
|
|
430
428
|
* commit, and the site is built with it; the pictures of the site in it (its screenshots/, packages/editor/scripts/theme-screenshots.mjs),
|
|
@@ -507,37 +505,37 @@ export function ThemePage({ of, env, files }: { of: ThemeInfo; env: Env; files:
|
|
|
507
505
|
<ListItem key={text} icon={glyph} headline={text} />
|
|
508
506
|
))}
|
|
509
507
|
</Group>
|
|
510
|
-
<OwnerLicenses id={`
|
|
508
|
+
<OwnerLicenses id={`theme/${of.id}`} name={of.name} author={of.author} version={of.version} declared={of} />
|
|
511
509
|
<DeveloperRow name={of.author} />
|
|
512
510
|
<ThemeStoreButtons of={of} env={env} files={files} />
|
|
513
511
|
</Screen>
|
|
514
512
|
);
|
|
515
513
|
}
|
|
516
514
|
|
|
517
|
-
/** "Dele" (#
|
|
515
|
+
/** "Dele" (#appearance/parts): the parts the editor and the site are built of, each on a screen of its own: the editor's
|
|
518
516
|
* (Parts.tsx), the theme's UI components, the blocks (the standard ones and the apps') and each list of kinds
|
|
519
517
|
* ("Promovering", its own kinds and the apps'), as the theme shows them (BlockParts.tsx), and the theme's design tokens ("Værdier", Tokens.tsx). */
|
|
520
518
|
export function PartsHome() {
|
|
521
519
|
const parts: Part[] = [
|
|
522
|
-
{ id: 'editor', label: t.parts.screens.editor, icon: icons.
|
|
523
|
-
{ id: 'ui', label: t.parts.screens.components, icon: icons.
|
|
524
|
-
{ id: '
|
|
525
|
-
...kindLists().map((c) => ({ id: `
|
|
526
|
-
{ id: '
|
|
520
|
+
{ id: 'editor', label: t.parts.screens.editor, icon: icons.parts },
|
|
521
|
+
{ id: 'ui', label: t.parts.screens.components, icon: icons.appearance },
|
|
522
|
+
{ id: 'blocks', label: t.parts.screens.blocks, icon: icons.blocks },
|
|
523
|
+
...kindLists().map((c) => ({ id: `list/${c.id}`, label: c.label, icon: icons[c.id] ?? icons.lists })),
|
|
524
|
+
{ id: 'values', label: t.parts.screens.values, icon: Ruler },
|
|
527
525
|
];
|
|
528
|
-
return <Parts title={t.common.parts.editorParts} route="
|
|
526
|
+
return <Parts title={t.common.parts.editorParts} route="appearance/parts" parts={parts} back={backToAppearance} />;
|
|
529
527
|
}
|
|
530
528
|
|
|
531
|
-
/** "Søgemaskineoptimering" (#seo), no longer in the menu: "Videresendelser" (Redirects.tsx, #seo/
|
|
529
|
+
/** "Søgemaskineoptimering" (#seo), no longer in the menu: "Videresendelser" (Redirects.tsx, #seo/redirects) and then
|
|
532
530
|
* the site's own parts (seoParts: "Interne links"), each on a screen of its own (CompanyForm.tsx). "SEO-vurdering"
|
|
533
|
-
* (SeoScores.tsx, #seo/
|
|
531
|
+
* (SeoScores.tsx, #seo/rating) is hidden: nothing links to it. */
|
|
534
532
|
export function Seo() {
|
|
535
|
-
const parts: Part[] = [{ id: '
|
|
533
|
+
const parts: Part[] = [{ id: 'redirects', label: t.common.parts.redirects, icon: icons.redirects }, ...seoParts];
|
|
536
534
|
return <Parts title={t.common.parts.seo} route="seo" parts={parts} back={backFrom('seo')} />;
|
|
537
535
|
}
|
|
538
536
|
|
|
539
537
|
// A screen with parts of the site's own (partScreens): "Privatliv"; and with the settings of the apps installed with its
|
|
540
|
-
// category (PartScreen.apps): "Analytics" and "Promovering", each opening the app's form (#
|
|
538
|
+
// category (PartScreen.apps): "Analytics" and "Promovering", each opening the app's form (#analytics/google-analytics).
|
|
541
539
|
export function PartsScreen({ screen, files }: { screen: PartScreen; files: RepoFile[] }) {
|
|
542
540
|
const parts = [...screen.parts, ...appPartsIn(screen, files)];
|
|
543
541
|
return (
|
|
@@ -553,11 +551,11 @@ export function PartsScreen({ screen, files }: { screen: PartScreen; files: Repo
|
|
|
553
551
|
// and the funnel with the filters by group and by whether the block is on a page, each picked one as a chip.
|
|
554
552
|
type BlockSort = 'group' | 'az' | 'za';
|
|
555
553
|
const BLOCK_SORTS: BlockSort[] = ['group', 'az', 'za'];
|
|
556
|
-
const BLOCK_SORT_KEY = 'editor-sort-
|
|
554
|
+
const BLOCK_SORT_KEY = 'editor-sort-blocks';
|
|
557
555
|
type Use = '' | 'used' | 'unused';
|
|
558
556
|
|
|
559
557
|
export function Blocks({ files }: { files: RepoFile[] }) {
|
|
560
|
-
const [query, setQuery] = useKept('
|
|
558
|
+
const [query, setQuery] = useKept('blocks-search', '');
|
|
561
559
|
const [sort, setSort] = useState<BlockSort>(() => {
|
|
562
560
|
try {
|
|
563
561
|
const saved = localStorage.getItem(BLOCK_SORT_KEY);
|
|
@@ -565,8 +563,8 @@ export function Blocks({ files }: { files: RepoFile[] }) {
|
|
|
565
563
|
} catch {}
|
|
566
564
|
return 'group';
|
|
567
565
|
});
|
|
568
|
-
const [group, setGroup] = useKept('
|
|
569
|
-
const [use, setUse] = useKept<Use>('
|
|
566
|
+
const [group, setGroup] = useKept('blocks-group', '');
|
|
567
|
+
const [use, setUse] = useKept<Use>('blocks-use', '');
|
|
570
568
|
// The blocks on a page (any copy, also a hidden one), by their type (a part's id).
|
|
571
569
|
const used = useMemo(() => new Set(blockParts.filter((p) => pagesWith(p.id, files).length).map((p) => p.id)), [files]);
|
|
572
570
|
const bothUses = blockParts.some((p) => used.has(p.id)) && blockParts.some((p) => !used.has(p.id));
|
|
@@ -650,9 +648,9 @@ export function Blocks({ files }: { files: RepoFile[] }) {
|
|
|
650
648
|
{!inGroups.length ? (
|
|
651
649
|
<p className="mb-8 px-1 text-muted">{t.common.noMatch}</p>
|
|
652
650
|
) : sort === 'group' ? (
|
|
653
|
-
inGroups.map((g) => <PartGroup key={g.title} title={g.title} route="
|
|
651
|
+
inGroups.map((g) => <PartGroup key={g.title} title={g.title} route="blocks" parts={g.parts} />)
|
|
654
652
|
) : (
|
|
655
|
-
lettered.map((g) => <PartGroup key={g.key ?? 'all'} title={g.key ?? undefined} route="
|
|
653
|
+
lettered.map((g) => <PartGroup key={g.key ?? 'all'} title={g.key ?? undefined} route="blocks" parts={g.items} />)
|
|
656
654
|
)}
|
|
657
655
|
</Screen>
|
|
658
656
|
);
|
|
@@ -975,7 +973,7 @@ type View = 'liste' | 'menu';
|
|
|
975
973
|
const seoKey = (c: Collection) => `editor-seo-${c.id}`;
|
|
976
974
|
function savedSeo(c: Collection): boolean {
|
|
977
975
|
try {
|
|
978
|
-
return localStorage.getItem(seoKey(c)) === '
|
|
976
|
+
return localStorage.getItem(seoKey(c)) === 'show';
|
|
979
977
|
} catch {
|
|
980
978
|
return false;
|
|
981
979
|
}
|
|
@@ -1006,16 +1004,16 @@ const saved = new Map<string, { oid: string; date: Date }>();
|
|
|
1006
1004
|
|
|
1007
1005
|
// The ways a list can be sorted; by time only where the entries have one: blog posts by their date,
|
|
1008
1006
|
// pages by when they were last saved; by their kind where they have kinds (Promovering).
|
|
1009
|
-
type Sort = '
|
|
1007
|
+
type Sort = 'newest' | 'oldest' | 'az' | 'za' | 'type';
|
|
1010
1008
|
const sortLabel = (c: Collection, s: Sort) => {
|
|
1011
1009
|
const { sorts } = t.library;
|
|
1012
|
-
return c.id === 'pages' && s === '
|
|
1010
|
+
return c.id === 'pages' && s === 'newest' ? sorts.savedNewest : c.id === 'pages' && s === 'oldest' ? sorts.savedOldest : sorts[s];
|
|
1013
1011
|
};
|
|
1014
1012
|
|
|
1015
1013
|
const byTitle = (a: Item, b: Item) => byText(a.title, b.title);
|
|
1016
1014
|
const compare: Record<Sort, (a: Item, b: Item) => number> = {
|
|
1017
|
-
|
|
1018
|
-
|
|
1015
|
+
newest: (a, b) => (b.date ?? '').localeCompare(a.date ?? '') || byTitle(a, b),
|
|
1016
|
+
oldest: (a, b) => (a.date ?? '').localeCompare(b.date ?? '') || byTitle(a, b),
|
|
1019
1017
|
az: byTitle,
|
|
1020
1018
|
za: (a, b) => byTitle(b, a),
|
|
1021
1019
|
type: (a, b) => byText(a.kind ?? '', b.kind ?? '') || byTitle(a, b),
|
|
@@ -1041,7 +1039,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1041
1039
|
// The tabs the apps installed add to it, and the one open (none: the list's own).
|
|
1042
1040
|
const appTabs = tabsOf(collection.id, apps, installedApps(files));
|
|
1043
1041
|
const appTab = appTabs.find((a) => a.app.id === tab);
|
|
1044
|
-
const [query, setQuery] = useKept(`${collection.id}-
|
|
1042
|
+
const [query, setQuery] = useKept(`${collection.id}-search`, '');
|
|
1045
1043
|
// The move that runs (row and target row, null: none); only its arrow shows busy, all arrows stay disabled meanwhile.
|
|
1046
1044
|
const [moving, setMoving] = useState<{ from: number; to: number } | null>(null);
|
|
1047
1045
|
const busy = moving !== null;
|
|
@@ -1060,7 +1058,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1060
1058
|
collection.kind === 'files' || (collection.kind === 'folder' && collection.orderable) || items.length < 2
|
|
1061
1059
|
? []
|
|
1062
1060
|
: collection.id === 'blog' || pages
|
|
1063
|
-
? ['
|
|
1061
|
+
? ['newest', 'oldest', 'az', 'za']
|
|
1064
1062
|
: collection.kind === 'folder' && collection.kinds
|
|
1065
1063
|
? ['az', 'za', 'type']
|
|
1066
1064
|
: ['az', 'za'];
|
|
@@ -1101,7 +1099,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1101
1099
|
// A list of what is shown on pages: only those on one page or the posts of one tag (and those on every
|
|
1102
1100
|
// page), picked among the pages and tags the entries are on, by their names (relationsOf), the tags
|
|
1103
1101
|
// under a heading of their own (`tag:<slug>`); all again when that one is no longer among them.
|
|
1104
|
-
const [onPage, setOnPage] = useKept(`${collection.id}-
|
|
1102
|
+
const [onPage, setOnPage] = useKept(`${collection.id}-page`, '');
|
|
1105
1103
|
const pageNames = useMemo(() => {
|
|
1106
1104
|
if (!items.some((i) => i.shownOn)) return [];
|
|
1107
1105
|
const { pages: all, fixed, categories } = relationsOf(files);
|
|
@@ -1249,7 +1247,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1249
1247
|
function pickSeo(next: boolean) {
|
|
1250
1248
|
setSeo(next);
|
|
1251
1249
|
try {
|
|
1252
|
-
localStorage.setItem(seoKey(collection), next ? '
|
|
1250
|
+
localStorage.setItem(seoKey(collection), next ? 'show' : 'hide');
|
|
1253
1251
|
} catch {}
|
|
1254
1252
|
}
|
|
1255
1253
|
|
|
@@ -1336,7 +1334,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1336
1334
|
/>
|
|
1337
1335
|
);
|
|
1338
1336
|
};
|
|
1339
|
-
const privacyScreen = partScreens.find((s) => s.id === '
|
|
1337
|
+
const privacyScreen = partScreens.find((s) => s.id === 'privacy');
|
|
1340
1338
|
return (
|
|
1341
1339
|
<Screen
|
|
1342
1340
|
title={collection.label}
|
|
@@ -1345,9 +1343,9 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1345
1343
|
collection.id === config.lists.cookies && privacyScreen
|
|
1346
1344
|
? { href: `#${privacyScreen.id}`, label: privacyScreen.label }
|
|
1347
1345
|
: lists.includes(collection.id)
|
|
1348
|
-
? { href: '#
|
|
1346
|
+
? { href: '#lists', label: t.common.parts.lists }
|
|
1349
1347
|
: header.includes(collection.id)
|
|
1350
|
-
? { href: '#
|
|
1348
|
+
? { href: '#appearance/header', label: t.common.parts.header }
|
|
1351
1349
|
: { href: '#', label: siteName }
|
|
1352
1350
|
}
|
|
1353
1351
|
tabs={
|
|
@@ -1359,7 +1357,7 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1359
1357
|
{ value: '', label: collection.label, icon: icons[collection.id as keyof typeof icons] ?? ListIcon },
|
|
1360
1358
|
...appTabs.map((a) => ({ value: a.app.id, label: siteText(a.tab.label), icon: a.tab.icon })),
|
|
1361
1359
|
],
|
|
1362
|
-
onChange: (v) => (location.hash = v ? `
|
|
1360
|
+
onChange: (v) => (location.hash = v ? `list/${collection.id}/${v}` : `list/${collection.id}`),
|
|
1363
1361
|
}
|
|
1364
1362
|
: undefined
|
|
1365
1363
|
}
|
|
@@ -1371,16 +1369,9 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1371
1369
|
icon={ClockCounterClockwise}
|
|
1372
1370
|
label={t.history.deletedOf(collection.label)}
|
|
1373
1371
|
|
|
1374
|
-
onClick={() => (location.hash = `
|
|
1372
|
+
onClick={() => (location.hash = `deleted/${collection.id}`)}
|
|
1375
1373
|
/>
|
|
1376
1374
|
)}
|
|
1377
|
-
{/* Of more than one kind (a pop-up: Standard or an app's, e.g. Mailchimp): a sheet to pick it. */}
|
|
1378
|
-
{collection.create &&
|
|
1379
|
-
(kinds.length > 1 ? (
|
|
1380
|
-
<NewChoice title={collection.create} options={kinds} onChange={(kind) => (location.hash = `#ny/${collection.id}/${kind}`)} />
|
|
1381
|
-
) : (
|
|
1382
|
-
<IconLink href={`#ny/${collection.id}`} label={collection.create!} icon={Plus} />
|
|
1383
|
-
))}
|
|
1384
1375
|
</>
|
|
1385
1376
|
}
|
|
1386
1377
|
>
|
|
@@ -1479,6 +1470,8 @@ export function List({ collection, tab, files, env }: { collection: Collection;
|
|
|
1479
1470
|
) : (
|
|
1480
1471
|
<p className="mb-8 px-1 text-muted">{t.common.noMatch}</p>
|
|
1481
1472
|
)}
|
|
1473
|
+
{/* A new entry: the list's FAB, or a FAB menu of its kinds when it has several (a pop-up: Standard or an app's, e.g. Mailchimp). */}
|
|
1474
|
+
<ListFab collection={collection} kinds={kinds} />
|
|
1482
1475
|
</Screen>
|
|
1483
1476
|
);
|
|
1484
1477
|
}
|
package/src/Licenses.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// "Licenser" (#
|
|
1
|
+
// "Licenser" (#licenses), under "Indstillinger": the third-party work the site and the editor are made with, as the
|
|
2
2
|
// site was last built (/editor/licenses.json, licensesIntegration in packages/editor/lib/licenses.mjs), with a search by
|
|
3
3
|
// name, who made it and the licence's name. First the icon packs (the system's, each with the sets it takes icons from
|
|
4
4
|
// besides its own), then what the editor and the site's own code bring (the npm packages shipped in what is downloaded,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// then each theme the site is built with and each app installed, under its name: its own licence first, then what it
|
|
7
7
|
// brings (what it declares, its icon packs and what is shipped through them alone). Each row has the work's name, its
|
|
8
8
|
// version, licence and who made it, and what it is and where it is used; one with a text opens it
|
|
9
|
-
// (#
|
|
9
|
+
// (#licenses/<id>, LicensePage). An app's and a theme's page has its group too (OwnerLicenses), and one in the store,
|
|
10
10
|
// from the catalog, the same without the texts (StoreLicenseRows).
|
|
11
11
|
import { useEffect, useState } from 'react';
|
|
12
12
|
import { Certificate, Code, Image, Shapes, TextAa, type Icon } from '@phosphor-icons/react';
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
type ThirdParty,
|
|
33
33
|
} from './licenseData';
|
|
34
34
|
|
|
35
|
-
export const LICENSES_ROUTE = '
|
|
35
|
+
export const LICENSES_ROUTE = 'licenses';
|
|
36
36
|
|
|
37
37
|
const KIND_ICONS: Record<LicenseKind, Icon> = { font: TextAa, icons: Shapes, library: Code, image: Image };
|
|
38
38
|
|
|
@@ -46,7 +46,7 @@ const ownerName = (o: Pick<LicenseOwner, 'kind' | 'key' | 'name'>) =>
|
|
|
46
46
|
/** Who brings a work, as a sentence's end: "i editoren og på sitet", "i temaet Material". */
|
|
47
47
|
function placesOf(where: LicenseWhere[], owners: LicenseOwner[]) {
|
|
48
48
|
// The editor and the site first, then the themes and the apps.
|
|
49
|
-
const rank = (w: LicenseWhere) => (w === 'editor' ? 0 : w === 'site' ? 1 : w.startsWith('
|
|
49
|
+
const rank = (w: LicenseWhere) => (w === 'editor' ? 0 : w === 'site' ? 1 : w.startsWith('theme/') ? 2 : 3);
|
|
50
50
|
const named = [...where]
|
|
51
51
|
.sort((a, b) => rank(a) - rank(b))
|
|
52
52
|
.map((w) => {
|
|
@@ -159,7 +159,7 @@ const worksOf = (owner: LicenseOwner, file: LicensesFile) =>
|
|
|
159
159
|
|
|
160
160
|
export default function Licenses() {
|
|
161
161
|
const file = useLicenses();
|
|
162
|
-
const [query, setQuery] = useKept('
|
|
162
|
+
const [query, setQuery] = useKept('licenses-search', '');
|
|
163
163
|
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
164
164
|
const matches = (...texts: (string | null | undefined)[]) => {
|
|
165
165
|
const all = texts.filter(Boolean).join(' ').toLowerCase();
|
|
@@ -170,7 +170,7 @@ export default function Licenses() {
|
|
|
170
170
|
|
|
171
171
|
const owners = file?.owners ?? [];
|
|
172
172
|
// The system's icon packs (a theme's own are under it, `where` it).
|
|
173
|
-
const packs = file ? sorted(file.works.filter((w) => w.kind === 'icons' && !w.where.some((x) => x.startsWith('
|
|
173
|
+
const packs = file ? sorted(file.works.filter((w) => w.kind === 'icons' && !w.where.some((x) => x.startsWith('theme/')))) : [];
|
|
174
174
|
// What the editor and the site bring: the CMS's own licence first, the rest A–Å.
|
|
175
175
|
const { cms, rest: system } = splitCms(
|
|
176
176
|
file ? sorted(file.works.filter((w) => w.kind !== 'icons' && w.where.some((x) => x === 'editor' || x === 'site'))) : [],
|
|
@@ -233,7 +233,7 @@ const paragraphsOf = (text: string) =>
|
|
|
233
233
|
)
|
|
234
234
|
.filter(Boolean);
|
|
235
235
|
|
|
236
|
-
/** One licence (#
|
|
236
|
+
/** One licence (#licenses/<id>): a work's, or an app's or a theme's own: its name, licence, who made it, what it is and
|
|
237
237
|
* its version, and its text. */
|
|
238
238
|
export function LicensePage({ id }: { id: string }) {
|
|
239
239
|
const file = useLicenses();
|
|
@@ -295,7 +295,7 @@ export function OwnerLicenses({
|
|
|
295
295
|
}) {
|
|
296
296
|
const file = useLicenses();
|
|
297
297
|
const owner = file?.owners.find((o) => o.id === id);
|
|
298
|
-
const [kind, key] = id.split('/') as ['app' | '
|
|
298
|
+
const [kind, key] = id.split('/') as ['app' | 'theme', string];
|
|
299
299
|
const self = owner ?? {
|
|
300
300
|
id,
|
|
301
301
|
kind: kind === 'app' ? ('app' as const) : ('theme' as const),
|
package/src/ListFab.tsx
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// The create FAB of a list (List in Library.tsx): its own create action, or a menu of its kinds when it has several.
|
|
2
|
+
// Exposes ListFab. Uses FabMenu (ui.tsx), listFab (fabScreens.ts) and the icons of site.ts.
|
|
3
|
+
import { Plus } from '@phosphor-icons/react';
|
|
4
|
+
import { listFab } from './fabScreens';
|
|
5
|
+
import { icons } from './site';
|
|
6
|
+
import { FabMenu } from './ui';
|
|
7
|
+
|
|
8
|
+
export function ListFab({ collection, kinds }: { collection: { id: string; create?: string }; kinds: { value: string; label: string }[] }) {
|
|
9
|
+
// One action is the FAB's (the +); each of several kinds has its list's icon.
|
|
10
|
+
const actions = listFab(collection, kinds);
|
|
11
|
+
const icon = actions.length > 1 ? (icons[collection.id] ?? Plus) : Plus;
|
|
12
|
+
return <FabMenu icon={Plus} label={collection.create ?? ''} items={actions.map((a) => ({ ...a, icon }))} />;
|
|
13
|
+
}
|
package/src/MainDrawerParts.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The main drawer and its menu button on #
|
|
1
|
+
// The main drawer and its menu button on #appearance/parts/editor (Parts.tsx): the modal drawer in its two levels (sections, and
|
|
2
2
|
// a section's list with the back row and a fold-out), opened from a button, so it can be tried at any width, and the menu
|
|
3
3
|
// button open and closed. The drawer's header is a sample user (AccountRow). Exposes MainDrawerSample. Uses MainDrawer and
|
|
4
4
|
// its parts from ui.tsx.
|
|
@@ -53,8 +53,8 @@ export function MainDrawerSample() {
|
|
|
53
53
|
{section === null ? (
|
|
54
54
|
<MainDrawerLevel>
|
|
55
55
|
<MainDrawerItem href="" icon={icons.home} label={parts.company} />
|
|
56
|
-
<MainDrawerSectionItem icon={icons.
|
|
57
|
-
<MainDrawerSectionItem icon={icons.
|
|
56
|
+
<MainDrawerSectionItem icon={icons.global} label={parts.header} selected onClick={() => setSection('global')} />
|
|
57
|
+
<MainDrawerSectionItem icon={icons.appearance} label={parts.appearance} onClick={() => setSection('appearance')} />
|
|
58
58
|
</MainDrawerLevel>
|
|
59
59
|
) : (
|
|
60
60
|
<MainDrawerLevel focus="list">
|
package/src/MainMenu.tsx
CHANGED
|
@@ -86,7 +86,7 @@ export function MainMenu({ route, files, user }: { route: string; files: RepoFil
|
|
|
86
86
|
onEscape={onEscape}
|
|
87
87
|
header={
|
|
88
88
|
shown === null ? (
|
|
89
|
-
user && <AccountRow user={user} supporting={config.domain} href="#
|
|
89
|
+
user && <AccountRow user={user} supporting={config.domain} href="#account" />
|
|
90
90
|
) : (
|
|
91
91
|
<MainDrawerBack label={t.library.back} name={t.common.backTo(t.library.mainMenu)} onClick={() => show(null)} />
|
|
92
92
|
)
|