@meith/theme-default 0.33.2 → 0.33.4
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/shared.tsx +74 -5
- package/src/slots/announcement.tsx +4 -4
- package/src/slots/auth-page.tsx +7 -5
- package/src/slots/board-index.tsx +7 -7
- package/src/slots/board-stats.tsx +10 -8
- package/src/slots/category-block.tsx +7 -6
- package/src/slots/discovery-view.tsx +36 -33
- package/src/slots/editor-toolbar.tsx +2 -2
- package/src/slots/footer.tsx +2 -2
- package/src/slots/forum-display.tsx +30 -31
- package/src/slots/forum-row.tsx +35 -12
- package/src/slots/header.tsx +62 -33
- package/src/slots/latest-posts.tsx +33 -21
- package/src/slots/latest-threads.tsx +16 -10
- package/src/slots/member-profile.tsx +35 -22
- package/src/slots/navigation.tsx +3 -3
- package/src/slots/pagination.tsx +2 -2
- package/src/slots/panel-nav.tsx +15 -13
- package/src/slots/panel-page.tsx +12 -9
- package/src/slots/panel-shell.tsx +35 -13
- package/src/slots/post-bit.tsx +61 -34
- package/src/slots/post-form.tsx +7 -7
- package/src/slots/subforum-list.tsx +41 -35
- package/src/slots/thread-row.tsx +15 -12
- package/src/slots/thread-view.tsx +4 -4
- package/src/slots/user-panel.tsx +13 -10
- package/src/slots/who-is-online.tsx +11 -5
- package/src/theme.ts +1 -1
|
@@ -1,32 +1,48 @@
|
|
|
1
1
|
import type { PanelShellModel } from '@meith/theme-kit'
|
|
2
2
|
|
|
3
|
-
import { MUTED_LINK } from '../shared'
|
|
3
|
+
import { EYEBROW, MUTED_LINK } from '../shared'
|
|
4
4
|
|
|
5
5
|
const RAIL =
|
|
6
|
-
'flex flex-col gap-4 px-4 pt-
|
|
6
|
+
'flex flex-col gap-4 px-4 pt-5 sm:px-6 lg:sticky lg:w-64 lg:shrink-0 lg:self-start lg:pt-8 lg:pr-0'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
function SwitchGlyph() {
|
|
9
9
|
return (
|
|
10
|
-
<
|
|
11
|
-
|
|
10
|
+
<svg
|
|
11
|
+
aria-hidden="true"
|
|
12
|
+
viewBox="0 0 16 16"
|
|
13
|
+
className="size-3.5 shrink-0 text-muted-foreground/70"
|
|
14
|
+
fill="none"
|
|
15
|
+
stroke="currentColor"
|
|
16
|
+
strokeWidth="1.5"
|
|
17
|
+
strokeLinecap="round"
|
|
18
|
+
strokeLinejoin="round"
|
|
19
|
+
>
|
|
20
|
+
<path d="M6 3.5 9.5 7 6 10.5M3 7h6.5M13 3v8" />
|
|
21
|
+
</svg>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function PanelShell({ links, linksLabel, regions, children }: PanelShellModel) {
|
|
26
|
+
return (
|
|
27
|
+
<div className="mx-auto flex w-full max-w-6xl flex-1 flex-col lg:flex-row lg:gap-8">
|
|
28
|
+
<aside className={`${RAIL} lg:top-14`}>
|
|
12
29
|
{regions.nav}
|
|
13
30
|
|
|
14
31
|
{links.length > 0 && (
|
|
15
32
|
<nav
|
|
16
33
|
aria-label={linksLabel}
|
|
17
|
-
className="hidden rounded-
|
|
34
|
+
className="hidden rounded-xl border border-border bg-card p-2 shadow-elevation lg:block"
|
|
18
35
|
>
|
|
19
|
-
<p className=
|
|
20
|
-
{linksLabel}
|
|
21
|
-
</p>
|
|
36
|
+
<p className={`${EYEBROW} px-3 pt-1.5 pb-1.5`}>{linksLabel}</p>
|
|
22
37
|
<ul className="flex flex-col gap-0.5 text-sm">
|
|
23
38
|
{links.map((link) => (
|
|
24
39
|
<li key={link.href}>
|
|
25
40
|
<a
|
|
26
41
|
href={link.href}
|
|
27
|
-
className={`
|
|
42
|
+
className={`flex items-center gap-2.5 rounded-lg px-3 py-2 ${MUTED_LINK} hover:bg-muted hover:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring`}
|
|
28
43
|
>
|
|
29
|
-
|
|
44
|
+
<SwitchGlyph />
|
|
45
|
+
<span className="min-w-0 flex-1 truncate">{link.label}</span>
|
|
30
46
|
</a>
|
|
31
47
|
</li>
|
|
32
48
|
))}
|
|
@@ -40,10 +56,16 @@ export function PanelShell({ panel, links, linksLabel, regions, children }: Pane
|
|
|
40
56
|
{links.length > 0 && (
|
|
41
57
|
<nav
|
|
42
58
|
aria-label={linksLabel}
|
|
43
|
-
className="flex flex-wrap gap-x-
|
|
59
|
+
className="flex flex-wrap items-center gap-x-2 gap-y-2 px-4 pt-2 pb-6 text-sm sm:px-6 lg:hidden"
|
|
44
60
|
>
|
|
61
|
+
<span className={`${EYEBROW} me-1`}>{linksLabel}</span>
|
|
45
62
|
{links.map((link) => (
|
|
46
|
-
<a
|
|
63
|
+
<a
|
|
64
|
+
key={link.href}
|
|
65
|
+
href={link.href}
|
|
66
|
+
className="inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1 text-xs font-medium text-muted-foreground transition-colors hover:border-primary/40 hover:text-primary"
|
|
67
|
+
>
|
|
68
|
+
<SwitchGlyph />
|
|
47
69
|
{link.label}
|
|
48
70
|
</a>
|
|
49
71
|
))}
|
package/src/slots/post-bit.tsx
CHANGED
|
@@ -10,7 +10,7 @@ const VISIBILITY_TINT = {
|
|
|
10
10
|
deleted: 'border-thread-deleted/50 bg-destructive/5',
|
|
11
11
|
} as const
|
|
12
12
|
|
|
13
|
-
const BODY_X = 'px-4 sm:px-
|
|
13
|
+
const BODY_X = 'px-4 sm:px-6'
|
|
14
14
|
|
|
15
15
|
function StatusBanner({
|
|
16
16
|
visibility,
|
|
@@ -76,8 +76,27 @@ function AuthorBlock({
|
|
|
76
76
|
const c = (key: string) => fromSlotCopy(copy, `default.postBit.${key}`)
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
|
-
<div className="flex items-center gap-3 sm:flex-col sm:items-stretch sm:gap-2 sm:text-center">
|
|
80
|
-
<
|
|
79
|
+
<div className="flex items-center gap-3 sm:flex-col sm:items-stretch sm:gap-2.5 sm:text-center">
|
|
80
|
+
<span className="relative shrink-0 sm:self-center">
|
|
81
|
+
<Avatar
|
|
82
|
+
src={author.avatarUrl}
|
|
83
|
+
name={author.username}
|
|
84
|
+
size={40}
|
|
85
|
+
className="rounded-full sm:hidden"
|
|
86
|
+
/>
|
|
87
|
+
<Avatar
|
|
88
|
+
src={author.avatarUrl}
|
|
89
|
+
name={author.username}
|
|
90
|
+
size={64}
|
|
91
|
+
className="hidden rounded-2xl sm:inline-flex"
|
|
92
|
+
/>
|
|
93
|
+
{author.isOnline && (
|
|
94
|
+
<span
|
|
95
|
+
aria-hidden="true"
|
|
96
|
+
className="absolute right-0 bottom-0 size-3 rounded-full border-2 border-card bg-moderation-approved"
|
|
97
|
+
/>
|
|
98
|
+
)}
|
|
99
|
+
</span>
|
|
81
100
|
|
|
82
101
|
<div className="min-w-0 flex-1 sm:flex-none">
|
|
83
102
|
<p className="truncate text-sm">
|
|
@@ -90,51 +109,55 @@ function AuthorBlock({
|
|
|
90
109
|
</p>
|
|
91
110
|
)}
|
|
92
111
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
<span
|
|
96
|
-
|
|
97
|
-
|
|
112
|
+
<p className="mt-1 flex flex-wrap gap-1 sm:justify-center">
|
|
113
|
+
{groupTags(author.groups, author.title).map((group) => (
|
|
114
|
+
<span
|
|
115
|
+
key={group.title}
|
|
116
|
+
className={cn(
|
|
117
|
+
'inline-flex max-w-full items-center truncate rounded-full bg-muted px-2 py-0.5 text-[0.6875rem] font-medium leading-4 text-muted-foreground',
|
|
118
|
+
group.nameClass,
|
|
119
|
+
)}
|
|
120
|
+
>
|
|
121
|
+
{group.title}
|
|
122
|
+
</span>
|
|
123
|
+
))}
|
|
124
|
+
</p>
|
|
98
125
|
|
|
99
|
-
{author.isOnline && (
|
|
100
|
-
<p className="mt-1 flex items-center gap-1.5 text-xs text-moderation-approved sm:justify-center">
|
|
101
|
-
<span aria-hidden="true" className="size-1.5 rounded-full bg-moderation-approved" />
|
|
102
|
-
{c('online')}
|
|
103
|
-
</p>
|
|
104
|
-
)}
|
|
126
|
+
{author.isOnline && <p className="sr-only">{c('online')}</p>}
|
|
105
127
|
|
|
106
128
|
{badges}
|
|
107
129
|
|
|
108
130
|
<dl
|
|
109
|
-
className={`mt-1 flex flex-wrap gap-x-
|
|
131
|
+
className={`mt-1.5 flex flex-wrap gap-x-3 text-xs text-muted-foreground sm:mt-2.5 sm:flex-col sm:gap-x-0 sm:gap-y-0.5 sm:border-t sm:border-border sm:pt-2.5 ${NUMERIC}`}
|
|
110
132
|
>
|
|
111
133
|
<div className="flex gap-1 sm:justify-center">
|
|
112
134
|
<dt className="sr-only">{c('postsLabel')}</dt>
|
|
113
135
|
<dd>
|
|
114
|
-
{author.postCount.label}{' '}
|
|
136
|
+
<span className="font-medium text-foreground">{author.postCount.label}</span>{' '}
|
|
115
137
|
{author.postCount.value === 1 ? c('post.one') : c('post.other')}
|
|
116
138
|
</dd>
|
|
117
139
|
</div>
|
|
118
|
-
{author.
|
|
140
|
+
{author.reputation != null && (
|
|
119
141
|
<div className="flex gap-1 sm:justify-center">
|
|
120
|
-
<dt className="sr-only">{c('
|
|
142
|
+
<dt className="sr-only">{c('reputationLabel')}</dt>
|
|
121
143
|
<dd>
|
|
122
|
-
|
|
144
|
+
<span className="font-medium text-foreground">{author.reputation.label}</span>{' '}
|
|
145
|
+
{c('reputation')}
|
|
123
146
|
</dd>
|
|
124
147
|
</div>
|
|
125
148
|
)}
|
|
126
|
-
{author.
|
|
149
|
+
{author.joinedAt !== null && (
|
|
127
150
|
<div className="flex gap-1 sm:justify-center">
|
|
128
|
-
<dt className="sr-only">{c('
|
|
151
|
+
<dt className="sr-only">{c('joined')}</dt>
|
|
129
152
|
<dd>
|
|
130
|
-
{
|
|
153
|
+
{c('joined')} <Stamp at={author.joinedAt} />
|
|
131
154
|
</dd>
|
|
132
155
|
</div>
|
|
133
156
|
)}
|
|
134
157
|
</dl>
|
|
135
158
|
|
|
136
159
|
{author.fields.length > 0 && (
|
|
137
|
-
<dl className="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-xs text-muted-foreground sm:mt-
|
|
160
|
+
<dl className="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-xs text-muted-foreground sm:mt-2 sm:flex-col sm:gap-x-0">
|
|
138
161
|
{author.fields.map((field) => (
|
|
139
162
|
<div key={field.label} className="flex min-w-0 gap-1 sm:justify-center">
|
|
140
163
|
<dt className="font-medium">{field.label}:</dt>
|
|
@@ -161,19 +184,19 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
|
|
|
161
184
|
data-post-id={post.id}
|
|
162
185
|
data-visibility={post.visibility}
|
|
163
186
|
className={cn(
|
|
164
|
-
'target:border-primary/60 target:ring-2 target:ring-primary/20',
|
|
187
|
+
'rounded-xl target:border-primary/60 target:ring-2 target:ring-primary/20',
|
|
165
188
|
VISIBILITY_TINT[post.visibility],
|
|
166
189
|
)}
|
|
167
190
|
>
|
|
168
191
|
<StatusBanner visibility={post.visibility} copy={copy} />
|
|
169
192
|
|
|
170
|
-
<div className="grid grid-cols-[minmax(0,1fr)_auto] sm:grid-cols-[
|
|
171
|
-
<div className="col-start-1 row-start-1 min-w-0 border-b border-border py-3 pl-4 sm:row-span-2 sm:border-r sm:border-b-0 sm:bg-surface/
|
|
193
|
+
<div className="grid grid-cols-[minmax(0,1fr)_auto] sm:grid-cols-[11.5rem_minmax(0,1fr)] sm:grid-rows-[auto_minmax(0,1fr)]">
|
|
194
|
+
<div className="col-start-1 row-start-1 min-w-0 border-b border-border py-3 pl-4 sm:row-span-2 sm:border-r sm:border-b-0 sm:bg-surface/50 sm:px-4 sm:py-5">
|
|
172
195
|
<AuthorBlock author={post.author} badges={regions.pluginBadges} copy={copy} />
|
|
173
196
|
</div>
|
|
174
197
|
|
|
175
198
|
<div
|
|
176
|
-
className={`col-start-2 row-start-1 flex flex-col-reverse items-end justify-center gap-1.5 border-b border-border py-3 text-xs text-muted-foreground sm:flex-row sm:items-center sm:justify-between sm:py-
|
|
199
|
+
className={`col-start-2 row-start-1 flex flex-col-reverse items-end justify-center gap-1.5 border-b border-border py-3 text-xs text-muted-foreground sm:flex-row sm:items-center sm:justify-between sm:py-2 ${BODY_X}`}
|
|
177
200
|
>
|
|
178
201
|
{select === null ? (
|
|
179
202
|
<span className="hidden sm:block" />
|
|
@@ -192,16 +215,18 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
|
|
|
192
215
|
|
|
193
216
|
<a
|
|
194
217
|
href={post.permalink}
|
|
195
|
-
className={`inline-flex min-h-
|
|
218
|
+
className={`inline-flex min-h-7 items-center gap-2 ${MUTED_LINK} ${NUMERIC}`}
|
|
196
219
|
>
|
|
197
220
|
<Stamp at={post.postedAt} />
|
|
198
|
-
<span className="font-semibold text-
|
|
221
|
+
<span className="rounded-full bg-muted px-2 py-0.5 font-semibold text-foreground">
|
|
222
|
+
#{post.number}
|
|
223
|
+
</span>
|
|
199
224
|
</a>
|
|
200
225
|
</div>
|
|
201
226
|
|
|
202
|
-
<div className="col-span-2 row-start-2 min-w-0 sm:col-span-1 sm:col-start-2">
|
|
227
|
+
<div className="col-span-2 row-start-2 flex min-w-0 flex-col sm:col-span-1 sm:col-start-2">
|
|
203
228
|
{post.ignored !== null ? (
|
|
204
|
-
<div className={`py-5 text-sm text-muted-foreground ${BODY_X}`}>
|
|
229
|
+
<div className={`flex-1 py-5 text-sm text-muted-foreground ${BODY_X}`}>
|
|
205
230
|
{c('ignoringPrefix')}{' '}
|
|
206
231
|
<span className="font-medium text-foreground">{post.ignored.authorUsername}</span>.{' '}
|
|
207
232
|
{c('hiddenNotice')}{' '}
|
|
@@ -210,7 +235,7 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
|
|
|
210
235
|
</a>
|
|
211
236
|
</div>
|
|
212
237
|
) : (
|
|
213
|
-
<div className={`py-4 sm:py-5 ${BODY_X}`}>
|
|
238
|
+
<div className={`flex-1 py-4 sm:py-5 ${BODY_X}`}>
|
|
214
239
|
<div
|
|
215
240
|
className="prose-md text-[0.9375rem] sm:text-base"
|
|
216
241
|
dangerouslySetInnerHTML={{ __html: post.bodyHtml }}
|
|
@@ -245,7 +270,7 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
|
|
|
245
270
|
height={file.height ?? undefined}
|
|
246
271
|
loading="lazy"
|
|
247
272
|
decoding="async"
|
|
248
|
-
className="mb-1 max-h-56 w-auto rounded-
|
|
273
|
+
className="mb-1 max-h-56 w-auto rounded-lg border border-border object-contain"
|
|
249
274
|
/>
|
|
250
275
|
) : null}
|
|
251
276
|
<span className="block truncate">
|
|
@@ -273,7 +298,9 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
|
|
|
273
298
|
)}
|
|
274
299
|
|
|
275
300
|
{actions && (
|
|
276
|
-
<footer
|
|
301
|
+
<footer
|
|
302
|
+
className={`border-t border-border bg-surface/40 py-1.5 empty:hidden ${BODY_X}`}
|
|
303
|
+
>
|
|
277
304
|
{regions.actions}
|
|
278
305
|
</footer>
|
|
279
306
|
)}
|
package/src/slots/post-form.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { PostFormModel, SlotCopy } from '@meith/theme-kit'
|
|
2
2
|
import { fromSlotCopy } from '@meith/theme-kit'
|
|
3
|
-
import { Alert, AlertDescription, AlertTitle, Card } from '@meith/ui'
|
|
3
|
+
import { Alert, AlertDescription, AlertTitle, buttonVariants, Card, cn } from '@meith/ui'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { PAGE_TITLE, pageAt } from '../shared'
|
|
6
6
|
|
|
7
7
|
export function PostForm({
|
|
8
8
|
heading,
|
|
@@ -16,9 +16,9 @@ export function PostForm({
|
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
18
|
<div className={`${pageAt('max-w-3xl')} flex w-full flex-col gap-5 py-6 sm:py-8`}>
|
|
19
|
-
<div className="flex flex-wrap items-
|
|
20
|
-
<h1 className=
|
|
21
|
-
<a href={cancelHref} className={
|
|
19
|
+
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2">
|
|
20
|
+
<h1 className={PAGE_TITLE}>{heading}</h1>
|
|
21
|
+
<a href={cancelHref} className={cn(buttonVariants({ variant: 'ghost', size: 'sm' }))}>
|
|
22
22
|
{cancelLabel}
|
|
23
23
|
</a>
|
|
24
24
|
</div>
|
|
@@ -31,9 +31,9 @@ export function PostForm({
|
|
|
31
31
|
</Alert>
|
|
32
32
|
)}
|
|
33
33
|
|
|
34
|
-
<Card>
|
|
34
|
+
<Card className="rounded-xl">
|
|
35
35
|
{regions.toolbar}
|
|
36
|
-
<div className="p-4 sm:p-
|
|
36
|
+
<div className="p-4 sm:p-6">{regions.form}</div>
|
|
37
37
|
</Card>
|
|
38
38
|
</div>
|
|
39
39
|
)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { SlotCopy, SubforumListModel } from '@meith/theme-kit'
|
|
2
2
|
import { fromSlotCopy } from '@meith/theme-kit'
|
|
3
|
-
import { Card,
|
|
3
|
+
import { Card, CardRows } from '@meith/ui'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { EYEBROW, Figures, LINK, Tile } from '../shared'
|
|
6
6
|
|
|
7
7
|
export function SubforumList({ forums, copy }: SubforumListModel & { copy: SlotCopy }) {
|
|
8
8
|
if (forums.length === 0) return null
|
|
@@ -10,42 +10,48 @@ export function SubforumList({ forums, copy }: SubforumListModel & { copy: SlotC
|
|
|
10
10
|
const c = (key: string) => fromSlotCopy(copy, `default.subforumList.${key}`)
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
|
-
<Card aria-labelledby="subforums-heading">
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
</CardTitle>
|
|
18
|
-
</CardHeader>
|
|
13
|
+
<Card aria-labelledby="subforums-heading" className="rounded-xl">
|
|
14
|
+
<h2 id="subforums-heading" className={`${EYEBROW} border-b border-border px-5 py-2.5`}>
|
|
15
|
+
{c('heading')}
|
|
16
|
+
</h2>
|
|
19
17
|
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
<CardRows className="grid sm:grid-cols-2 sm:divide-y-0">
|
|
19
|
+
{forums.map((forum) => (
|
|
20
|
+
<li
|
|
21
|
+
key={forum.id}
|
|
22
|
+
className="flex min-w-0 items-center gap-3 px-5 py-3 transition-colors hover:bg-muted/50"
|
|
23
|
+
>
|
|
24
|
+
<Tile label={forum.title} className="size-9 text-sm" />
|
|
25
|
+
<span className="min-w-0 flex-1">
|
|
26
|
+
<a
|
|
27
|
+
href={forum.href}
|
|
28
|
+
className={`block truncate text-sm font-medium text-foreground ${LINK}`}
|
|
29
|
+
>
|
|
25
30
|
{forum.title}
|
|
26
31
|
</a>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
</span>
|
|
33
|
+
{forum.type !== 'link' && (
|
|
34
|
+
<Figures
|
|
35
|
+
className="shrink-0"
|
|
36
|
+
items={[
|
|
37
|
+
{
|
|
38
|
+
label: c('threadsLabel'),
|
|
39
|
+
value: forum.threadCount,
|
|
40
|
+
one: c('thread.one'),
|
|
41
|
+
many: c('thread.other'),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: c('postsLabel'),
|
|
45
|
+
value: forum.postCount,
|
|
46
|
+
one: c('post.one'),
|
|
47
|
+
many: c('post.other'),
|
|
48
|
+
},
|
|
49
|
+
]}
|
|
50
|
+
/>
|
|
51
|
+
)}
|
|
52
|
+
</li>
|
|
53
|
+
))}
|
|
54
|
+
</CardRows>
|
|
49
55
|
</Card>
|
|
50
56
|
)
|
|
51
57
|
}
|
package/src/slots/thread-row.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { SlotCopy, ThreadRowSlotModel } from '@meith/theme-kit'
|
|
2
2
|
import { fromSlotCopy } from '@meith/theme-kit'
|
|
3
|
-
import { Badge } from '@meith/ui'
|
|
3
|
+
import { Avatar, Badge } from '@meith/ui'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { Figures, LINK, Prefix, Stamp, UnreadDot, UserRef } from '../shared'
|
|
6
6
|
|
|
7
7
|
export function ThreadRow({
|
|
8
8
|
thread,
|
|
@@ -19,11 +19,11 @@ export function ThreadRow({
|
|
|
19
19
|
<li
|
|
20
20
|
data-unread={thread.isUnread ? '' : undefined}
|
|
21
21
|
data-visibility={hidden ? thread.visibility : undefined}
|
|
22
|
-
className={`grid grid-cols-[auto_minmax(0,1fr)] gap-x-
|
|
22
|
+
className={`grid grid-cols-[auto_minmax(0,1fr)] gap-x-3.5 gap-y-2 px-4 py-3.5 transition-colors hover:bg-muted/50 sm:px-5 md:grid-cols-[auto_minmax(0,1fr)_9rem_15rem] md:items-center md:gap-x-5 ${hidden ? tint : ''}`}
|
|
23
23
|
>
|
|
24
|
-
<span className="flex items-
|
|
24
|
+
<span className="flex items-center gap-2.5">
|
|
25
25
|
{select !== null && (
|
|
26
|
-
<label className="
|
|
26
|
+
<label className="flex shrink-0 items-center">
|
|
27
27
|
<span className="sr-only">{select.label}</span>
|
|
28
28
|
<input
|
|
29
29
|
type="checkbox"
|
|
@@ -35,11 +35,14 @@ export function ThreadRow({
|
|
|
35
35
|
</label>
|
|
36
36
|
)}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
<span className="relative shrink-0">
|
|
39
|
+
<Avatar src={null} name={thread.author.username} size={36} className="rounded-full" />
|
|
40
|
+
{thread.isUnread && <UnreadDot className="absolute -top-0.5 -right-0.5" />}
|
|
41
|
+
</span>
|
|
39
42
|
</span>
|
|
40
43
|
|
|
41
44
|
<div className="min-w-0">
|
|
42
|
-
<div className="flex flex-wrap items-
|
|
45
|
+
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
43
46
|
{thread.prefix !== null && <Prefix prefix={thread.prefix} />}
|
|
44
47
|
{thread.isSticky && <Badge tone="pinned">{c('pinned')}</Badge>}
|
|
45
48
|
{thread.isLocked && <Badge tone="locked">{c('locked')}</Badge>}
|
|
@@ -51,7 +54,7 @@ export function ThreadRow({
|
|
|
51
54
|
href={thread.href}
|
|
52
55
|
className={
|
|
53
56
|
(thread.isUnread ? 'font-semibold text-foreground' : 'font-medium text-foreground') +
|
|
54
|
-
` ${LINK}`
|
|
57
|
+
` text-[0.9375rem] ${LINK}`
|
|
55
58
|
}
|
|
56
59
|
>
|
|
57
60
|
{thread.title}
|
|
@@ -65,9 +68,9 @@ export function ThreadRow({
|
|
|
65
68
|
</p>
|
|
66
69
|
</div>
|
|
67
70
|
|
|
68
|
-
<div className="col-start-2 flex min-w-0 flex-
|
|
69
|
-
<
|
|
70
|
-
className="md:col-start-3 md:justify-end"
|
|
71
|
+
<div className="col-start-2 flex min-w-0 flex-col gap-y-1 text-xs text-muted-foreground md:contents">
|
|
72
|
+
<Figures
|
|
73
|
+
className="md:col-start-3 md:justify-self-end"
|
|
71
74
|
items={[
|
|
72
75
|
{
|
|
73
76
|
label: c('repliesLabel'),
|
|
@@ -84,7 +87,7 @@ export function ThreadRow({
|
|
|
84
87
|
]}
|
|
85
88
|
/>
|
|
86
89
|
|
|
87
|
-
<div className="flex min-w-0 max-w-full flex-wrap gap-x-1 md:col-start-4 md:block">
|
|
90
|
+
<div className="order-first flex min-w-0 max-w-full flex-wrap gap-x-1 md:order-none md:col-start-4 md:block md:border-l md:border-border md:pl-5">
|
|
88
91
|
{thread.lastPost === null ? (
|
|
89
92
|
<span className="text-thread-moved">{c('noRepliesYet')}</span>
|
|
90
93
|
) : (
|
|
@@ -2,7 +2,7 @@ import type { SlotCopy, ThreadViewModel } from '@meith/theme-kit'
|
|
|
2
2
|
import { fromSlotCopy } from '@meith/theme-kit'
|
|
3
3
|
import { Badge, buttonVariants, cn } from '@meith/ui'
|
|
4
4
|
|
|
5
|
-
import { Counts, PAGE_BODY, Prefix } from '../shared'
|
|
5
|
+
import { Counts, PAGE_BODY, PAGE_TITLE, Prefix } from '../shared'
|
|
6
6
|
|
|
7
7
|
export function ThreadView({
|
|
8
8
|
thread,
|
|
@@ -18,7 +18,7 @@ export function ThreadView({
|
|
|
18
18
|
<div className={PAGE_BODY}>
|
|
19
19
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between sm:gap-6">
|
|
20
20
|
<div className="min-w-0">
|
|
21
|
-
<h1 className=
|
|
21
|
+
<h1 className={PAGE_TITLE}>{thread.title}</h1>
|
|
22
22
|
|
|
23
23
|
<div className="mt-2 flex flex-wrap items-center gap-x-3 gap-y-2">
|
|
24
24
|
{thread.prefix !== null && <Prefix prefix={thread.prefix} />}
|
|
@@ -78,10 +78,10 @@ export function ThreadView({
|
|
|
78
78
|
</div>
|
|
79
79
|
|
|
80
80
|
{regions.tools !== undefined && (
|
|
81
|
-
<div className="flex flex-col gap-3 empty:hidden">{regions.tools}</div>
|
|
81
|
+
<div className="-mb-1 flex flex-col gap-3 empty:hidden">{regions.tools}</div>
|
|
82
82
|
)}
|
|
83
83
|
|
|
84
|
-
<div className="flex flex-col gap-
|
|
84
|
+
<div className="flex flex-col gap-4">{regions.posts}</div>
|
|
85
85
|
|
|
86
86
|
{regions.pagination}
|
|
87
87
|
|
package/src/slots/user-panel.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { SlotCopy, UserPanelModel } from '@meith/theme-kit'
|
|
2
2
|
import { fromSlotCopy } from '@meith/theme-kit'
|
|
3
|
-
import { Avatar, Badge, buttonVariants } from '@meith/ui'
|
|
3
|
+
import { Avatar, Badge, buttonVariants, cn } from '@meith/ui'
|
|
4
4
|
import { Menu } from '@meith/ui/menu'
|
|
5
5
|
|
|
6
6
|
import { MUTED_LINK } from '../shared'
|
|
@@ -28,10 +28,10 @@ export function UserPanel({
|
|
|
28
28
|
<a
|
|
29
29
|
key={link.href}
|
|
30
30
|
href={link.href}
|
|
31
|
-
className={
|
|
32
|
-
variant: index === 0 ? 'primary' : '
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
className={cn(
|
|
32
|
+
buttonVariants({ variant: index === 0 ? 'primary' : 'ghost', size: 'sm' }),
|
|
33
|
+
index > 0 && 'hidden sm:inline-flex',
|
|
34
|
+
)}
|
|
35
35
|
>
|
|
36
36
|
{link.label}
|
|
37
37
|
</a>
|
|
@@ -51,12 +51,12 @@ export function UserPanel({
|
|
|
51
51
|
}}
|
|
52
52
|
/>
|
|
53
53
|
|
|
54
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
54
|
+
<div className="flex min-w-0 items-center gap-1.5 sm:gap-2">
|
|
55
55
|
{regions?.notifications ?? (
|
|
56
56
|
<>
|
|
57
57
|
{unreadNotifications.value > 0 && (
|
|
58
58
|
<a href={notificationsHref} className={COUNT_LINK}>
|
|
59
|
-
<Badge tone="solid">
|
|
59
|
+
<Badge tone="solid" className="rounded-full">
|
|
60
60
|
{unreadNotifications.label}
|
|
61
61
|
<span className="sr-only"> {c('unreadNotifications')}</span>
|
|
62
62
|
<span aria-hidden="true"> {c('new')}</span>
|
|
@@ -65,7 +65,7 @@ export function UserPanel({
|
|
|
65
65
|
)}
|
|
66
66
|
{unreadMessages.value > 0 && (
|
|
67
67
|
<a href={messagesHref} className={COUNT_LINK}>
|
|
68
|
-
<Badge tone="outline">
|
|
68
|
+
<Badge tone="outline" className="rounded-full">
|
|
69
69
|
{unreadMessages.label}
|
|
70
70
|
<span className="sr-only"> {c('unreadMessages')}</span>
|
|
71
71
|
<span aria-hidden="true"> {c('unread')}</span>
|
|
@@ -79,10 +79,13 @@ export function UserPanel({
|
|
|
79
79
|
<Menu
|
|
80
80
|
label={c('yourAccount')}
|
|
81
81
|
items={links}
|
|
82
|
+
triggerClassName="rounded-full py-0.5 pl-0.5 pr-2"
|
|
82
83
|
trigger={
|
|
83
84
|
<>
|
|
84
|
-
<Avatar src={viewer.avatarUrl} name={name} size={
|
|
85
|
-
<span className="max-w-40 truncate font-medium text-foreground">
|
|
85
|
+
<Avatar src={viewer.avatarUrl} name={name} size={28} className="rounded-full" />
|
|
86
|
+
<span className="hidden max-w-40 truncate text-sm font-medium text-foreground sm:inline">
|
|
87
|
+
{name}
|
|
88
|
+
</span>
|
|
86
89
|
<svg
|
|
87
90
|
aria-hidden="true"
|
|
88
91
|
viewBox="0 0 12 12"
|
|
@@ -30,11 +30,17 @@ export function WhoIsOnline({
|
|
|
30
30
|
{c('heading')}
|
|
31
31
|
</h2>
|
|
32
32
|
|
|
33
|
-
<span className={NUMERIC}>
|
|
34
|
-
<span
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
<span className={`inline-flex items-baseline gap-1.5 ${NUMERIC}`}>
|
|
34
|
+
<span
|
|
35
|
+
aria-hidden="true"
|
|
36
|
+
className="size-2 translate-y-px rounded-full bg-moderation-approved"
|
|
37
|
+
/>
|
|
38
|
+
<span>
|
|
39
|
+
<span className="font-semibold text-foreground">{total.label}</span> {c('online')}{' '}
|
|
40
|
+
{memberCount.label} {memberCount.value === 1 ? c('member.one') : c('member.other')}
|
|
41
|
+
{', '}
|
|
42
|
+
{guestCount.label} {guestCount.value === 1 ? c('guest.one') : c('guest.other')}
|
|
43
|
+
</span>
|
|
38
44
|
</span>
|
|
39
45
|
|
|
40
46
|
{memberCount.value === 0 ? (
|