Skip to content

Self-hosted: add a Terminal layout, the Developer aesthetic as a console - #1473

Merged
feruzm merged 2 commits into
developfrom
feature/self-hosted-terminal-theme
Aug 13, 2026
Merged

Self-hosted: add a Terminal layout, the Developer aesthetic as a console#1473
feruzm merged 2 commits into
developfrom
feature/self-hosted-terminal-theme

Conversation

@feruzm

@feruzm feruzm commented Aug 13, 2026

Copy link
Copy Markdown
Member

Closes #1469. Takes the roster to nine templates and five layouts.

Developer was the template whose look implied a structure it did not have: dark and code-friendly, rendering the same cards as everything else. Terminal is that aesthetic as an actual layout.

  • Its own shell: a prompt line (~/username) instead of a masthead, the description as a # comment, filters rendered as --flags with the active one in the accent, and no sidebar.
  • Its own archive: one row per post, dates in a tabular-nums column so they line up (proportional digits make a monospace listing ragged, which is the one thing a listing cannot be), a > prompt mark, the title truncating, read time on the right. No images, no excerpts, no cards. A reader sees thirty titles where a feed shows five.
  • Monospace throughout including headings, since the idiom is a console where everything is one face.

Two decisions worth stating

It ships beside Developer rather than replacing it. Replacing would keep the roster honest and no managed tenant uses Developer today, so the temptation was real. But an unknown template id clamps to the roster default, and independent deployments cannot be surveyed: retiring the id would silently reset someone's self-hosted blog to Medium. The cost of keeping a redundant skin is lower than that.

It carries no sidebar CSS. Gallery needs those rules because it keeps the shared shell and has to collapse the column that shell reserves. TerminalShell renders its own frame with no sidebar in it, so a rule hiding one would match nothing. I wrote them first, then removed them on reading the file back, and the guard test now asserts their absence so nobody adds them back for symmetry.

The shell mounts CreatePostButton itself, which is the standing contract here: the default navigation is what mounts the composer entry, so a shell replacing it and forgetting silently removes the only way an owner writes a post.

Verified by rendering it

Built the app and served the real dist through the published image's nginx, against a real account, with the hostile config: listType: grid (which is also what apply-config-dom falls back to when the key is absent) and dark mode.

viewport archive rows dates aligned sidebar horizontal scroll console
1440px flex listing 20 yes none none clean
390px flex listing 20 yes none none clean

The listing stays a listing under grid, monospace resolves, and the ground is the dark token rather than an inherited one. Rendering also caught a misalignment worth fixing: the shared BlogPage measure left the listing inset from the prompt line above it, so the header and body did not share a left edge. Both now sit at the same 868px.

946 SPA tests and typecheck pass. Roster, editor label, token and card-treatment guards updated for the ninth template, plus a layout guard for the two CSS rules that carry weight.

Developer was the template whose look implied a structure it did not have:
dark and code-friendly, rendering the same cards as everything else.

Terminal is that aesthetic as an actual layout. Its own shell (a prompt line
instead of a masthead, filters as flags, no sidebar) and its own archive: a
dense listing of one row per post, dates in a tabular column, no images and
no cards, so a reader sees thirty titles where a feed shows five.

It ships beside Developer rather than replacing it. An unknown template id
clamps to the roster default, so retiring that id would silently reset an
independent deployment's blog to Medium, and those cannot be surveyed.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 13, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (4)

Grey Divider


Informational

1. Terminal layout test mislocated 📜 Skill insight ⌂ Architecture
Description
The new test file is placed under apps/self-hosted/src/styles/, but the standard requires tests to
live under the corresponding src/specs/ subtree (not co-located with source). This breaks the
mandated test organization and can hinder consistent tooling and discovery.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Similar “move co-located tests into src/specs” suggestions were explicitly rejected in recent PRs.

