@meith/theme-midnight 0.15.0 → 0.16.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meith/theme-midnight",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "A dark theme for Meith, built on the default theme's slots.",
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-default": "^0.15.0",
24
- "@meith/theme-kit": "^0.15.0"
23
+ "@meith/theme-default": "^0.16.0",
24
+ "@meith/theme-kit": "^0.16.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "react": "^19.2.0"
package/src/copy.ts CHANGED
@@ -114,6 +114,7 @@ export function postActionsCopy(t: Translator): SlotCopy {
114
114
  'midnight.postActions.ariaLabel',
115
115
  'midnight.postActions.quote',
116
116
  'midnight.postActions.edit',
117
+ 'midnight.postActions.history',
117
118
  'midnight.postActions.restore',
118
119
  'midnight.postActions.rate',
119
120
  'midnight.postActions.report',
@@ -49,6 +49,7 @@
49
49
  "midnight.pagination.prev": "prev",
50
50
  "midnight.postActions.ariaLabel": "Post actions",
51
51
  "midnight.postActions.edit": "edit",
52
+ "midnight.postActions.history": "history",
52
53
  "midnight.postActions.moderate": "moderate",
53
54
  "midnight.postActions.quote": "quote",
54
55
  "midnight.postActions.rate": "rate",
@@ -53,9 +53,11 @@ export function Header({
53
53
  }: HeaderModel & { copy: SlotCopy }) {
54
54
  const c = (key: string) => fromSlotCopy(copy, `midnight.header.${key}`)
55
55
 
56
+ const opensMenus = navigation.some((item) => item.submenu !== undefined)
57
+
56
58
  return (
57
59
  <header>
58
- <div className="flex flex-wrap items-baseline justify-between gap-3 border-b border-border bg-secondary px-4 py-3">
60
+ <div className="flex flex-wrap items-baseline justify-between gap-3 border-b border-border bg-secondary px-4 py-3 sm:px-6">
59
61
  <a
60
62
  href={homeHref}
61
63
  className="inline-flex items-center font-mono text-xl font-semibold tracking-tight text-foreground hover:text-primary"
@@ -66,19 +68,27 @@ export function Header({
66
68
  </div>
67
69
 
68
70
  {navigation.length > 0 && (
69
- <nav aria-label={c('sectionsLabel')} className="flex flex-wrap border-b border-border">
70
- {navigation.map((item) => (
71
- <span key={item.href} className="group relative">
72
- <a
73
- href={item.href}
74
- {...linkTarget(item)}
75
- className="block border-r border-border px-3 py-1.5 font-mono text-xs uppercase tracking-wide text-muted-foreground hover:bg-muted hover:text-foreground"
76
- >
77
- {item.label}
78
- </a>
79
- <Submenu items={item.submenu} />
80
- </span>
81
- ))}
71
+ <nav aria-label={c('sectionsLabel')} className="border-b border-border">
72
+ <div
73
+ className={`-mx-4 flex px-4 sm:-mx-6 sm:px-6 ${
74
+ opensMenus
75
+ ? 'flex-wrap'
76
+ : 'overflow-x-auto [mask-image:linear-gradient(to_right,black_calc(100%-1.5rem),transparent)] sm:[mask-image:none]'
77
+ }`}
78
+ >
79
+ {navigation.map((item) => (
80
+ <span key={item.href} className="group relative shrink-0">
81
+ <a
82
+ href={item.href}
83
+ {...linkTarget(item)}
84
+ className="block border-r border-border px-3 py-1.5 font-mono text-xs uppercase tracking-wide text-muted-foreground hover:bg-muted hover:text-foreground"
85
+ >
86
+ {item.label}
87
+ </a>
88
+ <Submenu items={item.submenu} />
89
+ </span>
90
+ ))}
91
+ </div>
82
92
  </nav>
83
93
  )}
84
94
  </header>
@@ -6,14 +6,17 @@ export function Navigation({ items, copy }: NavigationModel & { copy: SlotCopy }
6
6
 
7
7
  return (
8
8
  <nav aria-label={c('breadcrumbLabel')} className="border-b border-border bg-muted px-4 py-1.5">
9
- <ol className="flex flex-wrap items-center gap-1 font-mono text-xs text-muted-foreground">
9
+ <ol className="flex items-center gap-1 overflow-x-auto font-mono text-xs whitespace-nowrap text-muted-foreground">
10
10
  {items.map((item, index) => {
11
11
  const isLast = index === items.length - 1
12
12
  return (
13
- <li key={item.href} className="flex items-center gap-1">
13
+ <li key={item.href} className="flex shrink-0 items-center gap-1">
14
14
  {index > 0 && <span aria-hidden="true">/</span>}
15
15
  {isLast ? (
16
- <span aria-current="page" className="text-foreground">
16
+ <span
17
+ aria-current="page"
18
+ className="max-w-[24ch] truncate text-foreground sm:max-w-none"
19
+ >
17
20
  {item.label}
18
21
  </span>
19
22
  ) : (
@@ -11,12 +11,13 @@ export function PostActions({
11
11
  const items = [
12
12
  { href: actions.quoteHref, label: c('quote') },
13
13
  { href: actions.editHref, label: c('edit') },
14
+ { href: actions.historyHref, label: c('history') },
14
15
  { href: actions.restoreHref, label: c('restore') },
15
16
  { href: actions.rateHref, label: c('rate') },
16
17
  { href: actions.reportHref, label: c('report') },
17
18
  { href: actions.warnHref, label: c('warn') },
18
19
  { href: actions.moderateHref, label: c('moderate') },
19
- ].filter((item): item is { href: string; label: string } => item.href !== null)
20
+ ].filter((item): item is { href: string; label: string } => item.href != null)
20
21
 
21
22
  if (items.length === 0 && children === undefined) return null
22
23
 
@@ -54,78 +54,89 @@ export function PostBit({ post, select, regions, copy }: PostBitSlotModel & { co
54
54
 
55
55
  <div className="grid grid-cols-1 sm:grid-cols-[11rem_1fr]">
56
56
  <div className="border-b border-border bg-secondary px-3 py-2 sm:border-b-0 sm:border-r">
57
- <p className="flex items-center gap-2">
58
- {select !== null && (
59
- <label className="flex items-center">
60
- <span className="sr-only">{select.label}</span>
61
- <input
62
- type="checkbox"
63
- name={select.name}
64
- value={select.value}
65
- form={select.formId}
66
- className="size-3.5"
67
- />
68
- </label>
69
- )}
70
- <UserRef
71
- user={post.author}
72
- className={
73
- post.author.profileHref === null ? 'font-medium' : 'font-medium hover:text-primary'
74
- }
75
- />
76
- </p>
77
-
78
- {regions.pluginBadges}
79
-
80
- {post.author.badge != null && (
81
- <p className="mt-1">
82
- <GroupBadge badge={post.author.badge} />
83
- </p>
84
- )}
85
- {post.author.title !== null && (
86
- <p className="font-mono text-xs text-muted-foreground">{post.author.title}</p>
87
- )}
88
- {post.author.avatarUrl !== null && (
89
- <img
90
- src={post.author.avatarUrl}
91
- alt=""
92
- width={64}
93
- height={64}
94
- className="mt-2 size-16 border border-border object-cover"
95
- />
96
- )}
97
- <dl className="mt-2 font-mono text-xs text-muted-foreground">
98
- <div className="flex gap-1">
99
- <dt>{c('posts')}</dt>
100
- <dd className="text-foreground">{post.author.postCount.label}</dd>
101
- </div>
102
- {post.author.joinedAt !== null && (
103
- <div className="flex gap-1">
104
- <dt>{c('joined')}</dt>
105
- <dd>
106
- <time dateTime={post.author.joinedAt.iso}>{post.author.joinedAt.label}</time>
107
- </dd>
108
- </div>
109
- )}
110
- {post.author.reputation != null && (
111
- <div className="flex gap-1">
112
- <dt>{c('rep')}</dt>
113
- <dd className="text-foreground">{post.author.reputation.label}</dd>
114
- </div>
57
+ <div className="flex items-start gap-3 sm:flex-col sm:items-center sm:gap-2 sm:text-center">
58
+ {post.author.avatarUrl !== null && (
59
+ <img
60
+ src={post.author.avatarUrl}
61
+ alt=""
62
+ width={48}
63
+ height={48}
64
+ className="size-12 shrink-0 border border-border object-cover sm:size-16"
65
+ />
115
66
  )}
116
- {post.author.isOnline && <div className="text-forum-unread">{c('online')}</div>}
117
- </dl>
118
-
119
- {post.author.fields.length > 0 && (
120
- <dl className="mt-2 font-mono text-xs text-muted-foreground">
121
- {post.author.fields.map((field) => (
122
- <div key={field.label} className="flex gap-1">
123
- <dt>{field.label}</dt>
124
- <dd className="text-foreground">{field.value}</dd>
67
+
68
+ <div className="min-w-0 flex-1 sm:flex-none">
69
+ <p className="flex items-center gap-2 sm:justify-center">
70
+ {select !== null && (
71
+ <label className="flex items-center">
72
+ <span className="sr-only">{select.label}</span>
73
+ <input
74
+ type="checkbox"
75
+ name={select.name}
76
+ value={select.value}
77
+ form={select.formId}
78
+ className="size-3.5"
79
+ />
80
+ </label>
81
+ )}
82
+ <UserRef
83
+ user={post.author}
84
+ className={
85
+ post.author.profileHref === null
86
+ ? 'font-medium'
87
+ : 'font-medium hover:text-primary'
88
+ }
89
+ />
90
+ </p>
91
+
92
+ {regions.pluginBadges}
93
+
94
+ {post.author.badge != null && (
95
+ <p className="mt-1 flex sm:justify-center">
96
+ <GroupBadge badge={post.author.badge} />
97
+ </p>
98
+ )}
99
+ {post.author.title !== null && (
100
+ <p className="truncate font-mono text-xs text-muted-foreground">
101
+ {post.author.title}
102
+ </p>
103
+ )}
104
+ <dl className="mt-2 font-mono text-xs text-muted-foreground">
105
+ <div className="flex gap-1 sm:justify-center">
106
+ <dt>{c('posts')}</dt>
107
+ <dd className="text-foreground">{post.author.postCount.label}</dd>
125
108
  </div>
126
- ))}
127
- </dl>
128
- )}
109
+ {post.author.joinedAt !== null && (
110
+ <div className="flex gap-1 sm:justify-center">
111
+ <dt>{c('joined')}</dt>
112
+ <dd>
113
+ <time dateTime={post.author.joinedAt.iso}>{post.author.joinedAt.label}</time>
114
+ </dd>
115
+ </div>
116
+ )}
117
+ {post.author.reputation != null && (
118
+ <div className="flex gap-1 sm:justify-center">
119
+ <dt>{c('rep')}</dt>
120
+ <dd className="text-foreground">{post.author.reputation.label}</dd>
121
+ </div>
122
+ )}
123
+ {post.author.isOnline && (
124
+ <div className="text-forum-unread sm:text-center">{c('online')}</div>
125
+ )}
126
+ </dl>
127
+
128
+ {post.author.fields.length > 0 && (
129
+ <dl className="mt-2 font-mono text-xs text-muted-foreground">
130
+ {post.author.fields.map((field) => (
131
+ <div key={field.label} className="flex gap-1 sm:justify-center">
132
+ <dt>{field.label}</dt>
133
+ <dd className="text-foreground">{field.value}</dd>
134
+ </div>
135
+ ))}
136
+ </dl>
137
+ )}
138
+ </div>
139
+ </div>
129
140
  </div>
130
141
 
131
142
  <div className="min-w-0">