Skip to content
Open
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
58 changes: 57 additions & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,54 @@
@import "tailwindcss";

/* Global CSS variables for theming */
:root {
/* Core colors */
--background: #ececec;
--foreground: #222;
--primary: #ff4a00;
--page-max-width: 1300px;
/* Derived colors */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-screen: #f3f3f3;
--color-black-10: rgba(0, 0, 0, 0.1);
--color-black-50: rgba(0, 0, 0, 0.5);
/* Lighting settings: color (R,G,B) and opacity */
--lighting-color: 248,248,248;
--lighting-opacity: 1;
--lighting-scale: 1;
}

/* Dark mode overrides */
html.dark {
--background: #1e1e1e;
--foreground: #e0e0e0;
--color-screen: #2a2a2a;
--color-black-10: rgba(255, 255, 255, 0.1);
--color-black-50: rgba(255, 255, 255, 0.5);
/* Lighting settings override for dark mode */
--lighting-color: 255,255,255;
--lighting-opacity: 0.1;
--lighting-scale: 1;
}
/* Utility class for panel/input backgrounds, uses theme variable */
.bg-screen {
background-color: var(--color-screen) !important;
position: relative;
}
.bg-screen::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: calc(100% - 1px);
height: calc(100% - 1px);
/* Panel/input border highlight: intensity scaled by lighting slider */
border-top: 1px solid rgba(var(--lighting-color), calc(var(--lighting-opacity) * var(--lighting-scale)));
border-left: 1px solid rgba(var(--lighting-color), calc(var(--lighting-opacity) * var(--lighting-scale)));
border-radius: var(--radius-md);
pointer-events: none;
}

@theme inline {
Expand Down Expand Up @@ -40,9 +84,10 @@ body {
color: var(--foreground);

@variant sm {
/* Gradient lighting effect using theme variables */
background-image: linear-gradient(
to bottom right,
#f8f8f8,
rgba(var(--lighting-color), var(--lighting-opacity)),
var(--background) 20%
);
background-repeat: no-repeat;
Expand All @@ -53,3 +98,14 @@ svg {
display: block;
flex-shrink: 0;
}
/* CodeMirror dark theme overrides */
html.dark .cm-editor {
background-color: var(--color-screen) !important;
}
html.dark .cm-editor .cm-content {
color: var(--color-foreground) !important;
}
html.dark .cm-editor .cm-gutters {
background-color: var(--color-screen) !important;
color: var(--color-foreground) !important;
}
43 changes: 36 additions & 7 deletions src/components/ui/Button.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
flex: 1;
border-radius: var(--radius-md);
padding: 12px;
background: #f4f4f4;
background: var(--color-screen);
box-shadow: rgb(255, 255, 255) 1px 1px 1px 0px inset,
rgba(0, 0, 0, 0.15) -1px -1px 1px 0px inset,
rgba(0, 0, 0, 0.26) 0.444584px 0.444584px 0.628737px -1px,
Expand All @@ -20,6 +20,32 @@
transition: box-shadow 0.3s ease;
cursor: pointer;
user-select: none;
position: relative;
/* Per-button variables for lighting: base brightness and edge opacity */
--lighting-brightness: 1;
--lighting-edge: 1;
/* Filter brightness = mix(global brightness (1) and per-element computed brightness) */
/* Blend distance-based brightness with global lighting scale */
filter: brightness(
calc(
var(--lighting-brightness) * (1 - var(--lighting-scale)) +
1 * var(--lighting-scale)
)
);
}
/* Top-left reflective highlight based on lighting */
.Button::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: calc(100% - 1px);
height: calc(100% - 1px);
/* Border highlight opacity based on distance and global slider */
border-top: 1px solid rgba(var(--lighting-color), calc(var(--lighting-edge) * var(--lighting-scale)));
border-left: 1px solid rgba(var(--lighting-color), calc(var(--lighting-edge) * var(--lighting-scale)));
border-radius: inherit;
pointer-events: none;
}

.Button[data-block] {
Expand Down Expand Up @@ -64,8 +90,9 @@

/* Secondary */
.Button[data-color="secondary"] {
color: #fff;
background: #222;
/* Contrast uses inverted base colors */
color: var(--color-background);
background: var(--color-foreground);
box-shadow: inset 1px 1px 1px #ffffffb3, inset -1px -1px 1px #0000003b,
0.444584px 0.444584px 0.628737px -0.75px #00000042,
1.21072px 1.21072px 1.71222px -1.5px #0000003f,
Expand All @@ -86,8 +113,9 @@

/* Tertiary */
.Button[data-color="tertiary"] {
color: #fff;
background: #6a6a6a;
/* Subtle accent using semi-transparent base */
color: var(--color-background);
background: var(--color-black-50);
box-shadow: inset 1px 1px 1px #ffffffba, inset -1px -1px 1px #0000003b,
0.444584px 0.444584px 0.628737px -1px #00000042,
1.21072px 1.21072px 1.71222px -1.5px #0000003f,
Expand All @@ -108,8 +136,9 @@

/* Neutral */
.Button[data-color="neutral"] {
color: #fff;
background: #aaa;
/* Low-contrast neutral: use foreground for icon/text clarity */
color: var(--color-foreground);
background: var(--color-black-10);
box-shadow: inset 1px 1px 1px #ffffffc2, inset -1px -1px 1px #0000003b,
0.444584px 0.444584px 0.628737px -1px #00000042,
1.21072px 1.21072px 1.71222px -1.5px #0000003f,
Expand Down
34 changes: 32 additions & 2 deletions src/components/ui/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useAudioClip } from "@/hooks/useAudioClip";
import clsx from "clsx";
import { KeyboardEvent, MouseEvent, ReactNode } from "react";
import { KeyboardEvent, MouseEvent, ReactNode, useRef, useEffect } from "react";
import s from "./Button.module.css";

interface ButtonBaseProps {
Expand Down Expand Up @@ -39,6 +39,36 @@ export const Button = ({
}: ButtonProps) => {
const TagName = href ? "a" : "div";
const playPressed = useAudioClip("/pressed.wav");
const ref = useRef<HTMLElement>(null);

useEffect(() => {
if (!ref.current) return;

const updateLighting = () => {
const el = ref.current!;
const rect = el.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
const maxDist = Math.hypot(window.innerWidth, window.innerHeight);
const dist = Math.hypot(x, y);
const norm = dist / maxDist;
// base brightness factor (1 = full, minB = dimmest at furthest point)
const minB = 0.6;
const brightness = minB + (1 - norm) * (1 - minB);
// set base brightness (distance-based) and edge opacity for this button
el.style.setProperty("--lighting-brightness", brightness.toString());
const baseEdge = Math.max(0, Math.min(1, 1 - norm));
el.style.setProperty("--lighting-edge", baseEdge.toString());
};

updateLighting();
window.addEventListener("resize", updateLighting);
window.addEventListener("scroll", updateLighting, true);
return () => {
window.removeEventListener("resize", updateLighting);
window.removeEventListener("scroll", updateLighting, true);
};
}, []);

const handleClick = (evt: MouseEvent) => {
if (!selected) {
Expand All @@ -54,7 +84,7 @@ export const Button = ({
};

return (
<TagName
<TagName ref={ref}
className={clsx(s.Button, className)}
data-color={color}
data-block={block ? "" : undefined}
Expand Down
51 changes: 48 additions & 3 deletions src/components/ui/DevMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import s from "./DevMode.module.css";
import { appStore } from "@/lib/store";
import { getCodeSnippet } from "../../lib/codeSnippet";
import clsx from "clsx";
import { useState, useEffect } from "react";

const fmTheme = createTheme({
theme: "light",
Expand Down Expand Up @@ -41,12 +42,56 @@ const fmTheme = createTheme({
],
});

// Dark mode CodeMirror theme, transparent background to use CSS bg-screen (dark) background
const fmDarkTheme = createTheme({
theme: "dark",
settings: {
background: "transparent",
backgroundImage: "",
foreground: "#e0e0e0",
caret: "#5d00ff",
selection: "#5d00ff33",
selectionMatch: "#5d00ff33",
lineHighlight: "#44444444",
gutterBackground: "transparent",
gutterForeground: "transparent",
},
// Syntax highlighting styles (same as light theme)
styles: [
{ tag: t.comment, color: "#66666699" },
{ tag: t.variableName, color: "#171717" },
{ tag: [t.string, t.special(t.brace)], color: "#C58041" },
{ tag: t.number, color: "#C58041" },
{ tag: t.bool, color: "#C58041" },
{ tag: t.null, color: "#C58041" },
{ tag: t.keyword, color: "#F64700" },
{ tag: t.operator, color: "#aaaaaa" },
{ tag: t.className, color: "#F64700" },
{ tag: t.definition(t.typeName), color: "#aaaaaa" },
{ tag: t.typeName, color: "#aaaaaa" },
{ tag: t.angleBracket, color: "#00A67D" },
{ tag: t.tagName, color: "#00A67D" },
{ tag: t.attributeName, color: "#00A67D" },
],
});

export const DevMode: React.FC = () => {
const voice = appStore.useState((state) => state.voice);
const input = appStore.useState((state) => state.input);
const prompt = appStore.useState((state) => state.prompt);
const height = "563px";
const codeView = appStore.useState((state) => state.codeView);
// Track dark mode to switch CodeMirror theme
const [isDark, setIsDark] = useState(
document.documentElement.classList.contains("dark")
);
useEffect(() => {
const obs = new MutationObserver(() => {
setIsDark(document.documentElement.classList.contains("dark"));
});
obs.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
return () => obs.disconnect();
}, []);

const editorTheme = EditorView.theme({
// Only highlight the line if the editor is in a focused state.
Expand Down Expand Up @@ -89,7 +134,7 @@ export const DevMode: React.FC = () => {
height={height}
extensions={[python(), editorTheme]}
basicSetup={setup}
theme={fmTheme}
theme={isDark ? fmDarkTheme : fmTheme}
/>
</div>
<div id="js" className={clsx(s.Container, "bg-screen")}>
Expand All @@ -98,7 +143,7 @@ export const DevMode: React.FC = () => {
height={height}
extensions={[javascript(), editorTheme]}
basicSetup={setup}
theme={fmTheme}
theme={isDark ? fmDarkTheme : fmTheme}
/>
</div>
<div id="curl" className={clsx(s.Container, "bg-screen")}>
Expand All @@ -107,7 +152,7 @@ export const DevMode: React.FC = () => {
height={height}
extensions={[editorTheme]}
basicSetup={setup}
theme={fmTheme}
theme={isDark ? fmDarkTheme : fmTheme}
/>
</div>
</Block>
Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/Footer.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
left: 0;
z-index: 20;
border-top: 1px solid transparent;
background: #ececec70;
/* Solid background respects theme background variable */
background: var(--background);
backdrop-filter: blur(2rem);
-webkit-backdrop-filter: blur(2rem);
font-size: 1.125rem;
transition: border 0.2s ease;
}

[data-scrollable="true"] .Footer {
border-top: 1px solid #fff;
/* Border adapts to theme contrast */
border-top: 1px solid var(--color-black-50);
}

@keyframes wave {
Expand Down
Loading