PR-#1437
PR-#1470
PR-#1441

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires test files to live in the corresponding src/specs/ subtree
rather than being co-located in src/. The PR adds a new test file under
apps/self-hosted/src/styles/, violating that placement requirement.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was added under `apps/self-hosted/src/styles/`, but compliance requires tests to be placed under the corresponding `src/specs/` subdirectory rather than co-located with source.
## Issue Context
This PR introduces `apps/self-hosted/src/styles/terminal-layout.test.ts` as a new test. Per the test placement rule, it should be moved to the `src/specs/` tree (and ideally follow the repo’s test naming convention as well).
## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Test file uses .test.ts 📜 Skill insight ⚙ Maintainability
Description
The newly added test file uses the .test.ts naming pattern, but the standard requires
.spec.ts/.spec.tsx. Nonconforming naming reduces consistency and may bypass configured test
globs.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Repo repeatedly rejected renaming .test.ts to .spec.ts for new tests; likely won’t enforce here.

PR-#1437
PR-#1441
PR-#1442

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test filenames to follow the .spec.ts/.spec.tsx convention.
The PR introduces a new test named terminal-layout.test.ts, which does not match the required
pattern.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test: Skill: add-test: Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was introduced with a `.test.ts` filename, but compliance requires `.spec.ts` (or `.spec.tsx` for React).
## Issue Context
The PR adds `apps/self-hosted/src/styles/terminal-layout.test.ts`. It should be renamed to match the required naming convention.
## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Community header identity wrong ✓ Resolved 🐞 Bug ≡ Correctness
Description
TerminalShell’s prompt logic is a no-op (isCommunityMode doesn’t change output) and it always
derives the prompt/title from instanceConfiguration.username, ignoring community identity/title
data. This can render incorrect branding for community instances and can also duplicate the username
in the header when meta.title is unset.
Code

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[R35-38]

+  // The prompt reads as a path: a community is a directory of many authors,
+  // a blog is one person's home.
+  const prompt = isCommunityMode ? `~/${username}` : `~/${username}`;
+
Relevance

● Weak

Community-mode identity/metadata alignment requests were previously rejected for theme shells;
likely same outcome here.

