@meith/theme-phasebook 0.1.0 → 0.2.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 +5 -5
- package/src/slots/auth-page.tsx +50 -0
- package/src/slots/discovery-view.tsx +111 -0
- package/src/slots/panel-nav.tsx +100 -0
- package/src/slots/panel-page.tsx +73 -0
- package/src/slots/panel-shell.tsx +39 -0
- package/src/slots/search-results.tsx +101 -0
- package/src/theme.ts +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meith/theme-phasebook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A theme for Meith with a familiar social shape, built on the default theme's slots.",
|
|
5
5
|
"license": "LGPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@meith/theme-
|
|
24
|
-
"@meith/theme-
|
|
25
|
-
"@meith/ui": "^0.
|
|
23
|
+
"@meith/theme-default": "^0.2.0",
|
|
24
|
+
"@meith/theme-kit": "^0.2.0",
|
|
25
|
+
"@meith/ui": "^0.2.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^19.2.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@types/react": "^19.2.
|
|
31
|
+
"@types/react": "^19.2.18"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { AuthPageModel } from '@meith/theme-kit'
|
|
2
|
+
|
|
3
|
+
import { LINK } from '../shared'
|
|
4
|
+
|
|
5
|
+
export function AuthPage({ title, alert, links, regions }: AuthPageModel) {
|
|
6
|
+
return (
|
|
7
|
+
<main
|
|
8
|
+
id="board-content"
|
|
9
|
+
tabIndex={-1}
|
|
10
|
+
className="flex flex-1 flex-col items-center justify-center px-3 py-8 sm:px-4"
|
|
11
|
+
>
|
|
12
|
+
<div className="flex w-full max-w-sm flex-col gap-4 rounded-lg border border-border bg-card p-5 text-card-foreground shadow-elevation">
|
|
13
|
+
<div className="flex flex-col gap-1">
|
|
14
|
+
<h1 className="text-xl leading-tight font-bold tracking-tight">{title}</h1>
|
|
15
|
+
{regions.lede !== undefined && (
|
|
16
|
+
<p className="text-sm text-muted-foreground">{regions.lede}</p>
|
|
17
|
+
)}
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
{alert !== null && (
|
|
21
|
+
<p
|
|
22
|
+
role="alert"
|
|
23
|
+
className="rounded-lg bg-destructive/12 px-3 py-2 text-sm font-semibold text-destructive"
|
|
24
|
+
>
|
|
25
|
+
{alert}
|
|
26
|
+
</p>
|
|
27
|
+
)}
|
|
28
|
+
|
|
29
|
+
{regions.note !== undefined && (
|
|
30
|
+
<p className="text-sm text-muted-foreground">{regions.note}</p>
|
|
31
|
+
)}
|
|
32
|
+
|
|
33
|
+
{regions.form}
|
|
34
|
+
|
|
35
|
+
{links.length > 0 && (
|
|
36
|
+
<div className="flex flex-col gap-1 border-t border-border pt-3 text-sm text-muted-foreground">
|
|
37
|
+
{links.map((link) => (
|
|
38
|
+
<span key={link.href}>
|
|
39
|
+
{link.lead === null ? null : `${link.lead} `}
|
|
40
|
+
<a href={link.href} className={`font-semibold ${LINK}`}>
|
|
41
|
+
{link.label}
|
|
42
|
+
</a>
|
|
43
|
+
</span>
|
|
44
|
+
))}
|
|
45
|
+
</div>
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
48
|
+
</main>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { cn } from '@meith/ui'
|
|
2
|
+
import type { DiscoveryViewModel, TabModel } from '@meith/theme-kit'
|
|
3
|
+
|
|
4
|
+
import { Chip, FEED, LINK, PAGE, PILL, Stamp, count, plural } from '../shared'
|
|
5
|
+
|
|
6
|
+
function Tabs({ label, tabs }: { label: string; tabs: readonly TabModel[] }) {
|
|
7
|
+
if (tabs.length === 0) return null
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<nav
|
|
11
|
+
aria-label={label}
|
|
12
|
+
className="overflow-hidden rounded-lg border border-border bg-card shadow-elevation"
|
|
13
|
+
>
|
|
14
|
+
<ul className="flex overflow-x-auto">
|
|
15
|
+
{tabs.map((tab) => (
|
|
16
|
+
<li key={tab.href} className="shrink-0">
|
|
17
|
+
<a
|
|
18
|
+
href={tab.href}
|
|
19
|
+
{...(tab.isCurrent ? { 'aria-current': 'page' as const } : {})}
|
|
20
|
+
className={cn(
|
|
21
|
+
'inline-flex h-11 items-center px-4 text-sm font-semibold whitespace-nowrap transition-colors',
|
|
22
|
+
tab.isCurrent
|
|
23
|
+
? 'border-b-2 border-primary text-primary'
|
|
24
|
+
: 'border-b-2 border-transparent text-muted-foreground hover:bg-accent hover:text-foreground',
|
|
25
|
+
)}
|
|
26
|
+
>
|
|
27
|
+
{tab.label}
|
|
28
|
+
</a>
|
|
29
|
+
</li>
|
|
30
|
+
))}
|
|
31
|
+
</ul>
|
|
32
|
+
</nav>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function DiscoveryView({
|
|
37
|
+
title,
|
|
38
|
+
blurb,
|
|
39
|
+
tabsLabel,
|
|
40
|
+
tabs,
|
|
41
|
+
rows,
|
|
42
|
+
nextHref,
|
|
43
|
+
nextLabel,
|
|
44
|
+
emptyMessage,
|
|
45
|
+
refusal,
|
|
46
|
+
}: DiscoveryViewModel) {
|
|
47
|
+
return (
|
|
48
|
+
<main id="board-content" tabIndex={-1} className={`${PAGE} flex-1 py-4 sm:py-6`}>
|
|
49
|
+
<div className={`${FEED} flex flex-col gap-4`}>
|
|
50
|
+
<header className="rounded-lg border border-border bg-card px-4 py-3.5 shadow-elevation">
|
|
51
|
+
<h1 className="text-xl leading-tight font-bold tracking-tight">{title}</h1>
|
|
52
|
+
<p className="mt-1 text-sm text-muted-foreground">{blurb}</p>
|
|
53
|
+
</header>
|
|
54
|
+
|
|
55
|
+
<Tabs label={tabsLabel} tabs={tabs} />
|
|
56
|
+
|
|
57
|
+
{refusal !== null ? (
|
|
58
|
+
<p
|
|
59
|
+
role="alert"
|
|
60
|
+
className="rounded-lg border border-border bg-card px-4 py-3.5 text-sm shadow-elevation"
|
|
61
|
+
>
|
|
62
|
+
{refusal.message}{' '}
|
|
63
|
+
<a href={refusal.signInHref} className={`font-semibold ${LINK}`}>
|
|
64
|
+
{refusal.signInLabel}
|
|
65
|
+
</a>
|
|
66
|
+
</p>
|
|
67
|
+
) : rows.length === 0 ? (
|
|
68
|
+
<p className="rounded-lg border border-border bg-card px-4 py-6 text-center text-sm text-muted-foreground shadow-elevation">
|
|
69
|
+
{emptyMessage}
|
|
70
|
+
</p>
|
|
71
|
+
) : (
|
|
72
|
+
<ul className="flex flex-col gap-3">
|
|
73
|
+
{rows.map((row) => (
|
|
74
|
+
<li
|
|
75
|
+
key={row.threadId}
|
|
76
|
+
className="rounded-lg border border-border bg-card px-4 py-3.5 shadow-elevation"
|
|
77
|
+
>
|
|
78
|
+
<div className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
|
|
79
|
+
<a
|
|
80
|
+
href={row.href}
|
|
81
|
+
className="min-w-0 text-[0.9375rem] font-semibold hover:underline"
|
|
82
|
+
>
|
|
83
|
+
{row.title}
|
|
84
|
+
</a>
|
|
85
|
+
<Chip>
|
|
86
|
+
{count(row.replyCount)} {plural(row.replyCount, 'reply', 'replies')}
|
|
87
|
+
</Chip>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
91
|
+
in{' '}
|
|
92
|
+
<a href={row.forum.href} className={LINK}>
|
|
93
|
+
{row.forum.label}
|
|
94
|
+
</a>{' '}
|
|
95
|
+
· started by {row.authorUsername} · last post <Stamp at={row.lastPostAt} />
|
|
96
|
+
{row.lastPostUsername === null ? null : ` by ${row.lastPostUsername}`}
|
|
97
|
+
</p>
|
|
98
|
+
</li>
|
|
99
|
+
))}
|
|
100
|
+
</ul>
|
|
101
|
+
)}
|
|
102
|
+
|
|
103
|
+
{nextHref !== null && (
|
|
104
|
+
<a href={nextHref} className={PILL}>
|
|
105
|
+
{nextLabel} →
|
|
106
|
+
</a>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
</main>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Disclosure, cn } from '@meith/ui'
|
|
2
|
+
import type { PanelNavItemModel, PanelNavModel } from '@meith/theme-kit'
|
|
3
|
+
|
|
4
|
+
import { Chip } from '../shared'
|
|
5
|
+
|
|
6
|
+
const ITEM =
|
|
7
|
+
'flex items-center gap-2 rounded-full px-3 py-2 text-sm font-semibold transition-colors duration-100'
|
|
8
|
+
|
|
9
|
+
const HERE = 'bg-primary/12 text-primary'
|
|
10
|
+
const OPEN = 'text-foreground hover:bg-accent'
|
|
11
|
+
const ELSEWHERE = 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
12
|
+
|
|
13
|
+
function Item({ item, className }: { item: PanelNavItemModel; className: string }) {
|
|
14
|
+
const body = (
|
|
15
|
+
<>
|
|
16
|
+
<span className="min-w-0 flex-1 truncate">{item.title}</span>
|
|
17
|
+
{item.count !== null && (
|
|
18
|
+
<Chip className="bg-primary/12 text-primary">
|
|
19
|
+
{item.count > 99 ? '99+' : item.count}
|
|
20
|
+
<span className="sr-only"> waiting</span>
|
|
21
|
+
</Chip>
|
|
22
|
+
)}
|
|
23
|
+
</>
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
if (item.isRecord) {
|
|
27
|
+
return (
|
|
28
|
+
<span className={cn(ITEM, HERE, className)} aria-current="page">
|
|
29
|
+
{body}
|
|
30
|
+
</span>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<a
|
|
36
|
+
href={item.href}
|
|
37
|
+
className={cn(ITEM, className)}
|
|
38
|
+
{...(item.current === null
|
|
39
|
+
? {}
|
|
40
|
+
: { 'aria-current': item.current === 'here' ? ('page' as const) : ('true' as const) })}
|
|
41
|
+
>
|
|
42
|
+
{body}
|
|
43
|
+
</a>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Sections({ label, sections }: Pick<PanelNavModel, 'label' | 'sections'>) {
|
|
48
|
+
return (
|
|
49
|
+
<nav aria-label={label}>
|
|
50
|
+
<ul className="flex flex-col">
|
|
51
|
+
{sections.map((section) => (
|
|
52
|
+
<li
|
|
53
|
+
key={section.href}
|
|
54
|
+
className={cn(section.isOverview && 'mb-1 border-b border-border pb-1')}
|
|
55
|
+
>
|
|
56
|
+
<Item
|
|
57
|
+
item={section}
|
|
58
|
+
className={section.current === 'here' ? HERE : section.isOpen ? OPEN : ELSEWHERE}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
{section.isOpen && section.children.length > 0 && (
|
|
62
|
+
<ul className="mt-1 ml-4 flex flex-col border-l border-border pl-2">
|
|
63
|
+
{section.children.map((child) => (
|
|
64
|
+
<li key={child.href}>
|
|
65
|
+
<Item
|
|
66
|
+
item={child}
|
|
67
|
+
className={cn(
|
|
68
|
+
'text-[0.8125rem]',
|
|
69
|
+
child.current === 'here' ? HERE : ELSEWHERE,
|
|
70
|
+
)}
|
|
71
|
+
/>
|
|
72
|
+
</li>
|
|
73
|
+
))}
|
|
74
|
+
</ul>
|
|
75
|
+
)}
|
|
76
|
+
</li>
|
|
77
|
+
))}
|
|
78
|
+
</ul>
|
|
79
|
+
</nav>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function PanelNav({ label, sections, currentTitle }: PanelNavModel) {
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<Disclosure
|
|
87
|
+
summary={label}
|
|
88
|
+
className="lg:hidden"
|
|
89
|
+
contentClassName="p-2"
|
|
90
|
+
{...(currentTitle === null ? {} : { aside: currentTitle })}
|
|
91
|
+
>
|
|
92
|
+
<Sections label={label} sections={sections} />
|
|
93
|
+
</Disclosure>
|
|
94
|
+
|
|
95
|
+
<div className="hidden rounded-lg border border-border bg-card p-2 shadow-elevation lg:block">
|
|
96
|
+
<Sections label={label} sections={sections} />
|
|
97
|
+
</div>
|
|
98
|
+
</>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { cn } from '@meith/ui'
|
|
2
|
+
import type { PanelPageModel, PanelSectionModel } from '@meith/theme-kit'
|
|
3
|
+
|
|
4
|
+
import { MUTED_LINK } from '../shared'
|
|
5
|
+
|
|
6
|
+
export function PanelPage({ title, back, width, gap, regions, children }: PanelPageModel) {
|
|
7
|
+
return (
|
|
8
|
+
<main
|
|
9
|
+
id="board-content"
|
|
10
|
+
tabIndex={-1}
|
|
11
|
+
className={cn(
|
|
12
|
+
'flex w-full flex-col',
|
|
13
|
+
width === 'wide' ? 'max-w-none' : 'max-w-4xl',
|
|
14
|
+
gap === 'loose' ? 'gap-4' : 'gap-3',
|
|
15
|
+
)}
|
|
16
|
+
>
|
|
17
|
+
<header className="rounded-lg border border-border bg-card px-4 py-3.5 shadow-elevation">
|
|
18
|
+
<div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2">
|
|
19
|
+
<div className="flex min-w-0 flex-col gap-1">
|
|
20
|
+
{back !== null && (
|
|
21
|
+
<a href={back.href} className={`text-xs font-semibold ${MUTED_LINK}`}>
|
|
22
|
+
← {back.label}
|
|
23
|
+
</a>
|
|
24
|
+
)}
|
|
25
|
+
|
|
26
|
+
<h1 className="text-xl leading-tight font-bold tracking-tight text-balance">
|
|
27
|
+
{title}
|
|
28
|
+
</h1>
|
|
29
|
+
|
|
30
|
+
{regions.lede !== undefined && (
|
|
31
|
+
<p className="text-sm text-muted-foreground">{regions.lede}</p>
|
|
32
|
+
)}
|
|
33
|
+
{regions.meta !== undefined && (
|
|
34
|
+
<p className="text-xs text-muted-foreground">{regions.meta}</p>
|
|
35
|
+
)}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
{regions.actions !== undefined && (
|
|
39
|
+
<div className="flex shrink-0 flex-wrap items-center gap-2">{regions.actions}</div>
|
|
40
|
+
)}
|
|
41
|
+
</div>
|
|
42
|
+
</header>
|
|
43
|
+
|
|
44
|
+
{children}
|
|
45
|
+
</main>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function PanelSection({ title, headingId, regions, children }: PanelSectionModel) {
|
|
50
|
+
return (
|
|
51
|
+
<section aria-labelledby={headingId} className="flex flex-col gap-3">
|
|
52
|
+
<div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-1 px-1">
|
|
53
|
+
<div className="flex min-w-0 flex-col gap-0.5">
|
|
54
|
+
<h2
|
|
55
|
+
id={headingId}
|
|
56
|
+
className="text-[0.9375rem] font-semibold text-muted-foreground"
|
|
57
|
+
>
|
|
58
|
+
{title}
|
|
59
|
+
</h2>
|
|
60
|
+
{regions.description !== undefined && (
|
|
61
|
+
<p className="text-sm text-muted-foreground">{regions.description}</p>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
{regions.actions !== undefined && (
|
|
66
|
+
<div className="flex shrink-0 flex-wrap items-center gap-2">{regions.actions}</div>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
{children}
|
|
71
|
+
</section>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PanelShellModel } from '@meith/theme-kit'
|
|
2
|
+
|
|
3
|
+
import { MUTED_LINK } from '../shared'
|
|
4
|
+
|
|
5
|
+
export function PanelShell({ panel, links, linksLabel, regions, children }: PanelShellModel) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="mx-auto flex w-full max-w-6xl flex-1 flex-col gap-4 px-3 py-4 sm:px-4 lg:flex-row lg:py-6">
|
|
8
|
+
<aside
|
|
9
|
+
className={`flex flex-col gap-3 lg:sticky lg:w-60 lg:shrink-0 lg:self-start ${
|
|
10
|
+
panel === 'admincp' ? 'lg:top-16' : 'lg:top-4'
|
|
11
|
+
}`}
|
|
12
|
+
>
|
|
13
|
+
{regions.nav}
|
|
14
|
+
|
|
15
|
+
{links.length > 0 && (
|
|
16
|
+
<nav
|
|
17
|
+
aria-label={linksLabel}
|
|
18
|
+
className="rounded-lg border border-border bg-card p-2 text-sm shadow-elevation"
|
|
19
|
+
>
|
|
20
|
+
<ul className="flex flex-col">
|
|
21
|
+
{links.map((link) => (
|
|
22
|
+
<li key={link.href}>
|
|
23
|
+
<a
|
|
24
|
+
href={link.href}
|
|
25
|
+
className={`block rounded-full px-3 py-2 font-semibold ${MUTED_LINK} hover:bg-accent hover:text-foreground hover:no-underline`}
|
|
26
|
+
>
|
|
27
|
+
{link.label}
|
|
28
|
+
</a>
|
|
29
|
+
</li>
|
|
30
|
+
))}
|
|
31
|
+
</ul>
|
|
32
|
+
</nav>
|
|
33
|
+
)}
|
|
34
|
+
</aside>
|
|
35
|
+
|
|
36
|
+
<div className="min-w-0 flex-1">{children}</div>
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { SearchResultsModel } from '@meith/theme-kit'
|
|
2
|
+
|
|
3
|
+
import { FEED, LINK, PAGE, PILL, PILL_PRIMARY, Stamp } from '../shared'
|
|
4
|
+
|
|
5
|
+
export function SearchResults({
|
|
6
|
+
terms,
|
|
7
|
+
searchedAt,
|
|
8
|
+
hits,
|
|
9
|
+
nextHref,
|
|
10
|
+
nextLabel,
|
|
11
|
+
newSearchHref,
|
|
12
|
+
within,
|
|
13
|
+
}: SearchResultsModel) {
|
|
14
|
+
return (
|
|
15
|
+
<main id="board-content" tabIndex={-1} className={`${PAGE} flex-1 py-4 sm:py-6`}>
|
|
16
|
+
<div className={`${FEED} flex flex-col gap-4`}>
|
|
17
|
+
<header className="rounded-lg border border-border bg-card px-4 py-3.5 shadow-elevation">
|
|
18
|
+
<h1 className="text-xl leading-tight font-bold tracking-tight text-balance">
|
|
19
|
+
Results for “{terms}”
|
|
20
|
+
</h1>
|
|
21
|
+
<p className="mt-1 text-sm text-muted-foreground">
|
|
22
|
+
Searched <Stamp at={searchedAt} />. Results are checked against your access
|
|
23
|
+
every time this page is opened, so they can change.
|
|
24
|
+
</p>
|
|
25
|
+
</header>
|
|
26
|
+
|
|
27
|
+
{hits.length === 0 ? (
|
|
28
|
+
<p className="rounded-lg border border-border bg-card px-4 py-6 text-center text-sm text-muted-foreground shadow-elevation">
|
|
29
|
+
Nothing matched — or nothing you can see does. Try fewer words, or a different
|
|
30
|
+
spelling.
|
|
31
|
+
</p>
|
|
32
|
+
) : (
|
|
33
|
+
<ul className="flex flex-col gap-3">
|
|
34
|
+
{hits.map((hit) => (
|
|
35
|
+
<li
|
|
36
|
+
key={hit.postId}
|
|
37
|
+
className="rounded-lg border border-border bg-card px-4 py-3.5 shadow-elevation"
|
|
38
|
+
>
|
|
39
|
+
<a href={hit.href} className="text-[0.9375rem] font-semibold hover:underline">
|
|
40
|
+
{hit.threadTitle}
|
|
41
|
+
</a>
|
|
42
|
+
<p
|
|
43
|
+
className="mt-1 text-sm text-muted-foreground [&_b]:font-semibold [&_b]:text-foreground"
|
|
44
|
+
dangerouslySetInnerHTML={{ __html: hit.excerptHtml }}
|
|
45
|
+
/>
|
|
46
|
+
<p className="mt-1.5 text-xs text-muted-foreground">
|
|
47
|
+
{hit.authorUsername} · <Stamp at={hit.postedAt} />
|
|
48
|
+
</p>
|
|
49
|
+
</li>
|
|
50
|
+
))}
|
|
51
|
+
</ul>
|
|
52
|
+
)}
|
|
53
|
+
|
|
54
|
+
{nextHref !== null && (
|
|
55
|
+
<a href={nextHref} className={PILL}>
|
|
56
|
+
{nextLabel} →
|
|
57
|
+
</a>
|
|
58
|
+
)}
|
|
59
|
+
|
|
60
|
+
<section className="rounded-lg border border-border bg-card shadow-elevation">
|
|
61
|
+
<form
|
|
62
|
+
method="get"
|
|
63
|
+
action={within.action}
|
|
64
|
+
className="flex flex-col gap-3 px-4 py-4"
|
|
65
|
+
>
|
|
66
|
+
<div>
|
|
67
|
+
<label
|
|
68
|
+
htmlFor="search-within"
|
|
69
|
+
className="mb-1 block text-sm font-semibold text-foreground"
|
|
70
|
+
>
|
|
71
|
+
{within.label}
|
|
72
|
+
</label>
|
|
73
|
+
<input
|
|
74
|
+
id="search-within"
|
|
75
|
+
type="search"
|
|
76
|
+
name={within.field}
|
|
77
|
+
defaultValue={within.value}
|
|
78
|
+
autoComplete="off"
|
|
79
|
+
aria-describedby="search-within-hint"
|
|
80
|
+
className="w-full rounded-full border border-input bg-surface px-4 py-2.5 text-sm text-foreground transition-colors focus-visible:border-ring"
|
|
81
|
+
/>
|
|
82
|
+
<p id="search-within-hint" className="mt-1.5 text-xs text-muted-foreground">
|
|
83
|
+
{within.hint}
|
|
84
|
+
</p>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div>
|
|
88
|
+
<button type="submit" className={PILL_PRIMARY}>
|
|
89
|
+
{within.submitLabel}
|
|
90
|
+
</button>
|
|
91
|
+
</div>
|
|
92
|
+
</form>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<a href={newSearchHref} className={`text-sm font-semibold ${LINK}`}>
|
|
96
|
+
Start a new search
|
|
97
|
+
</a>
|
|
98
|
+
</div>
|
|
99
|
+
</main>
|
|
100
|
+
)
|
|
101
|
+
}
|
package/src/theme.ts
CHANGED
|
@@ -2,9 +2,11 @@ import { defaultTheme } from '@meith/theme-default'
|
|
|
2
2
|
import { defineTheme } from '@meith/theme-kit'
|
|
3
3
|
|
|
4
4
|
import { Announcement } from './slots/announcement'
|
|
5
|
+
import { AuthPage } from './slots/auth-page'
|
|
5
6
|
import { BoardIndex } from './slots/board-index'
|
|
6
7
|
import { BoardStats } from './slots/board-stats'
|
|
7
8
|
import { CategoryBlock } from './slots/category-block'
|
|
9
|
+
import { DiscoveryView } from './slots/discovery-view'
|
|
8
10
|
import { ErrorNotice } from './slots/error-notice'
|
|
9
11
|
import { Footer } from './slots/footer'
|
|
10
12
|
import { ForumJump } from './slots/forum-jump'
|
|
@@ -17,11 +19,15 @@ import { MemberProfile } from './slots/member-profile'
|
|
|
17
19
|
import { Navigation } from './slots/navigation'
|
|
18
20
|
import { Notice } from './slots/notice'
|
|
19
21
|
import { Pagination } from './slots/pagination'
|
|
22
|
+
import { PanelNav } from './slots/panel-nav'
|
|
23
|
+
import { PanelPage, PanelSection } from './slots/panel-page'
|
|
24
|
+
import { PanelShell } from './slots/panel-shell'
|
|
20
25
|
import { PostActions } from './slots/post-actions'
|
|
21
26
|
import { PostBit } from './slots/post-bit'
|
|
22
27
|
import { PostForm } from './slots/post-form'
|
|
23
28
|
import { RedirectNotice } from './slots/redirect-notice'
|
|
24
29
|
import { SearchForm } from './slots/search-form'
|
|
30
|
+
import { SearchResults } from './slots/search-results'
|
|
25
31
|
import { Shell } from './slots/shell'
|
|
26
32
|
import { SubforumList } from './slots/subforum-list'
|
|
27
33
|
import { ThreadRow } from './slots/thread-row'
|
|
@@ -63,7 +69,18 @@ export const phasebookTheme = defineTheme({
|
|
|
63
69
|
|
|
64
70
|
MemberProfile,
|
|
65
71
|
|
|
72
|
+
AuthPage,
|
|
73
|
+
|
|
66
74
|
SearchForm,
|
|
75
|
+
SearchResults,
|
|
76
|
+
|
|
77
|
+
DiscoveryView,
|
|
78
|
+
|
|
79
|
+
PanelShell,
|
|
80
|
+
PanelNav,
|
|
81
|
+
PanelPage,
|
|
82
|
+
PanelSection,
|
|
83
|
+
|
|
67
84
|
ForumJump,
|
|
68
85
|
|
|
69
86
|
RedirectNotice,
|