mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-12 22:15:27 -04:00
make it crunchier: border borders, less padding
This commit is contained in:
+1
-1
@@ -5,7 +5,7 @@ export const settings = {
|
||||
background: '#222',
|
||||
lineBackground: '#22222299',
|
||||
foreground: '#fff',
|
||||
muted: '#ffffff50',
|
||||
muted: '#8a919966',
|
||||
caret: '#ffcc00',
|
||||
selection: 'rgba(128, 203, 196, 0.5)',
|
||||
selectionMatch: '#036dd626',
|
||||
|
||||
@@ -8,7 +8,7 @@ export function Code(Props) {
|
||||
|
||||
return (
|
||||
<section
|
||||
className={'text-gray-100 cursor-text pb-0 overflow-auto grow'}
|
||||
className={'text-gray-100 cursor-text pb-0 overflow-auto grow z-10'}
|
||||
id="code"
|
||||
ref={(el) => {
|
||||
containerRef.current = el;
|
||||
|
||||
@@ -16,7 +16,7 @@ export function Header({ context, isEmbedded = false }) {
|
||||
<header
|
||||
id="header"
|
||||
className={cx(
|
||||
'flex-none text-black z-[100] text-sm select-none min-h-10',
|
||||
'border-b border-muted flex-none text-black z-[100] text-sm select-none min-h-10',
|
||||
!isZen && !isEmbedded && 'bg-lineHighlight',
|
||||
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full justify-between',
|
||||
'flex items-center',
|
||||
|
||||
@@ -2,7 +2,7 @@ import cx from '@src/cx.mjs';
|
||||
|
||||
export function ActionButton({ children, label, labelIsHidden, className, ...buttonProps }) {
|
||||
return (
|
||||
<button className={cx('hover:opacity-50 text-nowrap w-fit text-sm ', className)} title={label} {...buttonProps}>
|
||||
<button className={cx('hover:opacity-50 text-nowrap w-fit', className)} title={label} {...buttonProps}>
|
||||
{labelIsHidden !== true && label}
|
||||
{children}
|
||||
</button>
|
||||
|
||||
@@ -7,8 +7,10 @@ export function ConsoleTab() {
|
||||
const log = useStore($strudel_log_history);
|
||||
const { fontFamily } = useSettings();
|
||||
return (
|
||||
<div id="console-tab" className="break-all w-full text-sm p-2 h-full" style={{ fontFamily }}>
|
||||
<div className="bg-background h-full w-full overflow-auto space-y-1 p-2 rounded-md">
|
||||
<div id="console-tab" className="break-all w-full h-full" style={{ fontFamily }}>
|
||||
<div className="h-full w-full overflow-auto space-y-1 p-2 rounded-md">
|
||||
{' '}
|
||||
{/* bg-background */}
|
||||
{log.map((l, i) => {
|
||||
const message = linkify(l.message);
|
||||
const color = l.data?.hap?.value?.color;
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function ExportTab(Props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="text-foreground w-full p-4 space-y-4">
|
||||
<div className="text-foreground w-full space-y-4 p-4">
|
||||
<FormItem label="File name" disabled={exporting}>
|
||||
<Textbox
|
||||
onBlur={(e) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import cx from '@src/cx.mjs';
|
||||
|
||||
export function ButtonGroup({ value, onChange, items }) {
|
||||
return (
|
||||
<div className="flex max-w-lg space-x-0 text-sm">
|
||||
<div className="flex max-w-lg space-x-0">
|
||||
{Object.entries(items).map(([key, label], i, arr) => (
|
||||
<button
|
||||
key={key}
|
||||
|
||||
@@ -19,7 +19,7 @@ function PanelCloseButton() {
|
||||
isPanelOpen && (
|
||||
<button
|
||||
onClick={() => setIsPanelOpened(false)}
|
||||
className={cx('px-4 py-2 text-foreground hover:opacity-50')}
|
||||
className={cx('px-4 py-1 text-foreground hover:opacity-50')}
|
||||
aria-label="Close Menu"
|
||||
>
|
||||
<XMarkIcon className="w-6 h-6" />
|
||||
@@ -34,15 +34,15 @@ export function HorizontalPanel({ context }) {
|
||||
<PanelNav
|
||||
className={cx(
|
||||
isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-10 max-h-10',
|
||||
'overflow-hidden flex flex-col relative ',
|
||||
'overflow-hidden flex flex-col relative',
|
||||
)}
|
||||
>
|
||||
<div className="flex justify-between min-h-10 max-h-10 grid-cols-2 items-center">
|
||||
<div className="flex justify-between min-h-10 max-h-10 grid-cols-2 items-center border-b border-muted">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelCloseButton />
|
||||
</div>
|
||||
{isPanelOpen && (
|
||||
<div className="flex h-full overflow-auto w-full">
|
||||
<div className="w-full h-full overflow-hidden">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</div>
|
||||
)}
|
||||
@@ -59,10 +59,13 @@ export function VerticalPanel({ context }) {
|
||||
return (
|
||||
<PanelNav
|
||||
settings={settings}
|
||||
className={cx(isPanelOpen ? `min-w-[min(600px,100vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12')}
|
||||
className={cx(
|
||||
'border-l border-muted',
|
||||
isPanelOpen ? `min-w-[min(600px,100vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12',
|
||||
)}
|
||||
>
|
||||
<div className={cx('flex flex-col h-full')}>
|
||||
<div className="flex justify-between w-full ">
|
||||
<div className="flex justify-between w-full border-b border-muted">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelCloseButton />
|
||||
</div>
|
||||
@@ -134,7 +137,7 @@ function PanelTab({ label, isSelected, onClick }) {
|
||||
<button
|
||||
onClick={onClick}
|
||||
className={cx(
|
||||
'h-8 px-2 text-sm text-foreground cursor-pointer hover:opacity-50 flex items-center space-x-1 border-b',
|
||||
'h-8 px-2 text-sm text-foreground cursor-pointer hover:opacity-50 flex items-center space-x-1 border-b-2',
|
||||
isSelected ? 'border-foreground' : 'border-transparent',
|
||||
)}
|
||||
>
|
||||
@@ -146,7 +149,7 @@ function PanelTab({ label, isSelected, onClick }) {
|
||||
function Tabs({ className }) {
|
||||
const { isPanelOpen, activeFooter: tab } = useSettings();
|
||||
return (
|
||||
<div className={cx('flex select-none max-w-full overflow-auto items-center', className)}>
|
||||
<div className={cx('w-full flex select-none max-w-full overflow-auto items-center', className)}>
|
||||
{Object.keys(tabNames).map((key) => {
|
||||
const val = tabNames[key];
|
||||
return <PanelTab key={key} isSelected={tab === val && isPanelOpen} label={key} onClick={() => setTab(val)} />;
|
||||
@@ -164,7 +167,7 @@ export function PanelToggle({ isEmbedded, isZen }) {
|
||||
<button
|
||||
title="share"
|
||||
className={cx(
|
||||
'absolute top-0 right-3 rounded-0 px-2 py-2 bg-background z-[1000] cursor-pointer hover:opacity-80 flex justify-center items-center space-x-1 text-foreground ',
|
||||
'absolute top-0.5 right-3 rounded-0 px-2 py-2 bg-background z-[1000] cursor-pointer hover:opacity-80 flex justify-center items-center space-x-1 text-foreground ',
|
||||
isPanelOpen && 'hidden',
|
||||
)}
|
||||
onClick={() => setIsPanelOpened(!isPanelOpen)}
|
||||
|
||||
@@ -43,7 +43,7 @@ function PatternButton({ showOutline, onClick, pattern, showHiglight }) {
|
||||
className={cx(
|
||||
'mr-4 hover:opacity-50 cursor-pointer block',
|
||||
showOutline && 'outline outline-1',
|
||||
showHiglight && 'bg-selection',
|
||||
showHiglight && 'ring-selection',
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
@@ -57,7 +57,7 @@ function PatternButtons({ patterns, activePattern, onClick, started }) {
|
||||
const viewingPatternData = parseJSON(viewingPatternStore);
|
||||
const viewingPatternID = viewingPatternData.id;
|
||||
return (
|
||||
<div className="">
|
||||
<div className="p-2">
|
||||
{Object.values(patterns)
|
||||
.reverse()
|
||||
.map((pattern) => {
|
||||
@@ -124,71 +124,68 @@ export function PatternsTab({ context }) {
|
||||
}, [search, viewingPatternStore]);
|
||||
|
||||
return (
|
||||
<div className="px-4 w-full text-foreground space-y-2 flex flex-col overflow-hidden max-h-full h-full">
|
||||
<div className="w-full flex">
|
||||
<Textbox className="w-full" placeholder="Search" value={search} onChange={setSearch} />
|
||||
<div className="w-full h-full text-foreground flex flex-col overflow-hidden">
|
||||
<Textbox className="w-full border-0" placeholder="Search" value={search} onChange={setSearch} />
|
||||
<div className="px-2 shrink-0 py-2 space-x-4 flex max-w-full overflow-x-auto border-y border-muted">
|
||||
<ActionButton
|
||||
label="new"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.createAndAddToDB();
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
<ActionButton
|
||||
label="duplicate"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.duplicate(viewingPatternData);
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
<ActionButton
|
||||
label="delete"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.delete(viewingPatternID);
|
||||
updateCodeWindow(context, { ...data, collection: userPattern.collection });
|
||||
}}
|
||||
/>
|
||||
<label className="hover:opacity-50 cursor-pointer">
|
||||
<input
|
||||
style={{ display: 'none' }}
|
||||
type="file"
|
||||
multiple
|
||||
accept="text/plain,text/x-markdown,application/json"
|
||||
onChange={(e) => importPatterns(e.target.files)}
|
||||
/>
|
||||
import
|
||||
</label>
|
||||
<ActionButton label="export" onClick={exportPatterns} />
|
||||
|
||||
<ActionButton
|
||||
label="delete-all"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.clearAll();
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 flex-grow overflow-hidden h-full pb-2 ">
|
||||
<div className="pr-4 space-x-4 flex max-w-full overflow-x-auto">
|
||||
<ActionButton
|
||||
label="new"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.createAndAddToDB();
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
<ActionButton
|
||||
label="duplicate"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.duplicate(viewingPatternData);
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
<ActionButton
|
||||
label="delete"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.delete(viewingPatternID);
|
||||
updateCodeWindow(context, { ...data, collection: userPattern.collection });
|
||||
}}
|
||||
/>
|
||||
<label className="hover:opacity-50 cursor-pointer">
|
||||
<input
|
||||
style={{ display: 'none' }}
|
||||
type="file"
|
||||
multiple
|
||||
accept="text/plain,text/x-markdown,application/json"
|
||||
onChange={(e) => importPatterns(e.target.files)}
|
||||
/>
|
||||
import
|
||||
</label>
|
||||
<ActionButton label="export" onClick={exportPatterns} />
|
||||
|
||||
<ActionButton
|
||||
label="delete-all"
|
||||
onClick={() => {
|
||||
const { data } = userPattern.clearAll();
|
||||
updateCodeWindow(context, data);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="overflow-auto">
|
||||
{/* bg-background */}
|
||||
{/* {patternFilter === patternFilterName.user && ( */}
|
||||
<PatternButtons
|
||||
onClick={(id) => {
|
||||
updateCodeWindow(context, { ...userPatterns[id], collection: userPattern.collection }, patternAutoStart);
|
||||
|
||||
<div className="overflow-auto h-full bg-background p-2">
|
||||
{/* {patternFilter === patternFilterName.user && ( */}
|
||||
<PatternButtons
|
||||
onClick={(id) => {
|
||||
updateCodeWindow(context, { ...userPatterns[id], collection: userPattern.collection }, patternAutoStart);
|
||||
|
||||
if (context.started && activePattern === id) {
|
||||
context.handleEvaluate();
|
||||
}
|
||||
}}
|
||||
patterns={visiblePatterns}
|
||||
started={context.started}
|
||||
activePattern={activePattern}
|
||||
viewingPatternID={viewingPatternID}
|
||||
/>
|
||||
{/* )} */}
|
||||
</div>
|
||||
if (context.started && activePattern === id) {
|
||||
context.handleEvaluate();
|
||||
}
|
||||
}}
|
||||
patterns={visiblePatterns}
|
||||
started={context.started}
|
||||
activePattern={activePattern}
|
||||
viewingPatternID={viewingPatternID}
|
||||
/>
|
||||
{/* )} */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -112,11 +112,12 @@ export const Reference = memo(function Reference() {
|
||||
}, [selectedFunction]);
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full p-2 overflow-hidden">
|
||||
<div className="h-full text-foreground flex flex-col gap-3 w-1/3 ">
|
||||
<div className="flex h-full w-full overflow-hidden">
|
||||
<div className="h-full text-foreground flex flex-col w-1/3 border-r border-muted">
|
||||
{/* bg-background */}
|
||||
<div className="w-full flex">
|
||||
<Textbox
|
||||
className="w-full"
|
||||
className="w-full border-0 border-b border-muted"
|
||||
placeholder="Search"
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
@@ -128,14 +129,14 @@ export const Reference = memo(function Reference() {
|
||||
{selectedTag && (
|
||||
<div className="w-72">
|
||||
<span
|
||||
className="text-foreground border border-muted px-1 py-0.5 my-2 cursor-pointer font-sans"
|
||||
className="text-foreground border border-muted border-t-0 border-l-0 px-1 py-0.5 my-2 cursor-pointer font-sans"
|
||||
onClick={onSearchTagFilterClick}
|
||||
>
|
||||
{selectedTag}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col h-full overflow-y-auto gap-1.5 bg-background bg-opacity-50">
|
||||
<div className="flex flex-col h-full py-2 overflow-y-auto gap-1.5 bg-opacity-50">
|
||||
{searchVisibleFunctions.map((entry, i) => (
|
||||
<Fragment key={`entry-${entry.name}`}>
|
||||
<a
|
||||
@@ -161,7 +162,7 @@ export const Reference = memo(function Reference() {
|
||||
className="break-normal flex-col overflow-y-auto overflow-x-hidden p-2 flex relative"
|
||||
id="reference-container"
|
||||
>
|
||||
<div className="prose dark:prose-invert min-w-full px-1 ">
|
||||
<div className="prose dark:prose-invert min-w-full px-1 text-sm">
|
||||
<h2>API Reference</h2>
|
||||
<p className="font-sans text-md">
|
||||
This is the long list of functions you can use. Remember that you don't need to remember all of those and
|
||||
|
||||
@@ -154,7 +154,7 @@ export function SettingsTab({ started }) {
|
||||
const shouldAlwaysSync = isUdels();
|
||||
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
|
||||
return (
|
||||
<div className="text-foreground p-4 space-y-4 w-full" style={{ fontFamily }}>
|
||||
<div className="p-4 text-foreground space-y-4 w-full" style={{ fontFamily }}>
|
||||
{canChangeAudioDevice && (
|
||||
<FormItem label="Audio Output Device">
|
||||
<AudioDeviceSelector
|
||||
|
||||
@@ -77,10 +77,10 @@ export function SoundsTab() {
|
||||
numRef.current = 0;
|
||||
});
|
||||
return (
|
||||
<div id="sounds-tab" className="px-4 flex gap-2 flex-col w-full h-full text-foreground">
|
||||
<Textbox placeholder="Search" value={search} onChange={(v) => setSearch(v)} />
|
||||
<div id="sounds-tab" className="flex flex-col w-full h-full text-foreground">
|
||||
<Textbox placeholder="Search" className="border-0" value={search} onChange={(v) => setSearch(v)} />
|
||||
|
||||
<div className=" flex shrink-0 flex-wrap">
|
||||
<div className="flex shrink-0 flex-wrap border-y border-muted">
|
||||
<ButtonGroup
|
||||
value={soundsFilter}
|
||||
onChange={(value) => settingsMap.setKey('soundsFilter', value)}
|
||||
@@ -114,7 +114,7 @@ export function SoundsTab() {
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="min-h-0 max-h-full grow overflow-auto text-sm break-normal bg-background p-2 rounded-md">
|
||||
<div className="min-h-0 max-h-full grow overflow-auto break-normal p-2">
|
||||
{soundEntries.map(([name, { data, onTrigger }]) => {
|
||||
return (
|
||||
<span
|
||||
|
||||
@@ -6,7 +6,7 @@ const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL
|
||||
export function WelcomeTab({ context }) {
|
||||
const { fontFamily } = useSettings();
|
||||
return (
|
||||
<div className="prose dark:prose-invert min-w-full pt-2 font-sans pb-8 px-4 " style={{ fontFamily }}>
|
||||
<div className="prose dark:prose-invert min-w-full py-4 font-sans px-4 text-sm" style={{ fontFamily }}>
|
||||
<h3>welcome</h3>
|
||||
<p>
|
||||
You have found <span className="underline">strudel</span>, a new live coding platform to write dynamic music
|
||||
|
||||
Reference in New Issue
Block a user