@meith/theme-clubhouse 0.31.0 → 0.33.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 +4 -4
- package/src/copy.ts +2 -0
- package/src/messages/en.json +2 -0
- package/src/shared.tsx +2 -2
- package/src/slots/header.tsx +86 -2
- package/src/slots/post-bit.tsx +27 -25
- package/src/slots/thread-row.tsx +7 -1
- package/src/slots/thread-view.tsx +20 -0
- package/src/theme.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meith/theme-clubhouse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "A sports club theme for Meith — GAA, soccer, basketball — painted from the club's own two colours.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@meith/theme-default": "^0.
|
|
24
|
-
"@meith/theme-kit": "^0.
|
|
25
|
-
"@meith/ui": "^0.
|
|
23
|
+
"@meith/theme-default": "^0.33.0",
|
|
24
|
+
"@meith/theme-kit": "^0.33.0",
|
|
25
|
+
"@meith/ui": "^0.33.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^19.2.0"
|
package/src/copy.ts
CHANGED
package/src/messages/en.json
CHANGED
|
@@ -107,6 +107,8 @@
|
|
|
107
107
|
"clubhouse.threadView.replies": "replies",
|
|
108
108
|
"clubhouse.threadView.reply": "Reply",
|
|
109
109
|
"clubhouse.threadView.views": "views",
|
|
110
|
+
"clubhouse.threadView.watch": "Watch",
|
|
111
|
+
"clubhouse.threadView.watching": "Watching",
|
|
110
112
|
"clubhouse.userPanel.new": "new",
|
|
111
113
|
"clubhouse.userPanel.signedIn": "Signed in",
|
|
112
114
|
"clubhouse.userPanel.unread": "unread",
|
package/src/shared.tsx
CHANGED
|
@@ -192,8 +192,8 @@ export function ReadMark({ unread }: { unread: boolean }) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
export function isEmptyRegion(node: React.ReactNode): boolean {
|
|
195
|
-
if (node === null || node === undefined || node === false) return true
|
|
196
|
-
return Array.isArray(node) && node.
|
|
195
|
+
if (node === null || node === undefined || node === false || node === '') return true
|
|
196
|
+
return Array.isArray(node) && node.every((child) => isEmptyRegion(child))
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
const PREFIX_TONES = {
|
package/src/slots/header.tsx
CHANGED
|
@@ -44,7 +44,7 @@ function Submenu({ items }: { items: HeaderModel['navigation'][number]['submenu'
|
|
|
44
44
|
<a
|
|
45
45
|
href={child.href}
|
|
46
46
|
{...linkTarget(child)}
|
|
47
|
-
className="
|
|
47
|
+
className="flex items-center px-3 py-1.5 text-muted-foreground pointer-coarse:min-h-11 hover:bg-muted hover:text-foreground"
|
|
48
48
|
>
|
|
49
49
|
{child.label}
|
|
50
50
|
</a>
|
|
@@ -54,6 +54,73 @@ function Submenu({ items }: { items: HeaderModel['navigation'][number]['submenu'
|
|
|
54
54
|
)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
function Chevron({ className }: { className: string }) {
|
|
58
|
+
return (
|
|
59
|
+
<svg
|
|
60
|
+
aria-hidden="true"
|
|
61
|
+
viewBox="0 0 12 12"
|
|
62
|
+
className={className}
|
|
63
|
+
fill="none"
|
|
64
|
+
stroke="currentColor"
|
|
65
|
+
strokeWidth="1.5"
|
|
66
|
+
strokeLinecap="round"
|
|
67
|
+
strokeLinejoin="round"
|
|
68
|
+
>
|
|
69
|
+
<path d="m4.5 3 3 3-3 3" />
|
|
70
|
+
</svg>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function MobileNavItem({ item }: { item: HeaderModel['navigation'][number] }) {
|
|
75
|
+
if (item.submenu === undefined || item.submenu.length === 0) {
|
|
76
|
+
return (
|
|
77
|
+
<li>
|
|
78
|
+
<a
|
|
79
|
+
href={item.href}
|
|
80
|
+
{...linkTarget(item)}
|
|
81
|
+
className={`${HEADING} flex min-h-11 items-center px-2.5 text-sm text-muted-foreground hover:bg-accent hover:text-foreground`}
|
|
82
|
+
>
|
|
83
|
+
{item.label}
|
|
84
|
+
</a>
|
|
85
|
+
</li>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<li>
|
|
91
|
+
<details data-nav-disclosure name="clubhouse-header-submenu" className="group/submenu">
|
|
92
|
+
<summary
|
|
93
|
+
className={`${HEADING} flex min-h-11 cursor-default list-none items-center justify-between gap-2 px-2.5 text-sm text-muted-foreground select-none [&::-webkit-details-marker]:hidden [&::marker]:content-none hover:bg-accent hover:text-foreground`}
|
|
94
|
+
>
|
|
95
|
+
<a
|
|
96
|
+
href={item.href}
|
|
97
|
+
{...linkTarget(item)}
|
|
98
|
+
className="min-w-0 flex-1 truncate hover:underline"
|
|
99
|
+
>
|
|
100
|
+
{item.label}
|
|
101
|
+
</a>
|
|
102
|
+
<span className="flex size-11 shrink-0 items-center justify-center">
|
|
103
|
+
<Chevron className="size-3 text-muted-foreground transition-transform group-open/submenu:rotate-90" />
|
|
104
|
+
</span>
|
|
105
|
+
</summary>
|
|
106
|
+
<ul className="ml-2 flex flex-col gap-0.5 border-l border-border py-1 pl-2.5">
|
|
107
|
+
{item.submenu.map((child) => (
|
|
108
|
+
<li key={child.href}>
|
|
109
|
+
<a
|
|
110
|
+
href={child.href}
|
|
111
|
+
{...linkTarget(child)}
|
|
112
|
+
className="flex min-h-11 items-center px-2.5 text-sm text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
113
|
+
>
|
|
114
|
+
{child.label}
|
|
115
|
+
</a>
|
|
116
|
+
</li>
|
|
117
|
+
))}
|
|
118
|
+
</ul>
|
|
119
|
+
</details>
|
|
120
|
+
</li>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
57
124
|
export function Header({
|
|
58
125
|
boardTitle,
|
|
59
126
|
homeHref,
|
|
@@ -84,7 +151,8 @@ export function Header({
|
|
|
84
151
|
<nav aria-label={c('boardSections')} className="border-b border-border bg-surface">
|
|
85
152
|
<div className={PAGE}>
|
|
86
153
|
<ul
|
|
87
|
-
|
|
154
|
+
data-nav-view="desktop"
|
|
155
|
+
className={`-mx-4 hidden items-stretch px-4 sm:-mx-6 sm:px-6 lg:flex ${
|
|
88
156
|
opensMenus ? 'flex-wrap' : 'overflow-x-auto'
|
|
89
157
|
}`}
|
|
90
158
|
>
|
|
@@ -101,6 +169,22 @@ export function Header({
|
|
|
101
169
|
</li>
|
|
102
170
|
))}
|
|
103
171
|
</ul>
|
|
172
|
+
|
|
173
|
+
<div data-nav-view="mobile" className="-mx-4 px-4 py-1 sm:-mx-6 sm:px-6 lg:hidden">
|
|
174
|
+
<details data-nav-disclosure className="group">
|
|
175
|
+
<summary
|
|
176
|
+
className={`${HEADING} flex min-h-11 cursor-default list-none items-center gap-2 text-sm text-foreground select-none [&::-webkit-details-marker]:hidden [&::marker]:content-none`}
|
|
177
|
+
>
|
|
178
|
+
<Chevron className="size-3 shrink-0 transition-transform group-open:rotate-90" />
|
|
179
|
+
{c('boardSections')}
|
|
180
|
+
</summary>
|
|
181
|
+
<ul className="flex flex-col gap-0.5 pb-2">
|
|
182
|
+
{navigation.map((item) => (
|
|
183
|
+
<MobileNavItem key={item.href} item={item} />
|
|
184
|
+
))}
|
|
185
|
+
</ul>
|
|
186
|
+
</details>
|
|
187
|
+
</div>
|
|
104
188
|
</div>
|
|
105
189
|
</nav>
|
|
106
190
|
)}
|
package/src/slots/post-bit.tsx
CHANGED
|
@@ -74,7 +74,7 @@ function GroupBadge({
|
|
|
74
74
|
|
|
75
75
|
function StatLine({ label, children }: { label: string; children: React.ReactNode }) {
|
|
76
76
|
return (
|
|
77
|
-
<div className="flex items-baseline justify-between gap-2">
|
|
77
|
+
<div className="flex items-baseline gap-1.5 sm:justify-between sm:gap-2">
|
|
78
78
|
<dt className={MICRO}>{label}</dt>
|
|
79
79
|
<dd className={`${NUMERIC} text-xs font-semibold text-foreground`}>{children}</dd>
|
|
80
80
|
</div>
|
|
@@ -94,43 +94,45 @@ function AuthorBlock({
|
|
|
94
94
|
|
|
95
95
|
return (
|
|
96
96
|
<>
|
|
97
|
-
<div aria-hidden="true" className="h-
|
|
97
|
+
<div aria-hidden="true" className="h-8 border-b-2 border-b-secondary bg-primary sm:h-12" />
|
|
98
98
|
|
|
99
|
-
<div className="relative z-10 -mt-
|
|
99
|
+
<div className="relative z-10 -mt-5 flex items-end gap-3 px-4 sm:-mt-7 sm:block">
|
|
100
100
|
<Avatar
|
|
101
101
|
src={author.avatarUrl}
|
|
102
102
|
name={author.username}
|
|
103
103
|
size={52}
|
|
104
|
-
className="rounded-sm border-2 border-card"
|
|
104
|
+
className="shrink-0 rounded-sm border-2 border-card bg-card"
|
|
105
105
|
/>
|
|
106
106
|
|
|
107
|
-
<
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
{groupTags(author.groups, author.title).map((group) => (
|
|
112
|
-
<p key={group.title} className={`${MICRO} mt-0.5 truncate`}>
|
|
113
|
-
<span className={group.nameClass ?? undefined}>{group.title}</span>
|
|
107
|
+
<div className="min-w-0 flex-1 sm:flex-none">
|
|
108
|
+
<p className="truncate sm:mt-1.5">
|
|
109
|
+
<UserRef user={author} className={`${HEADING} text-sm`} />
|
|
114
110
|
</p>
|
|
115
|
-
))}
|
|
116
111
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)}
|
|
112
|
+
{groupTags(author.groups, author.title).map((group) => (
|
|
113
|
+
<p key={group.title} className={`${MICRO} mt-0.5 truncate`}>
|
|
114
|
+
<span className={group.nameClass ?? undefined}>{group.title}</span>
|
|
115
|
+
</p>
|
|
116
|
+
))}
|
|
123
117
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
118
|
+
{author.isOnline && (
|
|
119
|
+
<p className="mt-1 flex items-center gap-1.5 text-xs text-moderation-approved">
|
|
120
|
+
<span aria-hidden="true" className="size-1.5 rounded-full bg-moderation-approved" />
|
|
121
|
+
{c('online')}
|
|
122
|
+
</p>
|
|
123
|
+
)}
|
|
129
124
|
|
|
130
|
-
|
|
125
|
+
{author.badge != null && (
|
|
126
|
+
<p className="mt-2">
|
|
127
|
+
<GroupBadge badge={author.badge} />
|
|
128
|
+
</p>
|
|
129
|
+
)}
|
|
130
|
+
|
|
131
|
+
{badges}
|
|
132
|
+
</div>
|
|
131
133
|
</div>
|
|
132
134
|
|
|
133
|
-
<dl className="mt-2
|
|
135
|
+
<dl className="mt-2 flex flex-wrap gap-x-4 gap-y-1 border-t border-border px-4 py-2 sm:mt-2.5 sm:block sm:space-y-1 sm:py-2.5">
|
|
134
136
|
<StatLine label={c('posts')}>{author.postCount.label}</StatLine>
|
|
135
137
|
{author.reputation != null && (
|
|
136
138
|
<StatLine label={c('rep')}>{author.reputation.label}</StatLine>
|
package/src/slots/thread-row.tsx
CHANGED
|
@@ -4,7 +4,12 @@ import { Badge } from '@meith/ui'
|
|
|
4
4
|
|
|
5
5
|
import { HEADING, LINK, MICRO, Prefix, ReadMark, Stamp, TABLE_ROW, Tally, UserRef } from '../shared'
|
|
6
6
|
|
|
7
|
-
export function ThreadRow({
|
|
7
|
+
export function ThreadRow({
|
|
8
|
+
thread,
|
|
9
|
+
select,
|
|
10
|
+
regions,
|
|
11
|
+
copy,
|
|
12
|
+
}: ThreadRowSlotModel & { copy: SlotCopy }) {
|
|
8
13
|
const c = (key: string) => fromSlotCopy(copy, `clubhouse.threadRow.${key}`)
|
|
9
14
|
|
|
10
15
|
const hidden = thread.visibility === 'deleted' || thread.visibility === 'unapproved'
|
|
@@ -49,6 +54,7 @@ export function ThreadRow({ thread, select, copy }: ThreadRowSlotModel & { copy:
|
|
|
49
54
|
{thread.title}
|
|
50
55
|
</a>
|
|
51
56
|
{thread.isUnread && <span className="sr-only"> {c('newPosts')}</span>}
|
|
57
|
+
{regions?.pluginBadges}
|
|
52
58
|
</div>
|
|
53
59
|
|
|
54
60
|
<p className="mt-0.5 text-xs text-muted-foreground">
|
|
@@ -9,6 +9,7 @@ export function ThreadView({
|
|
|
9
9
|
forum,
|
|
10
10
|
replyHref,
|
|
11
11
|
markReadAction,
|
|
12
|
+
watch,
|
|
12
13
|
regions,
|
|
13
14
|
copy,
|
|
14
15
|
}: ThreadViewModel & { copy: SlotCopy }) {
|
|
@@ -19,6 +20,25 @@ export function ThreadView({
|
|
|
19
20
|
<PageHead
|
|
20
21
|
actions={
|
|
21
22
|
<>
|
|
23
|
+
{watch != null && (
|
|
24
|
+
<form action={watch.action} method="post">
|
|
25
|
+
<button
|
|
26
|
+
type="submit"
|
|
27
|
+
className={cn(
|
|
28
|
+
BUTTON,
|
|
29
|
+
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
30
|
+
)}
|
|
31
|
+
>
|
|
32
|
+
{watch.subscribed ? (
|
|
33
|
+
<>
|
|
34
|
+
{c('watching')} <span aria-hidden="true">✓</span>
|
|
35
|
+
</>
|
|
36
|
+
) : (
|
|
37
|
+
c('watch')
|
|
38
|
+
)}
|
|
39
|
+
</button>
|
|
40
|
+
</form>
|
|
41
|
+
)}
|
|
22
42
|
{markReadAction !== null && (
|
|
23
43
|
<form action={markReadAction} method="post">
|
|
24
44
|
<button
|
package/src/theme.ts
CHANGED