g-comments 0.1.0 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -6,6 +6,33 @@ All notable changes to `g-comments` are listed here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.2.1] - 2026-10-20
10
+
11
+ ### Changed
12
+
13
+ - The default stylesheet lives in the `gc-defaults` cascade layer and a forum
14
+ theme's CSS is imported into `gc-forum`, so site CSS beats the forum's and the
15
+ forum's beats the defaults regardless of load order or specificity. The forum
16
+ stylesheet is no longer a `<link>`: it is an `@import … layer(gc-forum)` in
17
+ the installed `<style>`.
18
+
19
+ ## [0.2.0] - 2026-10-20
20
+
21
+ ### Added
22
+
23
+ - `theme="forum"` (provider, `<Comments>`, `<discourse-comments>`): applies the
24
+ forum's own palettes, fonts and "Embedded CSS" to the widget, from the
25
+ plugin's `GET /comments/theme`. Forum colours are exposed as
26
+ `--gc-forum-<name>`; tokens you set still win.
27
+ - `client.theme()` and `useForumTheme()` return the same data for sites that
28
+ style their own UI after the forum.
29
+
30
+ ### Changed
31
+
32
+ - The custom elements attach their default styles as `<style>` elements
33
+ instead of constructed stylesheets, so a stylesheet added to the shadow root
34
+ later (such as the forum's) wins ties.
35
+
9
36
  ## [0.1.0] - Unreleased
10
37
 
11
38
  First release, against the `discourse-comments` forum plugin.
package/README.md CHANGED
@@ -28,7 +28,7 @@ import "g-comments/styles.css";
28
28
  // Once, near the root of the app.
29
29
  <DiscourseComments
30
30
  forum="https://forum.example.com"
31
- theme="auto" // "light" | "dark" | "auto" (prefers-color-scheme) | "inherit"
31
+ theme="auto" // "light" | "dark" | "auto" (prefers-color-scheme) | "inherit" | "forum"
32
32
  locale="en" // "pt-BR" is bundled too; `messages` overrides single strings
33
33
  appearance={{ variables: { accent: "var(--brand)", radius: "0" } }}
34
34
  onEvent={(event) => analytics.track(event.type, event)}
@@ -134,9 +134,9 @@ depth, and `Item` keeps the inline reply, edit, report and delete panels.
134
134
  (`.gc-root.gc-root--styled`); nothing outside it is touched. Class names follow
135
135
  BEM (`gc-comment`, `gc-comment__body`, `gc-composer--replying`,
136
136
  `gc-button--primary`, …) and stay in place with `unstyled`, which only drops
137
- `gc-root--styled`. Selectors carry one class of specificity, so your own class
138
- rules win when loaded after the stylesheet. Cooked comment HTML is wrapped in
139
- `.gc-prose`.
137
+ `gc-root--styled`. The rules live in the `gc-defaults` cascade layer, so your
138
+ own (unlayered) CSS wins whatever its order or specificity. Cooked comment HTML
139
+ is wrapped in `.gc-prose`.
140
140
 
141
141
  `appearance.elements` adds class names: `root`, `header`, `count`, `sort`,
142
142
  `signIn`, `composer`, `textarea`, `toolbar`, `list`, `comment`, `avatar`,
@@ -166,7 +166,41 @@ colour scheme.
166
166
  `theme` sets `data-gc-theme` on the root: `light`, `dark`, or `auto`, which
167
167
  switches with `prefers-color-scheme`. `inherit` sets nothing and derives the
168
168
  neutral colours from the page's text colour, for sites that theme the widget
169
- themselves. The layout works down to 320px wide.
169
+ themselves. `forum` applies the forum's own look (below). The layout works
170
+ down to 320px wide.
171
+
172
+ ### Use the forum's look
173
+
174
+ ```tsx
175
+ <DiscourseComments forum="https://forum.example.com" theme="forum">
176
+ ```
177
+
178
+ `theme="forum"` loads the forum's theme once per forum (`GET /comments/theme`)
179
+ and installs it where the widget lives: the page's `<head>`, or the custom
180
+ element's shadow root. Three things arrive:
181
+
182
+ - **Colours.** Every custom property the forum's colour definitions emit is
183
+ available on the widget root as `--gc-forum-<name>` (`--gc-forum-primary`,
184
+ `--gc-forum-tertiary`, `--gc-forum-primary-low`, …), and the widget tokens
185
+ default to them: `fg` ← `primary`, `fgMuted` ← `primary-medium`, `bg` ←
186
+ `secondary`, `bgSubtle` ← `primary-very-low`, `border` ← `primary-low`,
187
+ `accent` ← `tertiary`, `accentFg` ← `secondary`, `danger` ← `danger`. When
188
+ the theme has a dark palette it applies under `prefers-color-scheme: dark`.
189
+ - **Fonts.** `--gc-font` defaults to the forum's body font;
190
+ `--gc-forum-font-body`, `--gc-forum-font-heading` and
191
+ `--gc-forum-font-monospace` carry the stacks, and `@font-face` rules are
192
+ added to the page for fonts the forum serves.
193
+ - **Theme CSS.** The default theme's "Embedded CSS" (Admin → Customize →
194
+ Themes → Edit CSS/HTML → Embedded) is imported into the `gc-forum` cascade
195
+ layer, so forum admins can style the `gc-*` classes without touching the
196
+ site.
197
+
198
+ Precedence, for tokens and for plain CSS alike: what a component sets
199
+ (`appearance`) beats the site's own CSS and `--gc-*` values, which beat the
200
+ forum's, which beat the defaults. Site CSS is unlayered and the forum's sits in
201
+ `gc-forum` above `gc-defaults`, so no ordering or specificity tricks are
202
+ needed. `useForumTheme()` returns the same data for sites that style their own
203
+ UI after the forum.
170
204
 
