Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/web/src/appSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ const AppSettingsSchema = Schema.Struct({
Option.some([] as ReadonlyArray<{ label: string; value: string }>),
),
),
backgroundColorOverride: Schema.String.check(Schema.isMaxLength(16)).pipe(
Schema.withConstructorDefault(() => Option.some("")),
),
foregroundColorOverride: Schema.String.check(Schema.isMaxLength(16)).pipe(
Schema.withConstructorDefault(() => Option.some("")),
),
uiFont: Schema.String.check(Schema.isMaxLength(256)).pipe(
Schema.withConstructorDefault(() => Option.some("")),
),
codeFont: Schema.String.check(Schema.isMaxLength(256)).pipe(
Schema.withConstructorDefault(() => Option.some("")),
),
uiFontSize: Schema.Number.pipe(Schema.withConstructorDefault(() => Option.some(0))),
codeFontSize: Schema.Number.pipe(Schema.withConstructorDefault(() => Option.some(0))),
contrast: Schema.Number.pipe(Schema.withConstructorDefault(() => Option.some(0))),
translucency: Schema.Boolean.pipe(Schema.withConstructorDefault(() => Option.some(false))),
});
export type AppSettings = typeof AppSettingsSchema.Type;
export interface AppModelOption {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/ui/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ function Sidebar({
{...props}
>
<div
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm/5"
className="sidebar-translucent flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm/5"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify selector scoping for translucent sidebar styles.
# Expected: `.sidebar-translucent` visual rules should be gated by `.theme-translucent` (or equivalent root state).

rg -n -C3 'theme-translucent|sidebar-translucent' --type=css --type=scss --type=ts --type=tsx

Repository: aaditagrawal/t3code

Length of output: 91


🏁 Script executed:

#!/bin/bash
# Search for theme-translucent and sidebar-translucent patterns
# Try without --type=scss since rg doesn't recognize it

# First, find what CSS/style files exist
fd -e css -e scss -e less | head -20

# Then search for the patterns in source files
rg -n 'theme-translucent|sidebar-translucent' --type=css --type=ts --type=tsx 2>/dev/null || \
rg -n 'theme-translucent|sidebar-translucent' 2>/dev/null

Repository: aaditagrawal/t3code

Length of output: 579


🏁 Script executed:

#!/bin/bash
# Check size of index.css and read relevant sections
wc -l apps/web/src/index.css

# Search for sidebar-translucent CSS rules with context
rg -n -B2 -A5 'sidebar-translucent' apps/web/src/index.css

Repository: aaditagrawal/t3code

Length of output: 89


🏁 Script executed:

#!/bin/bash
# sidebar-translucent not found in index.css with pattern search
# Let's check if it's defined in Tailwind config or as a CSS layer

# Search for tailwind config files
fd -e config -e ts -e js | grep -i tailwind

# Search for sidebar-translucent in all files (not just CSS)
rg -l 'sidebar-translucent'

# Check if there's a `@layer` directive in index.css
rg -n '@layer|theme-translucent' apps/web/src/index.css

Repository: aaditagrawal/t3code

Length of output: 118


🏁 Script executed:

#!/bin/bash
# sidebar-translucent is in sidebar.tsx only - check if it's defined there via `@layer`
# Read the sidebar.tsx file to see the `@layer` definition

cat -n apps/web/src/components/ui/sidebar.tsx | head -100

Repository: aaditagrawal/t3code

Length of output: 3684


🏁 Script executed:

#!/bin/bash
# Read the `@layer` definition section starting at line 47
cat -n apps/web/src/components/ui/sidebar.tsx | sed -n '47,120p'

Repository: aaditagrawal/t3code

Length of output: 2682


🏁 Script executed:

#!/bin/bash
# Search more broadly for `@layer` in sidebar.tsx
rg -n '@layer' apps/web/src/components/ui/sidebar.tsx

# Also get context around the `@layer` definition
rg -n -A30 '@layer base' apps/web/src/components/ui/sidebar.tsx

Repository: aaditagrawal/t3code

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Let's search for sidebar-translucent more thoroughly
# It might be in a CSS file or defined via Tailwind `@apply`

rg -n 'sidebar-translucent' --type-list

# Search in all files including CSS
rg -rn 'sidebar-translucent' apps/web/src/

# Check the entire sidebar.tsx file length
wc -l apps/web/src/components/ui/sidebar.tsx

# Look for CSS/Tailwind definitions with broader search
rg -n 'sidebar' apps/web/src/index.css | head -20

Repository: aaditagrawal/t3code

Length of output: 788


🏁 Script executed:

#!/bin/bash
# The file is 992 lines - read the section around line 291 where sidebar-translucent is used
cat -n apps/web/src/components/ui/sidebar.tsx | sed -n '285,310p'

# Also search for any `@layer` directives in the entire file
rg -n '@layer' apps/web/src/components/ui/sidebar.tsx

Repository: aaditagrawal/t3code

Length of output: 1101


🏁 Script executed:

#!/bin/bash
# sidebar-translucent is applied but not defined via `@layer`
# Check if it's a Tailwind utility class by looking at tailwind config

fd -e config.ts -e tailwind.config.ts -e tailwind.config.js

# Also read the entire index.css to see all CSS definitions
cat apps/web/src/index.css | head -200

Repository: aaditagrawal/t3code

Length of output: 6624


🏁 Script executed:

#!/bin/bash
# sidebar-translucent appears in markup but has no CSS definition
# Let's search for any reference to translucent (without sidebar prefix)
rg -n 'translucent' apps/web/src/

# Check if there's a tailwind.config file
fd tailwind.config

# Also check index.css for the complete file length and look for any dynamic class generation
tail -100 apps/web/src/index.css

Repository: aaditagrawal/t3code

Length of output: 2840


🏁 Script executed:

#!/bin/bash
# sidebar-translucent has no CSS definition in index.css
# Check if it's a Tailwind utility defined in config

cat apps/web/src/index.css | grep -n 'sidebar'

# Look for tailwind.config or theme definitions
fd -type f \( -name "tailwind.config*" -o -name "*.config.ts" \) | xargs grep -l 'sidebar-translucent' 2>/dev/null || echo "No tailwind config found with sidebar-translucent"

# Also check if there's a CSS-in-JS or other styling approach
rg -n 'sidebar-translucent' --type-list 2>/dev/null || rg -rn 'sidebar-translucent' apps/web/

Repository: aaditagrawal/t3code

Length of output: 576


🏁 Script executed:

#!/bin/bash
# sidebar-translucent class exists in markup but has no CSS definition
# Let's check the themeConfig to understand the theme-translucent mechanism better

cat -n apps/web/src/themeConfig.ts | sed -n '90,110p'

# Also search for any CSS that uses theme-translucent selector
rg -n 'theme-translucent' apps/web/src/index.css

# Check if sidebar-translucent might be a planned/TODO style
rg -n 'sidebar' apps/web/src/index.css

Repository: aaditagrawal/t3code

Length of output: 557


Add CSS rules for sidebar-translucent gated by .theme-translucent.

The sidebar-translucent class is applied unconditionally in line 291, but has no CSS definition. When styling is added, it must be scoped so translucency only applies when the root element has the theme-translucent class (set conditionally in themeConfig.ts based on settings.translucency).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/components/ui/sidebar.tsx` at line 291, The JSX applies the
class "sidebar-translucent" unconditionally but no CSS exists and translucency
must be enabled only when the root has "theme-translucent"; add stylesheet rules
scoped under ".theme-translucent .sidebar-translucent" (not a global
.sidebar-translucent) to define the required translucent background, borders,
and backdrop-filter styles so the sidebar becomes translucent only when the
theme toggled by themeConfig.ts (via settings.translucency) adds
"theme-translucent" to the root; update the relevant CSS/SCSS file where other
sidebar styles live to include these scoped rules (reference: className using
"sidebar-translucent" in the Sidebar component and the theme toggle logic in
themeConfig.ts).

data-sidebar="sidebar"
data-slot="sidebar-inner"
>
Expand Down
5 changes: 4 additions & 1 deletion apps/web/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import { getRouter } from "./router";
import { APP_DISPLAY_NAME } from "./branding";
import { getAppSettingsSnapshot } from "./appSettings";
import { applyAccentColorToDocument } from "./accentColor";
import { applyThemeConfigToDocument } from "./themeConfig";

// Electron loads the app from a file-backed shell, so hash history avoids path resolution issues.
const history = isElectron ? createHashHistory() : createBrowserHistory();

const router = getRouter(history);

document.title = APP_DISPLAY_NAME;
applyAccentColorToDocument(getAppSettingsSnapshot().accentColor);
const initialSettings = getAppSettingsSnapshot();
applyAccentColorToDocument(initialSettings.accentColor);
applyThemeConfigToDocument(initialSettings);

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import { APP_DISPLAY_NAME } from "../branding";
import { useAppSettings } from "../appSettings";
import { applyAccentColorToDocument } from "../accentColor";
import { applyThemeConfigToDocument } from "../themeConfig";
import { Button } from "../components/ui/button";
import { AnchoredToastProvider, ToastProvider, toastManager } from "../components/ui/toast";
import { resolveAndPersistPreferredEditor } from "../editorPreferences";
Expand Down Expand Up @@ -59,6 +60,19 @@
applyAccentColorToDocument(settings.accentColor);
}, [settings.accentColor]);

useEffect(() => {
applyThemeConfigToDocument(settings);

Check warning on line 64 in apps/web/src/routes/__root.tsx

View workflow job for this annotation

GitHub Actions / Format, Lint, Typecheck, Test, Browser Test, Build

eslint-plugin-react-hooks(exhaustive-deps)

React Hook useEffect has a missing dependency: 'settings'
}, [
settings.uiFont,
settings.codeFont,
settings.uiFontSize,
settings.codeFontSize,
settings.backgroundColorOverride,
settings.foregroundColorOverride,
settings.contrast,
settings.translucency,
]);

if (!readNativeApi()) {
return (
<div className="flex h-screen flex-col bg-background text-foreground">
Expand Down
107 changes: 107 additions & 0 deletions apps/web/src/themeConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import type { AppSettings } from "./appSettings";
import { isValidAccentColor, normalizeAccentColor } from "./accentColor";

// ── Default values ──────────────────────────────────────────────────────────
export const DEFAULT_UI_FONT = "";
export const DEFAULT_CODE_FONT = "";
export const DEFAULT_UI_FONT_SIZE = 0; // 0 = use CSS default
export const DEFAULT_CODE_FONT_SIZE = 0;
export const DEFAULT_CONTRAST = 0; // 0 = no adjustment
export const MIN_UI_FONT_SIZE = 10;
export const MAX_UI_FONT_SIZE = 24;
export const MIN_CODE_FONT_SIZE = 8;
export const MAX_CODE_FONT_SIZE = 24;
export const MIN_CONTRAST = -100;
export const MAX_CONTRAST = 100;

// ── Font families ───────────────────────────────────────────────────────────
const DEFAULT_UI_FONT_STACK =
'"DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif';
const DEFAULT_CODE_FONT_STACK =
'"Geist Mono", "SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace';

function buildFontStack(userFont: string, fallback: string): string {
const trimmed = userFont.trim();
if (!trimmed) return fallback;
// If the user provided a comma-separated stack, keep it as-is
if (trimmed.includes(",")) {
return `${trimmed}, ${fallback}`;
}
// If the single font family contains spaces and isn't already quoted, quote it
const quoted =
trimmed.includes(" ") && !trimmed.startsWith('"') && !trimmed.startsWith("'")
? `"${trimmed}"`
: trimmed;
return `${quoted}, ${fallback}`;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

function clampFontSize(size: number, min: number, max: number): number {
if (!Number.isFinite(size) || size <= 0) return 0;
return Math.min(max, Math.max(min, Math.round(size)));
}

function clampContrast(contrast: number): number {
if (!Number.isFinite(contrast)) return 0;
return Math.min(MAX_CONTRAST, Math.max(MIN_CONTRAST, Math.round(contrast)));
}

// ── Apply to document ───────────────────────────────────────────────────────

export function applyThemeConfigToDocument(settings: AppSettings): void {
if (typeof document === "undefined") return;

const root = document.documentElement.style;

// Fonts
const uiFontStack = buildFontStack(settings.uiFont, DEFAULT_UI_FONT_STACK);
const codeFontStack = buildFontStack(settings.codeFont, DEFAULT_CODE_FONT_STACK);
root.setProperty("--theme-ui-font", uiFontStack);
root.setProperty("--theme-code-font", codeFontStack);

// Font sizes
const uiSize = clampFontSize(settings.uiFontSize, MIN_UI_FONT_SIZE, MAX_UI_FONT_SIZE);
const codeSize = clampFontSize(settings.codeFontSize, MIN_CODE_FONT_SIZE, MAX_CODE_FONT_SIZE);
if (uiSize > 0) {
root.setProperty("--theme-ui-font-size", `${uiSize}px`);
} else {
root.removeProperty("--theme-ui-font-size");
}
if (codeSize > 0) {
root.setProperty("--theme-code-font-size", `${codeSize}px`);
} else {
root.removeProperty("--theme-code-font-size");
}

// Background/foreground overrides
if (settings.backgroundColorOverride && isValidAccentColor(settings.backgroundColorOverride)) {
root.setProperty(
"--theme-background-override",
normalizeAccentColor(settings.backgroundColorOverride),
);
} else {
root.removeProperty("--theme-background-override");
}
if (settings.foregroundColorOverride && isValidAccentColor(settings.foregroundColorOverride)) {
root.setProperty(
"--theme-foreground-override",
normalizeAccentColor(settings.foregroundColorOverride),
);
} else {
root.removeProperty("--theme-foreground-override");
}

// Contrast adjustment
const contrast = clampContrast(settings.contrast);
if (contrast !== 0) {
root.setProperty("--theme-contrast", String(contrast));
} else {
root.removeProperty("--theme-contrast");
}

// Translucency
if (settings.translucency) {
document.documentElement.classList.add("theme-translucent");
} else {
document.documentElement.classList.remove("theme-translucent");
}
}