style tweaks

This commit is contained in:
Felix Roos 2026-01-19 23:00:14 +01:00
parent 8ec1d4d034
commit 38b7bcb3d2
No known key found for this signature in database
12 changed files with 62 additions and 65 deletions

View file

@ -13,16 +13,13 @@ export function SpecialActionButton(props) {
const { className, ...buttonProps } = props; const { className, ...buttonProps } = props;
return ( return (
<ActionButton <ActionButton {...buttonProps} className={cx('bg-background p-2 max-w-[300px] hover:opacity-50', className)} />
{...buttonProps}
className={cx('bg-background p-2 max-w-[300px] rounded-md hover:opacity-50', className)}
/>
); );
} }
export function ActionInput({ label, className, ...props }) { export function ActionInput({ label, className, ...props }) {
return ( return (
<label className={cx('inline-flex items-center cursor-pointer', className)}> <label className={cx('inline-flex items-center cursor-pointer ', className)}>
<input {...props} className="sr-only peer" /> <input {...props} className="sr-only peer" />
<span className="inline-flex items-center peer-hover:opacity-50">{label}</span> <span className="inline-flex items-center peer-hover:opacity-50">{label}</span>
@ -35,7 +32,7 @@ export function SpecialActionInput({ className, ...props }) {
<ActionInput <ActionInput
{...props} {...props}
className={className} className={className}
label={<span className="bg-background p-2 max-w-[300px] rounded-md">{props.label}</span>} label={<span className="bg-background p-2 max-w-[300px]">{props.label}</span>}
/> />
); );
} }

View file

@ -1,4 +1,4 @@
import { Textbox } from '../textbox/Textbox'; import { Textbox } from '@src/repl/components/panel/SettingsTab';
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
function IncButton({ children, className, ...buttonProps }) { function IncButton({ children, className, ...buttonProps }) {

View file

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { SelectInput } from './SelectInput'; import { SelectInputDuplicate } from '@src/repl/components/panel/SettingsTab';
import { getAudioDevices } from '@strudel/webaudio'; import { getAudioDevices } from '@strudel/webaudio';
const initdevices = new Map(); const initdevices = new Map();
@ -29,7 +29,7 @@ export function AudioDeviceSelector({ audioDeviceName, onChange, isDisabled }) {
options.set(deviceName, deviceName); options.set(deviceName, deviceName);
}); });
return ( return (
<SelectInput <SelectInputDuplicate
isDisabled={isDisabled} isDisabled={isDisabled}
options={options} options={options}
onClick={onClick} onClick={onClick}

View file

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { audioEngineTargets } from '../../../settings.mjs'; import { audioEngineTargets } from '../../../settings.mjs';
import { SelectInput } from './SelectInput'; import { SelectInputDuplicate } from '@src/repl/components/panel/SettingsTab';
// Allows the user to select an audio interface for Strudel to play through // Allows the user to select an audio interface for Strudel to play through
export function AudioEngineTargetSelector({ target, onChange, isDisabled }) { export function AudioEngineTargetSelector({ target, onChange, isDisabled }) {
@ -12,8 +12,8 @@ export function AudioEngineTargetSelector({ target, onChange, isDisabled }) {
[audioEngineTargets.osc, audioEngineTargets.osc], [audioEngineTargets.osc, audioEngineTargets.osc],
]); ]);
return ( return (
<div className=" flex flex-col gap-1"> <div className="flex flex-col gap-1">
<SelectInput isDisabled={isDisabled} options={options} value={target} onChange={onTargetChange} /> <SelectInputDuplicate isDisabled={isDisabled} options={options} value={target} onChange={onTargetChange} />
{target === audioEngineTargets.osc && ( {target === audioEngineTargets.osc && (
<div> <div>
<p className="text-sm italic"> <p className="text-sm italic">

View file

@ -1,10 +1,7 @@
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
import NumberInput from '@src/repl/components/NumberInput'; import { useState } from 'react';
import { useEffect, useState } from 'react'; import { Textbox } from '@src/repl/components/panel/SettingsTab';
import { Textbox } from '../textbox/Textbox';
import { getAudioContext } from '@strudel/webaudio'; import { getAudioContext } from '@strudel/webaudio';
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
function Checkbox({ label, value, onChange, disabled = false }) { function Checkbox({ label, value, onChange, disabled = false }) {
return ( return (

View file

@ -13,7 +13,7 @@ export function ButtonGroup({ value, onChange, items }) {
// i === 0 && 'rounded-l-md', // i === 0 && 'rounded-l-md',
// i === arr.length - 1 && 'rounded-r-md', // i === arr.length - 1 && 'rounded-r-md',
// value === key ? 'bg-background' : 'bg-lineHighlight', // value === key ? 'bg-background' : 'bg-lineHighlight',
value === key ? 'border-foreground' : 'border-transparent', value === key ? 'border-foreground' : 'border-background',
)} )}
> >
{label.toLowerCase()} {label.toLowerCase()}

View file

@ -18,7 +18,7 @@ import { Pagination } from '../pagination/Pagination.jsx';
import { useState } from 'react'; import { useState } from 'react';
import { useDebounce } from '../usedebounce.jsx'; import { useDebounce } from '../usedebounce.jsx';
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
import { Textbox } from '../textbox/Textbox.jsx'; import { Textbox } from '@src/repl/components/panel/SettingsTab.jsx';
export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) { export function PatternLabel({ pattern } /* : { pattern: Tables<'code'> } */) {
const meta = useMemo(() => getMetadata(pattern.code), [pattern]); const meta = useMemo(() => getMetadata(pattern.code), [pattern]);

View file

@ -1,7 +1,7 @@
import { memo, useEffect, useMemo, useState, Fragment } from 'react'; import { memo, useEffect, useMemo, useState, Fragment } from 'react';
import jsdocJson from '../../../../../doc.json'; import jsdocJson from '../../../../../doc.json';
import { Textbox } from '../textbox/Textbox'; import { Textbox } from '@src/repl/components/panel/SettingsTab';
const isValid = ({ name, description }) => name && !name.startsWith('_') && !!description; const isValid = ({ name, description }) => name && !name.startsWith('_') && !!description;

View file

@ -1,20 +0,0 @@
import React from 'react';
// value: ?ID, options: Map<ID, any>, onChange: ID => null, onClick: event => void, isDisabled: boolean
export function SelectInput({ value, options, onChange, onClick, isDisabled }) {
return (
<select
disabled={isDisabled}
onClick={onClick}
className="p-2 bg-background rounded-md text-foreground border-foreground"
value={value ?? ''}
onChange={(e) => onChange(e.target.value)}
>
{options.size == 0 && <option value={value}>{`${value ?? 'select an option'}`}</option>}
{Array.from(options.keys()).map((id) => (
<option key={id} className="bg-background" value={id}>
{options.get(id)}
</option>
))}
</select>
);
}

View file

@ -1,6 +1,5 @@
import { defaultSettings, settingsMap, useSettings } from '../../../settings.mjs'; import { defaultSettings, settingsMap, useSettings } from '../../../settings.mjs';
import { themes } from '@strudel/codemirror'; import { themes } from '@strudel/codemirror';
import { Textbox } from '../textbox/Textbox.jsx';
import { confirmAndReloadPage, isUdels } from '../../util.mjs'; import { confirmAndReloadPage, isUdels } from '../../util.mjs';
import { ButtonGroup } from './Forms.jsx'; import { ButtonGroup } from './Forms.jsx';
import { AudioDeviceSelector } from './AudioDeviceSelector.jsx'; import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
@ -10,22 +9,60 @@ import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@
import { SpecialActionButton } from '../button/action-button.jsx'; import { SpecialActionButton } from '../button/action-button.jsx';
import { ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx'; import { ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx';
function cx(...classes) {
// : Array<string | undefined>
return classes.filter(Boolean).join(' ');
}
const inputClass =
'bg-background text-sm border rounded-0 text-foreground border-foreground placeholder-foreground focus:outline-none focus:ring-0 focus:border-foreground';
export function Textbox({ onChange, className, ...inputProps }) {
return (
<input className={cx('p-2', inputClass, className)} onChange={(e) => onChange(e.target.value)} {...inputProps} />
);
}
function Checkbox({ label, value, onChange, disabled = false }) { function Checkbox({ label, value, onChange, disabled = false }) {
return ( return (
<label> <label>
<input disabled={disabled} type="checkbox" checked={value} onChange={onChange} /> <input
className={cx(
'bg-background text-sm border border-foreground focus:outline-none focus:ring-0 focus:border-foreground',
)}
disabled={disabled}
type="checkbox"
checked={value}
onChange={onChange}
/>
{' ' + label} {' ' + label}
</label> </label>
); );
} }
function SelectInput({ value, options, onChange }) { // value: ?ID, options: Map<ID, any>, onChange: ID => null, onClick: event => void, isDisabled: boolean
export function SelectInputDuplicate({ value, options, onChange, onClick, isDisabled }) {
return ( return (
<select <select
className="p-2 bg-background rounded-md text-foreground border-foreground" disabled={isDisabled}
value={value} onClick={onClick}
className={cx('p-2', inputClass)}
value={value ?? ''}
onChange={(e) => onChange(e.target.value)} onChange={(e) => onChange(e.target.value)}
> >
{options.size == 0 && <option value={value}>{`${value ?? 'select an option'}`}</option>}
{Array.from(options.keys()).map((id) => (
<option key={id} className="bg-background" value={id}>
{options.get(id)}
</option>
))}
</select>
);
}
function SelectInput({ value, options, onChange }) {
return (
<select className={cx('p-2', inputClass)} value={value} onChange={(e) => onChange(e.target.value)}>
{Object.entries(options).map(([k, label]) => ( {Object.entries(options).map(([k, label]) => (
<option key={k} className="bg-background" value={k}> <option key={k} className="bg-background" value={k}>
{label} {label}
@ -37,9 +74,9 @@ function SelectInput({ value, options, onChange }) {
function NumberSlider({ value, onChange, step = 1, ...rest }) { function NumberSlider({ value, onChange, step = 1, ...rest }) {
return ( return (
<div className="flex space-x-2 gap-1"> <div className="flex space-x-2 gap-1 overflow-hidden">
<input <input
className="p-2 grow" className="p-2 grow accent-foreground"
type="range" type="range"
value={value} value={value}
step={step} step={step}
@ -50,7 +87,7 @@ function NumberSlider({ value, onChange, step = 1, ...rest }) {
type="number" type="number"
value={value} value={value}
step={step} step={step}
className="w-16 bg-background rounded-md" className={cx('w-16', inputClass)}
onChange={(e) => onChange(Number(e.target.value))} onChange={(e) => onChange(Number(e.target.value))}
/> />
</div> </div>
@ -60,7 +97,7 @@ function NumberSlider({ value, onChange, step = 1, ...rest }) {
function FormItem({ label, children, sublabel }) { function FormItem({ label, children, sublabel }) {
return ( return (
<div className="grid gap-2"> <div className="grid gap-2">
<label>{label}</label> <label className="text-sm">{label}</label>
{children} {children}
</div> </div>
); );
@ -178,7 +215,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 font-sans"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<FormItem label="Font Family"> <FormItem label="Font Family">
<SelectInput <SelectInput
options={fontFamilyOptions} options={fontFamilyOptions}

View file

@ -5,7 +5,7 @@ import { useMemo, useRef, useState } from 'react';
import { settingsMap, soundFilterType, useSettings } from '../../../settings.mjs'; import { settingsMap, soundFilterType, useSettings } from '../../../settings.mjs';
import { ButtonGroup } from './Forms.jsx'; import { ButtonGroup } from './Forms.jsx';
import ImportSoundsButton from './ImportSoundsButton.jsx'; import ImportSoundsButton from './ImportSoundsButton.jsx';
import { Textbox } from '../textbox/Textbox.jsx'; import { Textbox } from '@src/repl/components/panel/SettingsTab.jsx';
import { ActionButton } from '../button/action-button.jsx'; import { ActionButton } from '../button/action-button.jsx';
import { confirmDialog } from '@src/repl/util.mjs'; import { confirmDialog } from '@src/repl/util.mjs';
import { clearIDB, userSamplesDBConfig } from '@src/repl/idbutils.mjs'; import { clearIDB, userSamplesDBConfig } from '@src/repl/idbutils.mjs';

View file

@ -1,14 +0,0 @@
import cx from '@src/cx.mjs';
export function Textbox({ onChange, className, ...inputProps }) {
return (
<input
className={cx(
'p-2 bg-background rounded-md border-foreground text-foreground placeholder-foreground',
className,
)}
onChange={(e) => onChange(e.target.value)}
{...inputProps}
/>
);
}