171
205
  ## Custom elements (no framework)
172
206
 
@@ -193,7 +227,7 @@ Attributes mirror the React props, in kebab-case:
193
227
  | `identifier`, `url`, `title` | same | thread identity; `url` and `title` default to the page |
194
228
  | `sort` | `sort` | `best`, `hot`, `newest`, `oldest` |
195
229
  | `sign-in` | `signIn` | `inline` (default), `on-submit`, `manual` |
196
- | `theme` | `theme` | `auto` (default), `light`, `dark`, `inherit` |
230
+ | `theme` | `theme` | `auto` (default), `light`, `dark`, `inherit`, `forum` |
197
231
  | `locale` | `locale` | `en`, `pt-BR` |
198
232
  | `max-depth` | `maxDepth` | number, default 2 |
199
233
  | `read-only`, `unstyled`, `debug` | same | boolean: present means true (`"false"` is false) |
@@ -245,8 +279,10 @@ discourse-comments::part(gc-comment--pinned) {
245
279
  ```
246
280
 
247
281
  `unstyled` drops the default stylesheet's effect (the classes and parts stay),
248
- and `theme="inherit"` derives the neutral colours from the page's text colour.
249
- The count element has no styles of its own and inherits the page's font.
282
+ `theme="inherit"` derives the neutral colours from the page's text colour, and
283
+ `theme="forum"` loads the forum's palettes, fonts and theme CSS into the shadow
284
+ root (see "Use the forum's look"). The count element has no styles of its own
285
+ and inherits the page's font.
250
286
 
251
287
  `defineElements({ comments: "my-comments", count: "my-count" })` registers the
252
288
  same elements under other names; names that are already defined are left
@@ -2660,6 +2660,7 @@ function createClientWithInternals(options, internals) {
2660
2660
  const realtime = internals.realtime ?? new MessageBusPoller({ base: forum.base, fetch: http.fetch, log });
2661
2661
  const batcher = new CountsBatcher(http);
2662
2662
  let configGeneration = 0;
2663
+ let themePromise = null;
2663
2664
  let degradedRecheck;
2664
2665
  let degradedChecks = 0;
2665
2666
  function config() {
@@ -2778,6 +2779,16 @@ function createClientWithInternals(options, internals) {
2778
2779
  }
2779
2780
  return http.request("POST", `${threadPath(threadId)}/attachments`, { form });
2780
2781
  }
2782
+ function theme() {
2783
+ if (lifetime.signal.aborted) {
2784
+ return Promise.reject(disposedError());
2785
+ }
2786
+ themePromise ??= http.request("GET", "/theme").catch((error) => {
2787
+ themePromise = null;
2788
+ throw error;
2789
+ });
2790
+ return themePromise;
2791
+ }
2781
2792
  const client = {
2782
2793
  forum: forum.base,
2783
2794
  forumOrigin: forum.origin,
@@ -2786,6 +2797,7 @@ function createClientWithInternals(options, internals) {
2786
2797
  threads: { open },
2787
2798
  attachments: { upload },
2788
2799
  config,
2800
+ theme,
2789
2801
  counts: (refs) => batcher.request(refs),
2790
2802
  count: async (ref) => (await batcher.request([ref]))[encodeRef(ref)] ?? 0,
2791
2803
  preview: async (body) => (await http.request("POST", "/preview", { json: { raw: body } })).html,
@@ -3073,5 +3085,5 @@ exports.memoryStorage = memoryStorage;
3073
3085
  exports.normalizeForum = normalizeForum;
3074
3086
  exports.ptBR = ptBR;
3075
3087
  exports.resolveLocale = resolveLocale;
3076
- //# sourceMappingURL=chunk-X6RAR374.cjs.map
3077
- //# sourceMappingURL=chunk-X6RAR374.cjs.map
3088
+ //# sourceMappingURL=chunk-IBNNENCZ.cjs.map
3089
+ //# sourceMappingURL=chunk-IBNNENCZ.cjs.map