PR-#1446

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new TerminalShell computes prompt with an isCommunityMode ternary that returns the same
value for both branches and then renders {blogTitle || username} after showing the prompt. In
community mode, the canonical identity is communityId and community display metadata is expected
to come from useCommunityData(), which TerminalShell does not use (unlike other shells such as
JournalShell).

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-54]
apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TerminalShell` currently computes the prompt from `username` with an `isCommunityMode` ternary whose branches are identical, and renders `blogTitle || username` next to that prompt. In community mode, `username` is not the community identity, and other shells use `useCommunityData()` to display `community.title`/`community.name`.
## Issue Context
- In community mode, `useInstanceConfig()` exposes `communityId` as the identity used for data fetching, and community display metadata is available via `useCommunityData()`.
- Terminal’s header should follow the same community-vs-blog title behavior as other shells to avoid incorrect/misleading identity.
## Fix Focus Areas
- apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-68]
- apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
- apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]
## What to change
1. Import and use `useCommunityData()` (and/or `communityId`) in `TerminalShell`.
2. Compute a `displayTitle` similar to other shells:
- `displayTitle = isCommunityMode && community?.title ? community.title : blogTitle || username`
3. Compute a community-appropriate prompt value (and remove the identical ternary). Ensure the prompt value does not force duplication when `displayTitle` falls back to `username`.
- Example approach: make prompt represent the *context* (e.g. `~` for blog home, `~/communities/<communityName>` for community) and keep `displayTitle` for the human-readable name.
4. (Optional) Consider using community “about” text instead of `meta.description` in community mode if that matches other shells’ expectations for the description line.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View low (3)
4. Terminal layout test mislocated 📜 Skill insight ⌂ Architecture
Description
The new test file is placed under apps/self-hosted/src/styles/, but the standard requires tests to
live under the corresponding src/specs/ subtree (not co-located with source). This breaks the
mandated test organization and can hinder consistent tooling and discovery.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Similar “move co-located tests into src/specs” suggestions were explicitly rejected in recent PRs.

PR-#1437
PR-#1470
PR-#1441

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires test files to live in the corresponding src/specs/ subtree
rather than being co-located in src/. The PR adds a new test file under
apps/self-hosted/src/styles/, violating that placement requirement.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was added under `apps/self-hosted/src/styles/`, but compliance requires tests to be placed under the corresponding `src/specs/` subdirectory rather than co-located with source.
## Issue Context
This PR introduces `apps/self-hosted/src/styles/terminal-layout.test.ts` as a new test. Per the test placement rule, it should be moved to the `src/specs/` tree (and ideally follow the repo’s test naming convention as well).
## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Test file uses .test.ts 📜 Skill insight ⚙ Maintainability
Description
The newly added test file uses the .test.ts naming pattern, but the standard requires
.spec.ts/.spec.tsx. Nonconforming naming reduces consistency and may bypass configured test
globs.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Repo repeatedly rejected renaming .test.ts to .spec.ts for new tests; likely won’t enforce here.

PR-#1437
PR-#1441
PR-#1442

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test filenames to follow the .spec.ts/.spec.tsx convention.
The PR introduces a new test named terminal-layout.test.ts, which does not match the required
pattern.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test: Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was introduced with a `.test.ts` filename, but compliance requires `.spec.ts` (or `.spec.tsx` for React).
## Issue Context
The PR adds `apps/self-hosted/src/styles/terminal-layout.test.ts`. It should be renamed to match the required naming convention.
## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Community header identity wrong ✓ Resolved 🐞 Bug ≡ Correctness
Description
TerminalShell’s prompt logic is a no-op (isCommunityMode doesn’t change output) and it always
derives the prompt/title from instanceConfiguration.username, ignoring community identity/title
data. This can render incorrect branding for community instances and can also duplicate the username
in the header when meta.title is unset.
Code

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[R35-38]

+  // The prompt reads as a path: a community is a directory of many authors,
+  // a blog is one person's home.
+  const prompt = isCommunityMode ? `~/${username}` : `~/${username}`;
+
Relevance

● Weak

Community-mode identity/metadata alignment requests were previously rejected for theme shells;
likely same outcome here.

PR-#1446

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new TerminalShell computes prompt with an isCommunityMode ternary that returns the same
value for both branches and then renders {blogTitle || username} after showing the prompt. In
community mode, the canonical identity is communityId and community display metadata is expected
to come from useCommunityData(), which TerminalShell does not use (unlike other shells such as
JournalShell).

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-54]
apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TerminalShell` currently computes the prompt from `username` with an `isCommunityMode` ternary whose branches are identical, and renders `blogTitle || username` next to that prompt. In community mode, `username` is not the community identity, and other shells use `useCommunityData()` to display `community.title`/`community.name`.
## Issue Context
- In community mode, `useInstanceConfig()` exposes `communityId` as the identity used for data fetching, and community display metadata is available via `useCommunityData()`.
- Terminal’s header should follow the same community-vs-blog title behavior as other shells to avoid incorrect/misleading identity.
## Fix Focus Areas
- apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-68]
- apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
- apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]
## What to change
1. Import and use `useCommunityData()` (and/or `communityId`) in `TerminalShell`.
2. Compute a `displayTitle` similar to other shells:
 - `displayTitle = isCommunityMode && community?.title ? community.title : blogTitle || username`
3. Compute a community-appropriate prompt value (and remove the identical ternary). Ensure the prompt value does not force duplication when `displayTitle` falls back to `username`.
 - Example approach: make prompt represent the *context* (e.g. `~` for blog home, `~/communities/<communityName>` for community) and keep `displayTitle` for the human-readable name.
4. (Optional) Consider using community “about” text instead of `meta.description` in community mode if that matches other shells’ expectations for the description line.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@feruzm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ee950c20-aa64-4288-81fa-f3325219274e

📥 Commits

Reviewing files that changed from the base of the PR and between d9a12ae and 600900d.

