* fix(frontend): no_footer scrollbar regression introduced in v1.16.0
Two unrelated changes in v1.16.0 combined to surface a scrollbar in
no_footer=true mode:
1. c26f45e5 removed the deprecated `scrolling="no"` iframe attribute
on the grounds that "overflow is already hidden via CSS". That CSS
(`overflow: hidden` in createIframe styles) is on the iframe ELEMENT
in the parent page; it has no effect on the iframe DOCUMENT's own
scrollbars. The spec-correct replacement is `overflow: hidden` on
the iframe document's body — added here to global.css.
2. The negative `margin-bottom: -24px` on `.thread:last-child` was a
trick to tighten the gap to the footer (combined with the footer's
`margin-top: 48px` it collapsed to a 24px net gap). With no_footer
the negative margin had no positive-margin sibling to collapse
against and instead propagated up through .root, leaving body
~24px shorter than the visual content. The iframe height calc
(`body.offsetHeight + 12`) then sized the iframe below the visible
bottom of the last thread → scrollbar.
Replace the negative-margin trick with a straight `margin-top: 24px`
on `.copyright`. Same 24px visual gap when the footer is shown, no
propagation when it isn't. The mix={styles.thread} on Thread becomes
a dead reference and is dropped.
Closes#2073
* fix(frontend): drop dead Thread.mix prop after root.tsx removed its only caller
Both Copilot and umputun flagged this in PR review: after the parent
commit on this branch dropped `mix={styles.thread}` from root.tsx, the
`mix?: string` prop and the corresponding entry in the clsx() call in
thread.tsx are dead code — no caller passes it (the recursive Thread
render in thread.tsx:82 never did either). Remove the prop, the
destructure, and the clsx entry.
* Probe /auth/status from frontend to avoid 401 console noise on /user
GET /api/v1/user requires auth and returns 401 for anonymous visitors,
which the browser logs to console even when JS catches it. Probe
/auth/status first (always 200), then fetch /user only when logged in.
Stale auth cookies are cleared when status reports "not logged in" to
preserve the cleanup-on-probe behaviour previously triggered by /user 401.
Closes#1188.
* Don't clear auth cookies when /auth/status probe itself fails
A transient network/5xx on the /auth/status probe used to fall through
into the cookie-clear branch and silently log the user out on the next
page load. Distinguish "probe failed" (null) from explicit "not logged
in"; only the latter clears JWT/XSRF cookies. Lock the distinction with
a negative assertion in the probe-failure test.
Also align packages/api prettier config with apps/remark42 (trailingComma: 'es5')
so future edits don't sweep unrelated trailing commas into the diff.
* fix(embed): set color-scheme on iframe to fix Firefox dark mode
Firefox renders a white background in dark mode when color-scheme is 'none' on the iframe. Set color-scheme to match the active theme on both the outer iframe element and the inner document root, so Firefox uses the correct rendering mode from the start and on theme changes.
* fix(embed): default iframe color-scheme to light when no theme set
Changes the fallback from 'light dark' to 'light' to match the inner document's default behavior, which always defaults to light when no theme is specified.
The edit textarea was running `data.orig` through the browser's HTML
parser via a detached `<span>.innerHTML` to "decode entities", which
turned user-typed `<`/`>` into real `<`/`>`. On save, blackfriday
then saw a real `<script>` tag, bluemonday stripped it, and the comment
body collapsed to an empty string.
The decode block predates commit 243c835 (2022) which stopped the
backend from sanitising `orig` with bluemonday. Before 243c835, orig
came back HTML-escaped from the API and the frontend compensated.
After 243c835 the backend stores and returns orig byte-for-byte, but
the frontend decode was never removed — so it has been silently
corrupting user input containing entities for ~3.5 years.
The backend contract is clear: `orig` is the raw user input, never
rendered as HTML. The frontend should echo it back into the textarea
unchanged. This change removes the decode and adds 45 table-driven
regression tests covering entity round-trips, unicode edge cases,
and markdown constructs.
Consolidate legacy BEM CSS files into CSS Modules for 4 components:
- dropdown/__item: 1 CSS file → dropdown-item.module.css
- list-comments: 1 CSS file → list-comments.module.css (removed unused
comments-list class that had no CSS rules)
- comment-form/__subscribe-by-rss: 1 CSS file → subscribe-by-rss.module.css,
removed dead titleClass prop and dead __rss-link directory
- settings: 10 CSS files → settings.module.css, removed dead
.settings__blocked-users-username CSS rule
Built artefact comparison (master vs branch):
- 83 of 89 files in /srv/web/ are byte-identical (all locale bundles,
SVGs, HTML pages unchanged)
- 6 files differ: remark.css/js/mjs and last-comments.css/js/mjs
- CSS changes are class name hash shifts (e.g. G_A → H_A) caused by
webpack's module ordering, plus 3 new var() fallback values added
by the CSS modules build; all property:value pairs are preserved
- JS changes are minified variable name shifts (O ↔ A, I ↔ L) from
changed import order; no logic changes
- Visual comparison (pixel-by-pixel screenshots of both light and dark
themes on the demo page) shows 0 different pixels
- Bundle sizes: remark.css -626 bytes, remark.js -512 bytes,
last-comments.css -16 bytes (dead CSS removed)
* frontend: remove deprecated iframe attrs and non-standard CSS
Three separate cleanups:
1. remove deprecated HTML attributes from iframe creation (create-iframe.ts)
- frameborder="0": deprecated since HTML5; border is already set to none via CSS
- allowtransparency="true": non-standard Microsoft attribute never in any spec;
transparency is handled by body { background: transparent } in CSS instead
- scrolling="no": deprecated since HTML5; overflow is already hidden via CSS
- horizontalscrolling/verticalscrolling: non-standard IE-era attributes with
no effect in modern browsers; remove without replacement
2. replace allowtransparency with explicit CSS (global.css)
- add background: transparent to body; this is the spec-correct way to make
an iframe document transparent, as documented by MDN
3. drop -moz-touch-enabled media query prefix (5 comment CSS files)
- -moz-touch-enabled was a Firefox-only non-standard media feature removed
in Firefox 58 (2018); pointer: coarse is the standard equivalent and was
already present as the second condition in every query, so removing the
dead -moz prefix reduces the media query to just (pointer: coarse)
note: colorScheme: 'none' in create-iframe.ts is intentionally left unchanged;
it is tracked by #1430 and requires a broader color-scheme implementation
* frontend: fix CSS bugs and replace deprecated properties
Bugs fixed:
- comment-votes.module.css: add missing comma between transition values;
without it the shorthand was invalid and colour transitions on vote
buttons were silently ignored
- icon-button.module.css: fix "transfrom" typo (should be "transform");
the misspelling made the transition declaration a no-op, so the hover
scale animation jumped instantly instead of easing
- auth.module.css: remove doubly-nested rgb(rgb(var(…))) call; the outer
rgb() rejected the inner rgb() result, so the .title element's colour
fell back to inherited instead of the intended --secondary-text-color
Deprecated properties replaced:
- comment-form__markdown-toolbar.css: replace deprecated clip: rect()
with clip-path: inset(50%); clip was deprecated in CSS Masking Level 1
- raw-content.css: replace word-wrap with overflow-wrap; word-wrap was
renamed in CSS Text Level 3, all current browsers support overflow-wrap
- global.css: remove redundant literal-colour fallback lines before
var() declarations in .preloader and .preloader_view_iframe; the var()
calls already have inline fallback values (e.g. var(--color6, #fff)),
making the preceding duplicate property and its stylelint-disable
comment unnecessary since IE11 EOL
* move border:none from inline style to widget__comments-frame class
Remove non-iframe child nodes from the root element once the
iframe signals it has initialised, allowing users to add
loading placeholders that get cleaned up automatically. Fixes#1990
Add admin_edit field to frontend Config types and use it in
comment component to give admins unlimited edit time and allow
editing comments with replies. Hide countdown timer when
editDeadline is Infinity. Fixes#1986
The last step of the data deletion feature–when the admin user visits the link sent by the user requesting to delete their data–was broken due to the deleteme.js script not being loaded.
* 1833 - Toolbar buttons are stuck to the main comment form
* Add readonly and JSDoc to CommentForm textareaId properties
Improve code quality based on review feedback: mark textareaId as
readonly since it should never change after construction, and add
JSDoc to static textareaCounter explaining its purpose.
---------
Co-authored-by: Dmitry Verkhoturov <paskal.07@gmail.com>
- Update Google logo to use gradient version per new brand guidelines
- Replace Twitter bird logo with X logo
- Add light/dark variants for X logo (like Apple and GitHub)
- Update oauth.consts.ts to use new X logo variants
Fixes#1957
With AUTH_SEND_JWT_HEADER=true, frontend now properly handles JWT authentication:
- Store JWT token in client-side cookie named 'JWT'
- Extract and store XSRF token from JWT payload
- Set Secure flag automatically when on HTTPS connection
- Update documentation to clarify this behavior
This fixes an issue where login state would be lost after page reload
when using header-based JWT authentication.