@meith/theme-default 0.5.0 → 0.6.0
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/package.json +3 -3
- package/src/panel-icons.tsx +64 -0
- package/src/slots/header.tsx +1 -1
- package/src/slots/pagination.tsx +9 -3
- package/src/slots/panel-nav.tsx +28 -16
- package/src/slots/panel-shell.tsx +30 -5
- package/src/slots/search-results.tsx +11 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meith/theme-default",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Meith's default theme — every slot and every token, and the reference for what a complete theme fills.",
|
|
5
5
|
"license": "LGPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@meith/theme-kit": "^0.
|
|
24
|
-
"@meith/ui": "^0.
|
|
23
|
+
"@meith/theme-kit": "^0.6.0",
|
|
24
|
+
"@meith/ui": "^0.6.0"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": "^19.2.0"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { PanelNavIcon } from '@meith/theme-kit'
|
|
2
|
+
|
|
3
|
+
const SHARED = {
|
|
4
|
+
'aria-hidden': true,
|
|
5
|
+
viewBox: '0 0 16 16',
|
|
6
|
+
fill: 'none',
|
|
7
|
+
stroke: 'currentColor',
|
|
8
|
+
strokeWidth: 1.5,
|
|
9
|
+
strokeLinecap: 'round',
|
|
10
|
+
strokeLinejoin: 'round',
|
|
11
|
+
className: 'size-4 shrink-0',
|
|
12
|
+
} as const
|
|
13
|
+
|
|
14
|
+
const PATHS: Record<PanelNavIcon, string> = {
|
|
15
|
+
overview: 'M2.5 8.5h4l1.5 3 2-6 1.5 3h2.5M2.5 4.5v7a1 1 0 0 0 1 1h9a1 1 0 0 0 1-1v-7',
|
|
16
|
+
settings: 'M3 4.5h10M3 8h10M3 11.5h10M6 3v3M10.5 6.5v3M5 10v3',
|
|
17
|
+
forums: 'M2.5 3.5h4l1 1.5h6v7a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1Zm3 5.5h5M5.5 11h3',
|
|
18
|
+
groups:
|
|
19
|
+
'M6 7.5a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm5.5.5a1.75 1.75 0 1 0 0-3.5M2 13v-.5A3.5 3.5 0 0 1 5.5 9h1A3.5 3.5 0 0 1 10 12.5v.5m1.5-4A3 3 0 0 1 14 12v1',
|
|
20
|
+
users:
|
|
21
|
+
'M8 8a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5Zm-4.5 5v-.5A3.5 3.5 0 0 1 7 9h2a3.5 3.5 0 0 1 3.5 3.5v.5',
|
|
22
|
+
content:
|
|
23
|
+
'M4 2.5h5l3 3v8a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-10a1 1 0 0 1 1-1Zm5 0v3h3M5.5 8.5h5M5.5 11h3',
|
|
24
|
+
antispam: 'M8 2 3 4v4c0 3 2.2 5.2 5 6 2.8-.8 5-3 5-6V4Zm-2 5.5 1.5 1.5L10.5 6',
|
|
25
|
+
themes:
|
|
26
|
+
'M8 2.5a5.5 5.5 0 1 0 0 11c.9 0 1.5-.7 1.5-1.5 0-.4-.2-.7-.4-1a1.4 1.4 0 0 1 1-2.4h1.3A2.6 2.6 0 0 0 14 6C14 4 11.3 2.5 8 2.5Zm-2.5 3.7h.01M9 4.7h.01M11.3 6.4h.01M5.2 9.2h.01',
|
|
27
|
+
plugins:
|
|
28
|
+
'M6 2.8a1.3 1.3 0 0 1 2.6 0V4h2.2a.7.7 0 0 1 .7.7V7h1.2a1.3 1.3 0 0 1 0 2.6H11.5v2.2a.7.7 0 0 1-.7.7H8.6v-1.2a1.3 1.3 0 0 0-2.6 0V12.5H3.8a.7.7 0 0 1-.7-.7V4.7A.7.7 0 0 1 3.8 4H6Z',
|
|
29
|
+
tokens:
|
|
30
|
+
'M9.8 3.2a3.2 3.2 0 1 1-3 5.3L3 12.3v1.2h1.5l.6-.7h1.2v-1.2h1.2l1-1a3.2 3.2 0 0 0 1.3-7.4Zm.9 2.6h.01',
|
|
31
|
+
system:
|
|
32
|
+
'M3 3.5h10a.5.5 0 0 1 .5.5v2.5a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V4a.5.5 0 0 1 .5-.5Zm0 5.5h10a.5.5 0 0 1 .5.5V12a.5.5 0 0 1-.5.5H3a.5.5 0 0 1-.5-.5V9.5A.5.5 0 0 1 3 9Zm2 1.75h.01M5 5.25h.01',
|
|
33
|
+
log: 'M4.5 2.5h7a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1Zm1.5 3h4m-4 2.5h4m-4 2.5h2.5',
|
|
34
|
+
queue:
|
|
35
|
+
'M2.5 9.5h3l1 2h3l1-2h3M2.5 9.5 4 4a1 1 0 0 1 1-.8h6a1 1 0 0 1 1 .8l1.5 5.5v2.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1Z',
|
|
36
|
+
reports: 'M4 14V3m0 0h7.5l-1.5 3 1.5 3H4',
|
|
37
|
+
ip: 'M8 2.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Zm0 0c-1.6 1.4-2.4 3.3-2.4 5.5S6.4 12.1 8 13.5c1.6-1.4 2.4-3.3 2.4-5.5S9.6 3.9 8 2.5ZM2.8 6h10.4M2.8 10h10.4',
|
|
38
|
+
messages:
|
|
39
|
+
'M2.5 5a1 1 0 0 1 1-1h9a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1Zm.4-.4 5.1 4 5.1-4',
|
|
40
|
+
notifications:
|
|
41
|
+
'M8 2.5a3.5 3.5 0 0 0-3.5 3.5c0 3-1 4-1 4h9s-1-1-1-4A3.5 3.5 0 0 0 8 2.5ZM6.8 12a1.3 1.3 0 0 0 2.4 0',
|
|
42
|
+
subscriptions: 'M4 2.8h8a.5.5 0 0 1 .5.5v10L8 10.6l-4.5 2.7v-10a.5.5 0 0 1 .5-.5Z',
|
|
43
|
+
profile:
|
|
44
|
+
'M8 8.2a2.6 2.6 0 1 0 0-5.2 2.6 2.6 0 0 0 0 5.2ZM3.5 13.2v-.7A3.3 3.3 0 0 1 6.8 9.2h2.4a3.3 3.3 0 0 1 3.3 3.3v.7',
|
|
45
|
+
avatar:
|
|
46
|
+
'M3.5 2.8h9a.7.7 0 0 1 .7.7v9a.7.7 0 0 1-.7.7h-9a.7.7 0 0 1-.7-.7v-9a.7.7 0 0 1 .7-.7Zm.3 9.6 3.4-3.9 2 2.2 1.6-1.7 1.6 1.9M6 6.6h.01',
|
|
47
|
+
signature:
|
|
48
|
+
'M2.8 11.5c2.5 0 3-6.5 4.7-6.5 1.2 0 .5 4.5 1.9 4.5 1 0 1.3-2 2.3-2 .8 0 1 1.3 1.5 1.3M3 13.5h10',
|
|
49
|
+
buddies:
|
|
50
|
+
'M5.8 7.6a2.1 2.1 0 1 0 0-4.2 2.1 2.1 0 0 0 0 4.2ZM2 13v-.4a3.3 3.3 0 0 1 3.3-3.3h1a3.3 3.3 0 0 1 3.3 3.3v.4m2.4-7.5v3.4m1.7-1.7h-3.4',
|
|
51
|
+
security:
|
|
52
|
+
'M4.5 7V5.5a3.5 3.5 0 1 1 7 0V7m-7.7 0h8.4a.8.8 0 0 1 .8.8v5a.8.8 0 0 1-.8.8H3.8a.8.8 0 0 1-.8-.8v-5a.8.8 0 0 1 .8-.8Z',
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function PanelIcon({ icon }: { icon: PanelNavIcon }) {
|
|
56
|
+
const path = PATHS[icon]
|
|
57
|
+
if (path === undefined) return null
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<svg {...SHARED}>
|
|
61
|
+
<path d={path} />
|
|
62
|
+
</svg>
|
|
63
|
+
)
|
|
64
|
+
}
|
package/src/slots/header.tsx
CHANGED
|
@@ -40,7 +40,7 @@ export function Header({ boardTitle, homeHref, navigation, logo, children }: Hea
|
|
|
40
40
|
{navigation.length > 0 && (
|
|
41
41
|
<nav aria-label="Board sections" className="border-t border-border bg-surface">
|
|
42
42
|
<div className={PAGE}>
|
|
43
|
-
<ul className="-mx-4 flex items-stretch gap-1 overflow-x-auto px-4 text-sm sm:-mx-6 sm:px-6">
|
|
43
|
+
<ul className="-mx-4 flex items-stretch gap-1 overflow-x-auto px-4 text-sm [mask-image:linear-gradient(to_right,black_calc(100%-1.5rem),transparent)] sm:-mx-6 sm:px-6 sm:[mask-image:none]">
|
|
44
44
|
{navigation.map((item) => (
|
|
45
45
|
<li key={item.href} className="shrink-0">
|
|
46
46
|
<a
|
package/src/slots/pagination.tsx
CHANGED
|
@@ -3,7 +3,14 @@ import type { PaginationModel } from '@meith/theme-kit'
|
|
|
3
3
|
|
|
4
4
|
import { NUMERIC } from '../shared'
|
|
5
5
|
|
|
6
|
-
export function Pagination({
|
|
6
|
+
export function Pagination({
|
|
7
|
+
page,
|
|
8
|
+
pageCount,
|
|
9
|
+
pageCountIsExact,
|
|
10
|
+
pages,
|
|
11
|
+
previousHref,
|
|
12
|
+
nextHref,
|
|
13
|
+
}: PaginationModel) {
|
|
7
14
|
if (pageCount <= 1 && previousHref === null && nextHref === null) return null
|
|
8
15
|
|
|
9
16
|
const step = cn(buttonVariants({ variant: 'outline', size: 'sm' }), 'min-w-20')
|
|
@@ -54,9 +61,8 @@ export function Pagination({ page, pageCount, pages, previousHref, nextHref }: P
|
|
|
54
61
|
})}
|
|
55
62
|
|
|
56
63
|
<li className="ml-1 text-xs whitespace-nowrap text-muted-foreground">
|
|
57
|
-
<span className="sr-only">Page </span>
|
|
58
64
|
<span className={NUMERIC}>
|
|
59
|
-
{page} of {pageCount}
|
|
65
|
+
{pageCountIsExact ? `Page ${page} of ${pageCount}` : `Page ${page}`}
|
|
60
66
|
</span>
|
|
61
67
|
</li>
|
|
62
68
|
</ol>
|
package/src/slots/panel-nav.tsx
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { Disclosure, cn } from '@meith/ui'
|
|
2
2
|
import type { PanelNavItemModel, PanelNavModel } from '@meith/theme-kit'
|
|
3
3
|
|
|
4
|
+
import { PanelIcon } from '../panel-icons'
|
|
5
|
+
|
|
4
6
|
const ITEM =
|
|
5
|
-
'flex items-
|
|
7
|
+
'relative flex items-center gap-2.5 rounded-lg px-2.5 py-2 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'
|
|
6
8
|
|
|
7
|
-
const HERE =
|
|
9
|
+
const HERE =
|
|
10
|
+
'bg-secondary font-semibold text-foreground before:absolute before:top-1.5 before:bottom-1.5 before:-left-2.5 before:w-0.5 before:rounded-full before:bg-primary'
|
|
8
11
|
const OPEN = 'font-semibold text-foreground hover:bg-accent'
|
|
9
12
|
const ELSEWHERE = 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
10
13
|
|
|
@@ -13,7 +16,7 @@ function Count({ count }: { count: number }) {
|
|
|
13
16
|
<>
|
|
14
17
|
<span
|
|
15
18
|
aria-hidden="true"
|
|
16
|
-
className="ml-auto rounded-full bg-
|
|
19
|
+
className="ml-auto min-w-5 rounded-full bg-primary px-1.5 py-0.5 text-center text-xs font-semibold tabular-nums text-primary-foreground"
|
|
17
20
|
>
|
|
18
21
|
{count > 99 ? '99+' : count}
|
|
19
22
|
</span>
|
|
@@ -25,7 +28,12 @@ function Count({ count }: { count: number }) {
|
|
|
25
28
|
function Item({ item, className }: { item: PanelNavItemModel; className: string }) {
|
|
26
29
|
const body = (
|
|
27
30
|
<>
|
|
28
|
-
|
|
31
|
+
{item.icon !== null && (
|
|
32
|
+
<span className="text-muted-foreground/80">
|
|
33
|
+
<PanelIcon icon={item.icon} />
|
|
34
|
+
</span>
|
|
35
|
+
)}
|
|
36
|
+
<span className="min-w-0 flex-1 truncate">{item.title}</span>
|
|
29
37
|
{item.count !== null && <Count count={item.count} />}
|
|
30
38
|
</>
|
|
31
39
|
)
|
|
@@ -44,7 +52,10 @@ function Item({ item, className }: { item: PanelNavItemModel; className: string
|
|
|
44
52
|
className={cn(ITEM, className)}
|
|
45
53
|
{...(item.current === null
|
|
46
54
|
? {}
|
|
47
|
-
: {
|
|
55
|
+
: {
|
|
56
|
+
'aria-current':
|
|
57
|
+
item.current === 'here' ? ('page' as const) : ('true' as const),
|
|
58
|
+
})}
|
|
48
59
|
>
|
|
49
60
|
{body}
|
|
50
61
|
</a>
|
|
@@ -54,7 +65,7 @@ function Item({ item, className }: { item: PanelNavItemModel; className: string
|
|
|
54
65
|
function Sections({ label, sections }: Pick<PanelNavModel, 'label' | 'sections'>) {
|
|
55
66
|
return (
|
|
56
67
|
<nav aria-label={label} className="text-sm">
|
|
57
|
-
<ul className="flex flex-col gap-0.5">
|
|
68
|
+
<ul className="flex flex-col gap-0.5 pl-2.5">
|
|
58
69
|
{sections.map((section) => (
|
|
59
70
|
<li
|
|
60
71
|
key={section.href}
|
|
@@ -68,7 +79,7 @@ function Sections({ label, sections }: Pick<PanelNavModel, 'label' | 'sections'>
|
|
|
68
79
|
/>
|
|
69
80
|
|
|
70
81
|
{section.isOpen && section.children.length > 0 && (
|
|
71
|
-
<ul className="mt-0.5 ml-
|
|
82
|
+
<ul className="mt-0.5 ml-4 flex flex-col gap-0.5 border-l border-border pl-2.5">
|
|
72
83
|
{section.children.map((child) => (
|
|
73
84
|
<li key={child.href}>
|
|
74
85
|
<Item
|
|
@@ -89,16 +100,17 @@ function Sections({ label, sections }: Pick<PanelNavModel, 'label' | 'sections'>
|
|
|
89
100
|
export function PanelNav({ label, sections, currentTitle }: PanelNavModel) {
|
|
90
101
|
return (
|
|
91
102
|
<>
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
<div className="sticky top-0 z-20 -mx-4 bg-background/95 px-4 py-2 backdrop-blur-sm sm:-mx-6 sm:px-6 lg:hidden">
|
|
104
|
+
<Disclosure
|
|
105
|
+
summary={label}
|
|
106
|
+
contentClassName="p-2"
|
|
107
|
+
{...(currentTitle === null ? {} : { aside: currentTitle })}
|
|
108
|
+
>
|
|
109
|
+
<Sections label={label} sections={sections} />
|
|
110
|
+
</Disclosure>
|
|
111
|
+
</div>
|
|
100
112
|
|
|
101
|
-
<div className="hidden rounded-
|
|
113
|
+
<div className="hidden rounded-xl border border-border bg-card p-2 shadow-elevation lg:block">
|
|
102
114
|
<Sections label={label} sections={sections} />
|
|
103
115
|
</div>
|
|
104
116
|
</>
|
|
@@ -3,22 +3,34 @@ import type { PanelShellModel } from '@meith/theme-kit'
|
|
|
3
3
|
import { MUTED_LINK } from '../shared'
|
|
4
4
|
|
|
5
5
|
const RAIL =
|
|
6
|
-
'flex flex-col gap-4 px-
|
|
6
|
+
'flex flex-col gap-4 px-4 pt-4 sm:px-6 lg:sticky lg:w-60 lg:shrink-0 lg:self-start lg:py-8 lg:pr-0'
|
|
7
7
|
|
|
8
|
-
export function PanelShell({
|
|
8
|
+
export function PanelShell({
|
|
9
|
+
panel,
|
|
10
|
+
links,
|
|
11
|
+
linksLabel,
|
|
12
|
+
regions,
|
|
13
|
+
children,
|
|
14
|
+
}: PanelShellModel) {
|
|
9
15
|
return (
|
|
10
16
|
<div className="mx-auto flex w-full max-w-6xl flex-1 flex-col lg:flex-row">
|
|
11
17
|
<aside className={`${RAIL} ${panel === 'admincp' ? 'lg:top-14' : 'lg:top-6'}`}>
|
|
12
18
|
{regions.nav}
|
|
13
19
|
|
|
14
20
|
{links.length > 0 && (
|
|
15
|
-
<nav
|
|
16
|
-
|
|
21
|
+
<nav
|
|
22
|
+
aria-label={linksLabel}
|
|
23
|
+
className="hidden rounded-xl border border-border bg-card p-2 shadow-elevation lg:block"
|
|
24
|
+
>
|
|
25
|
+
<p className="px-2.5 pt-1 pb-1.5 text-xs font-medium tracking-wide text-muted-foreground uppercase">
|
|
26
|
+
{linksLabel}
|
|
27
|
+
</p>
|
|
28
|
+
<ul className="flex flex-col gap-0.5 text-sm">
|
|
17
29
|
{links.map((link) => (
|
|
18
30
|
<li key={link.href}>
|
|
19
31
|
<a
|
|
20
32
|
href={link.href}
|
|
21
|
-
className={`block rounded-
|
|
33
|
+
className={`block rounded-lg px-2.5 py-1.5 ${MUTED_LINK} hover:bg-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring`}
|
|
22
34
|
>
|
|
23
35
|
{link.label}
|
|
24
36
|
</a>
|
|
@@ -30,6 +42,19 @@ export function PanelShell({ panel, links, linksLabel, regions, children }: Pane
|
|
|
30
42
|
</aside>
|
|
31
43
|
|
|
32
44
|
<div className="min-w-0 flex-1">{children}</div>
|
|
45
|
+
|
|
46
|
+
{links.length > 0 && (
|
|
47
|
+
<nav
|
|
48
|
+
aria-label={linksLabel}
|
|
49
|
+
className="flex flex-wrap gap-x-4 gap-y-1 px-4 pt-2 text-sm sm:px-6 lg:hidden"
|
|
50
|
+
>
|
|
51
|
+
{links.map((link) => (
|
|
52
|
+
<a key={link.href} href={link.href} className={MUTED_LINK}>
|
|
53
|
+
{link.label}
|
|
54
|
+
</a>
|
|
55
|
+
))}
|
|
56
|
+
</nav>
|
|
57
|
+
)}
|
|
33
58
|
</div>
|
|
34
59
|
)
|
|
35
60
|
}
|
|
@@ -25,6 +25,7 @@ export function SearchResults({
|
|
|
25
25
|
newSearchHref,
|
|
26
26
|
within,
|
|
27
27
|
refine,
|
|
28
|
+
regions,
|
|
28
29
|
}: SearchResultsModel) {
|
|
29
30
|
return (
|
|
30
31
|
<main
|
|
@@ -71,12 +72,16 @@ export function SearchResults({
|
|
|
71
72
|
</CardRows>
|
|
72
73
|
)}
|
|
73
74
|
|
|
74
|
-
{
|
|
75
|
-
<CardFooter>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
{regions?.pagination !== undefined ? (
|
|
76
|
+
<CardFooter>{regions.pagination}</CardFooter>
|
|
77
|
+
) : (
|
|
78
|
+
nextHref !== null && (
|
|
79
|
+
<CardFooter>
|
|
80
|
+
<a href={nextHref} className={`font-medium text-foreground ${LINK}`}>
|
|
81
|
+
{nextLabel} →
|
|
82
|
+
</a>
|
|
83
|
+
</CardFooter>
|
|
84
|
+
)
|
|
80
85
|
)}
|
|
81
86
|
</Card>
|
|
82
87
|
|