📒 Files selected for processing (12)
  • apps/self-hosted/hosting/api/src/style-template-display.ts
  • apps/self-hosted/hosting/api/src/style-templates.ts
  • apps/self-hosted/src/core/i18n-strings.ts
  • apps/self-hosted/src/features/floating-menu/config-fields.ts
  • apps/self-hosted/src/styles/terminal-layout.test.ts
  • apps/self-hosted/src/styles/theme-appearance-tokens.test.ts
  • apps/self-hosted/src/styles/themes/index.css
  • apps/self-hosted/src/styles/themes/terminal.css
  • apps/self-hosted/src/themes/registry.test.ts
  • apps/self-hosted/src/themes/registry.ts
  • apps/self-hosted/src/themes/terminal/terminal-archive.tsx
  • apps/self-hosted/src/themes/terminal/terminal-shell.tsx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

qodo-code-review Bot commented Aug 13, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Self-hosted: add Terminal layout theme (console shell + dense archive listing)

✨ Enhancement 🧪 Tests ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Add new "Terminal" style template with monospace tokens and dark console palette.
• Introduce a dedicated shell (prompt header, flag-style filters, no sidebar) and a one-row-per-post
 archive listing.
• Wire Terminal into template rosters/editor labels and add guard tests for tokens and layout CSS
 invariants.
Diagram

graph TD
  A["Style template roster"] --> B["Theme registry"] --> C["Terminal manifest"] --> D["TerminalShell"] --> E["BlogPage"] --> F["TerminalArchive"]
  C --> G["terminal.css"]
  H["Editor labels (i18n + config)"] --> A
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Replace the existing Developer template id with Terminal
  • ➕ Keeps the template roster smaller and avoids two similar aesthetics
  • ➖ Breaking for self-hosted instances that still reference 'developer' (unknown ids clamp to default, potentially changing sites unexpectedly)
  • ➖ Harder to reason about backwards compatibility vs. shipping a new id
2. Implement Terminal as CSS-only (no custom Shell/ArchiveList)
  • ➕ Less React surface area; fewer seams to maintain
  • ➖ Cannot express the prompt header, flag-style filters, and dense archive rows cleanly using only tokens
  • ➖ Higher risk of brittle selector overrides competing with components.css
3. Make Terminal a mode/option under Developer instead of a new template
  • ➕ Avoids adding another template id and editor option
  • ➖ Couples layout behavior to a separate config dimension, increasing UI/config complexity
  • ➖ Harder to enforce invariants (e.g., unsupported options, layout-specific tests) per template

Recommendation: Keep the PR’s approach: ship Terminal as a distinct template id with manifest-level component overrides. It preserves backwards compatibility for existing 'developer' deployments, cleanly expresses a true layout change (Shell + ArchiveList), and limits CSS to tokens plus two rooted layout rules with explicit tests to prevent silent regressions.

Files changed (12) +458 / -5

Enhancement (6) +374 / -0
style-template-display.tsAdd Terminal template display metadata (name/tagline/colors) +11/-0

Add Terminal template display metadata (name/tagline/colors)

• Introduces a new 'terminal' entry in the template display catalog with a console-oriented tagline, dark GitHub-like palette, and monospace heading style.

apps/self-hosted/hosting/api/src/style-template-display.ts

style-templates.tsExtend style template roster with 'terminal' id +1/-0

Extend style template roster with 'terminal' id

• Adds 'terminal' to the frozen 'STYLE_TEMPLATES' list so it becomes a valid 'StyleTemplate' and is available to the system.

apps/self-hosted/hosting/api/src/style-templates.ts

terminal.cssAdd Terminal theme tokens + rooted listing/measure layout rules +157/-0

Add Terminal theme tokens + rooted listing/measure layout rules

• Creates a new theme stylesheet defining full '--theme-*' tokens (monospace typography, light/dark palettes, square/no-elevation effects, transparent card treatment) and two layout rules: widen '.blog-page-measure' only when it contains '.blog-posts-list', and force '.blog-posts-list' to be a flex column.

apps/self-hosted/src/styles/themes/terminal.css

registry.tsRegister Terminal manifest with custom shell and archive components +15/-0

