style tweaks
This commit is contained in:
parent
8ec1d4d034
commit
38b7bcb3d2
12 changed files with 62 additions and 65 deletions
|
|
@ -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>}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 }) {
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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 (
|
||||||
|
|
|
||||||
|
|
@ -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()}
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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';
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue