fixed style

This commit is contained in:
Jade (Rose) Rowland 2025-02-21 01:31:06 -05:00
parent b664bd3d1f
commit 1ded398468
14 changed files with 138 additions and 65 deletions

View File

@ -4,7 +4,7 @@ import blackscreen, { settings as blackscreenSettings } from './themes/blackscre
import whitescreen, { settings as whitescreenSettings } from './themes/whitescreen.mjs'; import whitescreen, { settings as whitescreenSettings } from './themes/whitescreen.mjs';
import teletext, { settings as teletextSettings } from './themes/teletext.mjs'; import teletext, { settings as teletextSettings } from './themes/teletext.mjs';
import algoboy, { settings as algoboySettings } from './themes/algoboy.mjs'; import algoboy, { settings as algoboySettings } from './themes/algoboy.mjs';
import grl2000, {settings as grl2000Settings} from './themes/grl2000.mjs' import CutiePi, {settings as CutiePiSettings} from './themes/CutiePi.mjs'
import terminal, { settings as terminalSettings } from './themes/terminal.mjs'; import terminal, { settings as terminalSettings } from './themes/terminal.mjs';
import abcdef, { settings as abcdefSettings } from './themes/abcdef.mjs'; import abcdef, { settings as abcdefSettings } from './themes/abcdef.mjs';
import androidstudio, { settings as androidstudioSettings } from './themes/androidstudio.mjs'; import androidstudio, { settings as androidstudioSettings } from './themes/androidstudio.mjs';
@ -56,7 +56,7 @@ export const themes = {
androidstudio, androidstudio,
duotoneDark, duotoneDark,
githubDark, githubDark,
grl2000, CutiePi,
gruvboxDark, gruvboxDark,
materialDark, materialDark,
nord, nord,
@ -100,7 +100,7 @@ export const settings = {
duotoneLight: duotoneLightSettings, duotoneLight: duotoneLightSettings,
duotoneDark: duotoneDarkSettings, duotoneDark: duotoneDarkSettings,
eclipse: eclipseSettings, eclipse: eclipseSettings,
grl2000: grl2000Settings, CutiePi: CutiePiSettings,
githubLight: githubLightSettings, githubLight: githubLightSettings,
githubDark: githubDarkSettings, githubDark: githubDarkSettings,
gruvboxDark: gruvboxDarkSettings, gruvboxDark: gruvboxDarkSettings,

View File

@ -12,7 +12,7 @@ const grey = '#272C35'
const pinkAccent ="#fee1ff" const pinkAccent ="#fee1ff"
const lightGrey = '#465063' const lightGrey = '#465063'
const bratGreen = "#9acd3f" const bratGreen = "#9acd3f"
const lighterGrey = "#97a1b7"
const pink = '#f6a6fd' const pink = '#f6a6fd'
export const settings = { export const settings = {
@ -29,7 +29,7 @@ export const settings = {
}; };
export default createTheme({ export default createTheme({
theme: 'dark', theme: 'light',
settings, settings,
styles: [ styles: [
{ {
@ -37,11 +37,11 @@ export default createTheme({
color: deepPurple, color: deepPurple,
}, },
{ tag: [t.tagName, t.heading], color: settings.foreground }, { tag: [t.tagName, t.heading], color: settings.foreground },
{ tag: t.comment, color: pink }, { tag: t.comment, color: lighterGrey },
{ tag: [t.variableName, t.propertyName, t.labelName], color: lightGrey }, { tag: [t.variableName, t.propertyName, t.labelName], color: pink },
{ tag: [t.attributeName, t.number], color: 'hsl( 29, 54%, 61%)' }, { tag: [t.attributeName, t.number], color: 'hsl( 29, 54%, 61%)' },
{ tag: t.className, color: grey }, { tag: t.className, color: grey },
{ tag: t.keyword, color: grey }, { tag: t.keyword, color: deepPurple },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: bratGreen }, { tag: [t.string, t.regexp, t.special(t.propertyName)], color: bratGreen },
], ],
}); });

Binary file not shown.

View File

@ -0,0 +1,7 @@
100% free for personal and commercial use.
However it's limited on basic latin only,
contact riedjal@gmail.com for full glyph (based on ANSI encoding)
and OTF features (alternates).
src: https://www.dafont.com/cute-aurora.font?text=%24%3A+s%28%22bd%285%2C8%29%22%29.superimpose%28x+%3D%3E+x.note%28%22c2%22%29.midi%28device%29%29

View File

@ -11,17 +11,19 @@ export function Header({ context, embedded = false }) {
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } = const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } =
context; context;
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location); const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
const { isZen, isButtonRowHidden, isCSSAnimationDisabled } = useSettings(); const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily } = useSettings();
return ( return (
<header <header
id="header" id="header"
className={cx( className={cx(
'flex-none text-black z-[100] text-lg select-none h-20 md:h-14', 'flex-none text-black z-[100] text-lg select-none h-20 md:h-14',
!isZen && !isEmbedded && 'bg-lineHighlight', !isZen && !isEmbedded && 'bg-lineHighlight',
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full py-1 justify-between', isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full py-1 justify-between',
isEmbedded ? 'flex' : 'md:flex', isEmbedded ? 'flex' : 'md:flex',
)} )}
style={{fontFamily}}
> >
<div className="px-4 flex space-x-2 md:pt-0 select-none"> <div className="px-4 flex space-x-2 md:pt-0 select-none">
<h1 <h1
@ -46,7 +48,7 @@ export function Header({ context, embedded = false }) {
} }
}} }}
> >
<span className="block rotate-90"></span> <span className="block text-foreground rotate-90"></span>
</div> </div>
{!isZen && ( {!isZen && (
<div className="space-x-2"> <div className="space-x-2">

View File

@ -5,42 +5,51 @@ import { nanoid } from 'nanoid';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useSettings } from '../../../settings.mjs'; import { useSettings } from '../../../settings.mjs';
export function ConsoleTab() { function getUpdatedLog(log, event) {
const [log, setLog] = useState([]); const { message, type, data } = event.detail;
const { fontFamily, fontSize } = useSettings(); const lastLog = log.length ? log[log.length - 1] : undefined;
useLogger(
useCallback((e) => {
const { message, type, data } = e.detail;
setLog((l) => {
const lastLog = l.length ? l[l.length - 1] : undefined;
const id = nanoid(12); const id = nanoid(12);
// if (type === 'loaded-sample' && lastLog.type === 'load-sample' && lastLog.url === data.url) { // if (type === 'loaded-sample' && lastLog.type === 'load-sample' && lastLog.url === data.url) {
if (type === 'loaded-sample') { if (type === 'loaded-sample') {
// const loadIndex = l.length - 1; // const loadIndex = log.length - 1;
const loadIndex = l.findIndex(({ data: { url }, type }) => type === 'load-sample' && url === data.url); const loadIndex = log.findIndex(({ data: { url }, type }) => type === 'load-sample' && url === data.url);
l[loadIndex] = { message, type, id, data }; log[loadIndex] = { message, type, id, data };
} else if (lastLog && lastLog.message === message) { } else if (lastLog && lastLog.message === message) {
l = l.slice(0, -1).concat([{ message, type, count: (lastLog.count ?? 1) + 1, id, data }]); log = log.slice(0, -1).concat([{ message, type, count: (lastLog.count ?? 1) + 1, id, data }]);
} else { } else {
l = l.concat([{ message, type, id, data }]); log = log.concat([{ message, type, id, data }]);
} }
return l.slice(-20); return log.slice(-20);
}
//ensures that the log state persists when component is remounted
let logSaved = [];
export function ConsoleTab() {
const [log, setLog] = useState(logSaved);
const { fontFamily } = useSettings();
useLogger(
useCallback((event) => {
setLog((log) => {
const newLog = getUpdatedLog(log, event);
logSaved = newLog;
return newLog;
}); });
}, []), }, []),
); );
return ( return (
<div <div id="console-tab" className="break-all first-line:text-sm p-2 h-full" style={{ fontFamily }}>
id="console-tab" <div className="bg-background h-full overflow-auto space-y-1 p-2 rounded-md">
className="break-all px-4 dark:text-white text-stone-900 text-sm py-2 space-y-1"
style={{ fontFamily, fontSize }}
>
{log.map((l, i) => { {log.map((l, i) => {
const message = linkify(l.message); const message = linkify(l.message);
const color = l.data?.hap?.value?.color; const color = l.data?.hap?.value?.color;
return ( return (
<div <div
key={l.id} key={l.id}
className={cx(l.type === 'error' && 'text-red-500', l.type === 'highlight' && 'underline')} className={cx(
l.type === 'error' ? 'text-background bg-foreground' : 'text-foreground',
l.type === 'highlight' && 'underline',
)}
style={color ? { color } : {}} style={color ? { color } : {}}
> >
<span dangerouslySetInnerHTML={{ __html: message }} /> <span dangerouslySetInnerHTML={{ __html: message }} />
@ -49,6 +58,7 @@ export function ConsoleTab() {
); );
})} })}
</div> </div>
</div>
); );
} }

View File

@ -149,8 +149,9 @@ function PanelTab({ label, isSelected, onClick }) {
); );
} }
function Tabs({ setTab, tab, className }) { function Tabs({ setTab, tab, className }) {
const {fontFamily, fontSize} = useSettings()
return ( return (
<div className={cx('flex select-none max-w-full overflow-auto pb-2', className)}> <div className={cx('flex select-none max-w-full overflow-auto pb-2', className)} style={{fontFamily}}>
{Object.keys(tabNames).map((key) => { {Object.keys(tabNames).map((key) => {
const val = tabNames[key]; const val = tabNames[key];
return <PanelTab key={key} isSelected={tab === val} label={key} onClick={() => setTab(val)} />; return <PanelTab key={key} isSelected={tab === val} label={key} onClick={() => setTab(val)} />;

View File

@ -56,7 +56,7 @@ function PatternButtons({ patterns, activePattern, onClick, started }) {
const viewingPatternData = parseJSON(viewingPatternStore); const viewingPatternData = parseJSON(viewingPatternStore);
const viewingPatternID = viewingPatternData.id; const viewingPatternID = viewingPatternData.id;
return ( return (
<div className="font-mono text-sm"> <div className="">
{Object.values(patterns) {Object.values(patterns)
.reverse() .reverse()
.map((pattern) => { .map((pattern) => {
@ -89,7 +89,7 @@ export function PatternsTab({ context }) {
const viewingPatternStore = useViewingPatternData(); const viewingPatternStore = useViewingPatternData();
const viewingPatternData = parseJSON(viewingPatternStore); const viewingPatternData = parseJSON(viewingPatternStore);
const { userPatterns, patternFilter } = useSettings(); const { userPatterns, patternFilter, fontFamily } = useSettings();
const examplePatterns = useExamplePatterns(); const examplePatterns = useExamplePatterns();
const collections = examplePatterns.collections; const collections = examplePatterns.collections;
@ -102,7 +102,7 @@ export function PatternsTab({ context }) {
const autoResetPatternOnChange = !isUdels(); const autoResetPatternOnChange = !isUdels();
return ( return (
<div className="px-4 w-full dark:text-white text-stone-900 space-y-2 flex flex-col overflow-hidden max-h-full h-full"> <div className="px-4 w-full text-foreground space-y-2 flex flex-col overflow-hidden max-h-full h-full" style={{fontFamily}}>
<ButtonGroup <ButtonGroup
value={patternFilter} value={patternFilter}
onChange={(value) => settingsMap.setKey('patternFilter', value)} onChange={(value) => settingsMap.setKey('patternFilter', value)}
@ -173,14 +173,14 @@ export function PatternsTab({ context }) {
return ( return (
<section key={collection} className="py-2"> <section key={collection} className="py-2">
<h2 className="text-xl mb-2">{collection}</h2> <h2 className="text-xl mb-2">{collection}</h2>
<div className="font-mono text-sm">
<PatternButtons <PatternButtons
onClick={(id) => updateCodeWindow({ ...patterns[id], collection }, autoResetPatternOnChange)} onClick={(id) => updateCodeWindow({ ...patterns[id], collection }, autoResetPatternOnChange)}
started={context.started} started={context.started}
patterns={patterns} patterns={patterns}
activePattern={activePattern} activePattern={activePattern}
/> />
</div>
</section> </section>
); );
})} })}

View File

@ -1,6 +1,7 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import jsdocJson from '../../../../../doc.json'; import jsdocJson from '../../../../../doc.json';
import { useSettings } from '@src/settings.mjs';
const availableFunctions = jsdocJson.docs const availableFunctions = jsdocJson.docs
.filter(({ name, description }) => name && !name.startsWith('_') && !!description) .filter(({ name, description }) => name && !name.startsWith('_') && !!description)
.sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name)); .sort((a, b) => /* a.meta.filename.localeCompare(b.meta.filename) + */ a.name.localeCompare(b.name));
@ -14,6 +15,8 @@ const getInnerText = (html) => {
export function Reference() { export function Reference() {
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const {fontFamily} = useSettings()
const visibleFunctions = useMemo(() => { const visibleFunctions = useMemo(() => {
return availableFunctions.filter((entry) => { return availableFunctions.filter((entry) => {
if (!search) { if (!search) {
@ -25,7 +28,7 @@ export function Reference() {
}, [search]); }, [search]);
return ( return (
<div className="flex h-full w-full p-2 text-foreground overflow-hidden"> <div className="flex h-full w-full p-2 overflow-hidden" style={{fontFamily}}>
<div className="h-full flex flex-col gap-2 w-1/3 max-w-72 "> <div className="h-full flex flex-col gap-2 w-1/3 max-w-72 ">
<div class="w-full flex"> <div class="w-full flex">
<input <input
@ -39,7 +42,7 @@ export function Reference() {
{visibleFunctions.map((entry, i) => ( {visibleFunctions.map((entry, i) => (
<a <a
key={i} key={i}
className="cursor-pointer flex-none hover:bg-lineHighlight overflow-x-hidden px-1 text-ellipsis" className="cursor-pointer text-foreground flex-none hover:bg-lineHighlight overflow-x-hidden px-1 text-ellipsis"
onClick={() => { onClick={() => {
const el = document.getElementById(`doc-${i}`); const el = document.getElementById(`doc-${i}`);
const container = document.getElementById('reference-container'); const container = document.getElementById('reference-container');
@ -55,15 +58,15 @@ export function Reference() {
className="break-normal flex-grow flex-col overflow-y-auto overflow-x-hidden px-2 flex relative" className="break-normal flex-grow flex-col overflow-y-auto overflow-x-hidden px-2 flex relative"
id="reference-container" id="reference-container"
> >
<div className="prose dark:prose-invert min-w-full px-1 text-foreground"> <div className="prose dark:prose-invert min-w-full px-1 ">
<h2 className='text-foreground'>API Reference</h2> <h2 >API Reference</h2>
<p> <p>
This is the long list of functions you can use. Remember that you don't need to remember all of those and This is the long list of functions you can use. Remember that you don't need to remember all of those and
that you can already make music with a small set of functions! that you can already make music with a small set of functions!
</p> </p>
{visibleFunctions.map((entry, i) => ( {visibleFunctions.map((entry, i) => (
<section key={i}> <section key={i}>
<h3 className='text-foreground' id={`doc-${i}`}>{entry.name}</h3> <h3 id={`doc-${i}`}>{entry.name}</h3>
{!!entry.synonyms_text && ( {!!entry.synonyms_text && (
<p> <p>
Synonyms: <code className='text-foreground'>{entry.synonyms_text}</code> Synonyms: <code className='text-foreground'>{entry.synonyms_text}</code>
@ -79,7 +82,7 @@ export function Reference() {
))} ))}
</ul> </ul>
{entry.examples?.map((example, j) => ( {entry.examples?.map((example, j) => (
<pre className='text-foreground bg-background' key={j}>{example}</pre> <pre className='bg-background' key={j}>{example}</pre>
))} ))}
</section> </section>
))} ))}

View File

@ -66,6 +66,7 @@ const themeOptions = Object.fromEntries(Object.keys(themes).map((k) => [k, k]));
const fontFamilyOptions = { const fontFamilyOptions = {
monospace: 'monospace', monospace: 'monospace',
Courier: 'Courier', Courier: 'Courier',
CutiePi: 'CutiePi',
JetBrains: 'JetBrains', JetBrains: 'JetBrains',
Hack: 'Hack', Hack: 'Hack',
FiraCode: 'FiraCode', FiraCode: 'FiraCode',
@ -78,6 +79,7 @@ const fontFamilyOptions = {
PressStart: 'PressStart2P', PressStart: 'PressStart2P',
'we-come-in-peace': 'we-come-in-peace', 'we-come-in-peace': 'we-come-in-peace',
galactico: 'galactico', galactico: 'galactico',
}; };
const RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?'; const RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?';
@ -104,11 +106,12 @@ export function SettingsTab({ started }) {
audioDeviceName, audioDeviceName,
audioEngineTarget, audioEngineTarget,
togglePanelTrigger, togglePanelTrigger,
} = useSettings(); } = useSettings();
const shouldAlwaysSync = isUdels(); const shouldAlwaysSync = isUdels();
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null; const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
return ( return (
<div className="text-foreground p-4 space-y-4 w-full"> <div className="text-foreground p-4 space-y-4 w-full" style={{fontFamily}}>
{canChangeAudioDevice && ( {canChangeAudioDevice && (
<FormItem label="Audio Output Device"> <FormItem label="Audio Output Device">
<AudioDeviceSelector <AudioDeviceSelector
@ -141,7 +144,7 @@ export function SettingsTab({ started }) {
<FormItem label="Theme"> <FormItem label="Theme">
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} /> <SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
</FormItem> </FormItem>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 font-sans">
<FormItem label="Font Family"> <FormItem label="Font Family">
<SelectInput <SelectInput
options={fontFamilyOptions} options={fontFamilyOptions}

View File

@ -11,7 +11,7 @@ const getSamples = (samples) =>
export function SoundsTab() { export function SoundsTab() {
const sounds = useStore(soundMap); const sounds = useStore(soundMap);
const { soundsFilter } = useSettings(); const { soundsFilter, fontFamily } = useSettings();
const [search, setSearch] = useState(''); const [search, setSearch] = useState('');
const soundEntries = useMemo(() => { const soundEntries = useMemo(() => {
@ -52,7 +52,7 @@ export function SoundsTab() {
}); });
return ( return (
<div id="sounds-tab" className="px-4 flex flex-col w-full h-full dark:text-white text-stone-900"> <div id="sounds-tab" className="px-4 flex flex-col w-full h-full text-foreground" style={{fontFamily}}>
<input <input
className="w-full p-1 bg-background rounded-md my-2" className="w-full p-1 bg-background rounded-md my-2"
placeholder="Search" placeholder="Search"
@ -74,7 +74,7 @@ export function SoundsTab() {
<ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} /> <ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} />
</div> </div>
<div className="min-h-0 max-h-full grow overflow-auto font-mono text-sm break-normal pb-2"> <div className="min-h-0 max-h-full grow overflow-auto text-sm break-normal pb-2">
{soundEntries.map(([name, { data, onTrigger }]) => { {soundEntries.map(([name, { data, onTrigger }]) => {
return ( return (
<span <span

View File

@ -1,11 +1,14 @@
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
import { useSettings } from '@src/settings.mjs';
const { BASE_URL } = import.meta.env; const { BASE_URL } = import.meta.env;
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL; const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
export function WelcomeTab({ context }) { export function WelcomeTab({ context }) {
const {fontFamily} = useSettings()
return ( return (
<div className="prose dark:prose-invert min-w-full pt-2 font-sans pb-8 px-4 "> <div className="prose dark:prose-invert min-w-full pt-2 font-sans pb-8 px-4 " style={{fontFamily}}>
<h3> welcome</h3> <h3> welcome</h3>
<p> <p>
You have found <span className="underline">strudel</span>, a new live coding platform to write dynamic music You have found <span className="underline">strudel</span>, a new live coding platform to write dynamic music

View File

@ -1,6 +1,7 @@
@font-face { @font-face {
font-family: 'PressStart'; font-family: 'PressStart';
src: url('/fonts/PressStart2P/PressStart2P-Regular.ttf'); src: url('/fonts/PressStart2P/PressStart2P-Regular.ttf');
size-adjust: 65%;
} }
@font-face { @font-face {
font-family: 'BigBlueTerminal'; font-family: 'BigBlueTerminal';
@ -14,6 +15,11 @@
font-family: 'galactico'; font-family: 'galactico';
src: url('/fonts/galactico/Galactico-Basic.otf'); src: url('/fonts/galactico/Galactico-Basic.otf');
} }
@font-face {
font-family: 'CutiePi';
src: url('/fonts/CutiePi/Cute_Aurora_demo.ttf');
size-adjust: 120%;
}
@font-face { @font-face {
font-family: 'JetBrains'; font-family: 'JetBrains';
src: url('/fonts/JetBrains/JetBrainsMono.woff2'); src: url('/fonts/JetBrains/JetBrainsMono.woff2');
@ -21,6 +27,7 @@
@font-face { @font-face {
font-family: 'Monocraft'; font-family: 'Monocraft';
src: url('/fonts/Monocraft/Monocraft.ttf'); src: url('/fonts/Monocraft/Monocraft.ttf');
size-adjust: 90%;
} }
@font-face { @font-face {
font-family: 'Hack'; font-family: 'Hack';
@ -41,6 +48,7 @@
@font-face { @font-face {
font-family: 'teletext'; font-family: 'teletext';
src: url('/fonts/teletext/EuropeanTeletext.ttf'); src: url('/fonts/teletext/EuropeanTeletext.ttf');
size-adjust: 90%;
} }
@font-face { @font-face {
font-family: 'mode7'; font-family: 'mode7';

View File

@ -46,6 +46,42 @@ module.exports = {
'code::after': { 'code::after': {
content: 'none', content: 'none',
}, },
color: 'var(--foreground)',
// text: {
// },
// p: {
// color: 'var(--foreground)',
// },
a: {
color: 'var(--foreground)',
},
h1: {
color: 'var(--foreground)',
},
h2: {
color: 'var(--foreground)',
},
h3: {
color: 'var(--foreground)',
},
h4: {
color: 'var(--foreground)',
},
pre: {
color: 'var(--foreground)',
background: 'var(--background)'
},
code: {
color: 'var(--foreground)',
},
// li: {
// color: 'var(--foreground)',
// },
// span: {
// color: 'var(--foreground)',
// }
}, },
}, },
}; };