Register Terminal manifest with custom shell and archive components

• Imports Terminal components and adds a 'terminal' manifest defining component overrides, 'showsReadTime: true', and declaring 'sidebar'/'listType' unsupported to keep config toggles explicit rather than silently inert.

apps/self-hosted/src/themes/registry.ts

terminal-archive.tsxImplement Terminal archive as dense, column-aligned listing rows +80/-0

Implement Terminal archive as dense, column-aligned listing rows

• Adds a new ArchiveList implementation using 'ArchiveFrame' but rendering one row per post: date column with 'tabular-nums', a prompt marker, truncated title, and optional read-time on larger viewports.

apps/self-hosted/src/themes/terminal/terminal-archive.tsx

terminal-shell.tsxImplement Terminal shell with prompt header, flag filters, and composer entry +110/-0

Implement Terminal shell with prompt header, flag filters, and composer entry

• Adds a custom Shell that renders a console-like prompt line header (title + '~/user'), description as a '#' comment, filters as '--flags', and mounts 'SearchInput', 'CreatePostButton', and 'UserMenu' without a sidebar.

apps/self-hosted/src/themes/terminal/terminal-shell.tsx

Tests (3) +79 / -5
terminal-layout.test.tsAdd guard tests for Terminal layout CSS invariants +64/-0

Add guard tests for Terminal layout CSS invariants

• Adds Vitest coverage that parses 'terminal.css' to assert (1) archive stays a flex column regardless of 'listType', (2) measure widening is scoped via ':has(.blog-posts-list)', (3) no misleading sidebar rules exist, and (4) selectors are rooted to outrank component CSS.

apps/self-hosted/src/styles/terminal-layout.test.ts

theme-appearance-tokens.test.tsUpdate token-coverage tests for ninth template +4/-4

Update token-coverage tests for ninth template

• Adjusts expectations for accent palette blocks and card-treatment declarations to account for the new Terminal theme file(s).

apps/self-hosted/src/styles/theme-appearance-tokens.test.ts

registry.test.tsAdd registry tests for Terminal component overrides +11/-1

Add registry tests for Terminal component overrides

• Updates the set of layout themes and adds an assertion that Terminal resolves custom 'Shell' and 'ArchiveList' while keeping shared defaults (notably 'PostCard') to preserve search-result rendering behavior.

apps/self-hosted/src/themes/registry.test.ts

Other (3) +5 / -0
i18n-strings.tsAdd editor translation key/label for Terminal template option +3/-0

Add editor translation key/label for Terminal template option

• Extends 'TranslationKey' with the Terminal style-template option key and provides an English label for the configuration panel.

apps/self-hosted/src/core/i18n-strings.ts

config-fields.tsWire Terminal label key into style-template config field mapping +1/-0

Wire Terminal label key into style-template config field mapping

• Adds the 'terminal' entry to 'STYLE_TEMPLATE_LABEL_KEYS', enabling the editor to render the localized option label for the new template.

apps/self-hosted/src/features/floating-menu/config-fields.ts

index.cssImport terminal.css into theme bundle +1/-0

Import terminal.css into theme bundle

• Adds '@import "./terminal.css";' so the Terminal token contract and layout rules ship with the app’s theme CSS.

apps/self-hosted/src/styles/themes/index.css

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce7e88daab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

<span aria-hidden="true" className="text-theme-muted">
{prompt}
</span>{' '}
{blogTitle || username}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the current community title in the Terminal header

When Terminal is used for a community whose on-chain title differs from the stored meta.title (for example, after the community is renamed), this renders the stale configured title or the account name. The shared BlogNavigation and the Journal/Reader shells instead load useCommunityData() and prefer community.title, so selecting Terminal changes the community's visible identity; resolve the display title through the same community-aware path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, fixed at 600900d. The shell now takes communityId from useInstanceConfig() for a community prompt and prefers useCommunityData()'s community.title over the stored meta.title, matching Journal, Reader and the shared navigation. A community renamed on chain now shows its current name here too.

Worth admitting the shape of the original bug: the prompt line read isCommunityMode ? \/${username}` : `/${username}``, a ternary with identical branches. I had clearly intended to differentiate and then did not, which is exactly the kind of thing that reads as deliberate in a diff.

Comment on lines +55 to +57
<time
dateTime={entryData.created}
className="shrink-0 w-[6.5rem] text-xs text-theme-muted tabular-nums"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accommodate owner-configured date formats in listing rows

When an owner selects a longer valid date format such as MMMM d, yyyy, formatDate() returns text wider than this fixed 6.5rem column. Because the <time> has neither truncation nor a no-wrap/dynamic-width strategy, the date wraps or spills toward the prompt and destroys the aligned compact listing; size the column from the configured output or constrain the rendered value safely.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, fixed at 600900d, and the fix leans on the one property this theme guarantees.

The column is now measured rather than assumed: the archive formats every date in the batch, takes the longest, and sets the column to that many ch. ch is exact here because Terminal is monospace throughout, so one character is one advance width. The <time> also carries whitespace-nowrap, so an unusually long value pushes the column instead of folding onto a second line.

Verified by rendering with dateFormat: 'MMMM d, yyyy', the format you named:

  • dates render as August 12, 2026
  • every date cell is exactly 108px wide (one distinct value across the listing)
  • every cell is 16px tall, so nothing wrapped
  • every > prompt mark sits at the same left edge, 406px
  • no horizontal scroll

@qodo-code-review

qodo-code-review Bot commented Aug 13, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (2)

Grey Divider


Informational

1. Terminal layout test mislocated 📜 Skill insight ⌂ Architecture
Description
The new test file is placed under apps/self-hosted/src/styles/, but the standard requires tests to
live under the corresponding src/specs/ subtree (not co-located with source). This breaks the
mandated test organization and can hinder consistent tooling and discovery.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Similar “move co-located tests into src/specs” suggestions were explicitly rejected in recent PRs.

PR-#1437
PR-#1470
PR-#1441

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668281 requires test files to live in the corresponding src/specs/ subtree
rather than being co-located in src/. The PR adds a new test file under
apps/self-hosted/src/styles/, violating that placement requirement.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was added under `apps/self-hosted/src/styles/`, but compliance requires tests to be placed under the corresponding `src/specs/` subdirectory rather than co-located with source.

## Issue Context
This PR introduces `apps/self-hosted/src/styles/terminal-layout.test.ts` as a new test. Per the test placement rule, it should be moved to the `src/specs/` tree (and ideally follow the repo’s test naming convention as well).

## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Test file uses .test.ts 📜 Skill insight ⚙ Maintainability
Description
The newly added test file uses the .test.ts naming pattern, but the standard requires
.spec.ts/.spec.tsx. Nonconforming naming reduces consistency and may bypass configured test
globs.
Code

apps/self-hosted/src/styles/terminal-layout.test.ts[1]

+import { readFileSync } from 'node:fs';
Relevance

● Weak

Repo repeatedly rejected renaming .test.ts to .spec.ts for new tests; likely won’t enforce here.

PR-#1437
PR-#1441
PR-#1442

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668286 requires test filenames to follow the .spec.ts/.spec.tsx convention.
The PR introduces a new test named terminal-layout.test.ts, which does not match the required
pattern.

apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]
Skill: add-test

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new test file was introduced with a `.test.ts` filename, but compliance requires `.spec.ts` (or `.spec.tsx` for React).

## Issue Context
The PR adds `apps/self-hosted/src/styles/terminal-layout.test.ts`. It should be renamed to match the required naming convention.

## Fix Focus Areas
- apps/self-hosted/src/styles/terminal-layout.test.ts[1-4]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Community header identity wrong ✓ Resolved 🐞 Bug ≡ Correctness
Description
TerminalShell’s prompt logic is a no-op (isCommunityMode doesn’t change output) and it always
derives the prompt/title from instanceConfiguration.username, ignoring community identity/title
data. This can render incorrect branding for community instances and can also duplicate the username
in the header when meta.title is unset.
Code

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[R35-38]

+  // The prompt reads as a path: a community is a directory of many authors,
+  // a blog is one person's home.
+  const prompt = isCommunityMode ? `~/${username}` : `~/${username}`;
+
Relevance

● Weak

Community-mode identity/metadata alignment requests were previously rejected for theme shells;
likely same outcome here.

PR-#1446

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new TerminalShell computes prompt with an isCommunityMode ternary that returns the same
value for both branches and then renders {blogTitle || username} after showing the prompt. In
community mode, the canonical identity is communityId and community display metadata is expected
to come from useCommunityData(), which TerminalShell does not use (unlike other shells such as
JournalShell).

apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-54]
apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TerminalShell` currently computes the prompt from `username` with an `isCommunityMode` ternary whose branches are identical, and renders `blogTitle || username` next to that prompt. In community mode, `username` is not the community identity, and other shells use `useCommunityData()` to display `community.title`/`community.name`.

## Issue Context
- In community mode, `useInstanceConfig()` exposes `communityId` as the identity used for data fetching, and community display metadata is available via `useCommunityData()`.
- Terminal’s header should follow the same community-vs-blog title behavior as other shells to avoid incorrect/misleading identity.

## Fix Focus Areas
- apps/self-hosted/src/themes/terminal/terminal-shell.tsx[21-68]
- apps/self-hosted/src/features/blog/hooks/use-instance-config.ts[8-44]
- apps/self-hosted/src/themes/journal/journal-shell.tsx[19-39]

## What to change
1. Import and use `useCommunityData()` (and/or `communityId`) in `TerminalShell`.
2. Compute a `displayTitle` similar to other shells:
  - `displayTitle = isCommunityMode && community?.title ? community.title : blogTitle || username`
3. Compute a community-appropriate prompt value (and remove the identical ternary). Ensure the prompt value does not force duplication when `displayTitle` falls back to `username`.
  - Example approach: make prompt represent the *context* (e.g. `~` for blog home, `~/communities/<communityName>` for community) and keep `displayTitle` for the human-readable name.
4. (Optional) Consider using community “about” text instead of `meta.description` in community mode if that matches other shells’ expectations for the description line.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 75 rules
✅ Skills: 6 invoked
  add-feature
  add-query
  add-sdk-mutation
  add-test
  code-review
  debug
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 16/18, lines 463/200; both must reach the floor). Router rationale: This adds a new runtime theme across registry, shell, archive rendering, CSS tokens, routing/config integration, and responsive behavior, creating many independent logic paths with subtle compatibility and accessibility risks.

Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@feruzm

feruzm commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Both P2s are fixed at 600900d (replies on the threads). The two Qodo skill insights I am refuting, with evidence.

"Test file mislocated, should be under src/specs/" and "should use .spec.ts, not .test.ts": those are the conventions of apps/web, not this app. In apps/self-hosted:

vitest.config.ts:38   include: ['src/**/*.test.ts']
count
.test.ts files in apps/self-hosted/src 72
.spec.* files 0
src/specs/ directory does not exist

Every existing test here is co-located and named .test.ts, including the ones this PR extends (themes/registry.test.ts, styles/theme-appearance-tokens.test.ts, styles/style-template-roster.test.ts). Following the suggestion would be actively harmful rather than merely inconsistent: the vitest include pattern is src/**/*.test.ts, so renaming the file to .spec.ts or moving it to a src/specs/ tree that does not exist would mean the test silently stops running. A guard that no longer runs is worse than no guard, because the PR still looks covered.

The CLAUDE.md section those rules come from is headed "Main App (Vitest)" and describes apps/web/vitest.config.ts, whose pattern genuinely is src/specs/**/*.spec.tsx. The two apps have different conventions on purpose.

@feruzm
feruzm merged commit df47c67 into develop Aug 13, 2026
12 checks passed
@feruzm
feruzm deleted the feature/self-hosted-terminal-theme branch August 13, 2026 11:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Self-hosted: turn the Developer aesthetic into a Terminal layout

1 participant