Merge pull request 'add muted theme color + tweak pane styles' (#1936) from stylez into main

Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1936
This commit is contained in:
froos 2026-01-21 00:27:43 +01:00
commit b684e183a0
64 changed files with 334 additions and 343 deletions

5
.astro/settings.json Normal file
View file

@ -0,0 +1,5 @@
{
"devToolbar": {
"enabled": false
}
}

View file

@ -198,6 +198,7 @@ export function activateTheme(name) {
const themeSettings = settings[name] || settings.strudelTheme; const themeSettings = settings[name] || settings.strudelTheme;
// set css variables // set css variables
themeStyle.innerHTML = `:root { themeStyle.innerHTML = `:root {
color-scheme: ${themeSettings.light ? 'light' : 'dark'};
${Object.entries(themeSettings) ${Object.entries(themeSettings)
// important to override fallback // important to override fallback
.map(([key, value]) => `--${key}: ${value} !important;`) .map(([key, value]) => `--${key}: ${value} !important;`)

View file

@ -17,13 +17,15 @@ export const settings = {
background: 'white', background: 'white',
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: deepPurple, foreground: deepPurple,
muted: deepPurple + '50',
caret: '#797977', caret: '#797977',
selection: yellowPink, selection: yellowPink,
selectionMatch: '#2B323D', selectionMatch: '#2B323D',
gutterBackground: grey, gutterBackground: pinkAccent,
gutterForeground: lightGrey, gutterForeground: lightGrey,
gutterBorder: 'transparent', gutterBorder: 'transparent',
lineHighlight: pinkAccent, lineHighlight: pinkAccent,
light: true,
}; };
export default createTheme({ export default createTheme({

View file

@ -31,6 +31,7 @@ const palette = palettes['Sour Watermelon B'];
export const settings = { export const settings = {
background: palette[3], background: palette[3],
foreground: palette[1], foreground: palette[1],
muted: palette[1] + '50',
caret: palette[0], caret: palette[0],
selection: palette[0], selection: palette[0],
selectionMatch: palette[1], selectionMatch: palette[1],

View file

@ -8,6 +8,7 @@ export const settings = {
background: '#282b2e', background: '#282b2e',
lineBackground: '#282b2e99', lineBackground: '#282b2e99',
foreground: '#a9b7c6', foreground: '#a9b7c6',
muted: '#a9b7c650',
caret: '#00FF00', caret: '#00FF00',
selection: '#343739', selection: '#343739',
selectionMatch: '#343739', selectionMatch: '#343739',
@ -19,6 +20,7 @@ export default createTheme({
settings: { settings: {
background: '#282b2e', background: '#282b2e',
foreground: '#a9b7c6', foreground: '#a9b7c6',
muted: '#a9b7c650',
caret: '#00FF00', caret: '#00FF00',
selection: '#4e5254', selection: '#4e5254',
selectionMatch: '#4e5254', selectionMatch: '#4e5254',

View file

@ -12,6 +12,7 @@ export const settings = {
background: hex[0], background: hex[0],
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[1], foreground: hex[1],
muted: hex[2],
selection: hex[2], selection: hex[2],
selectionMatch: hex[0], selectionMatch: hex[0],
gutterBackground: hex[0], gutterBackground: hex[0],

View file

@ -11,6 +11,7 @@ export const settings = {
background: '#272C35', background: '#272C35',
lineBackground: '#272C3599', lineBackground: '#272C3599',
foreground: 'hsl(220, 14%, 71%)', foreground: 'hsl(220, 14%, 71%)',
muted: 'hsl(220, 14%, 41%)',
caret: '#797977', caret: '#797977',
selection: '#ffffff30', selection: '#ffffff30',
selectionMatch: '#2B323D', selectionMatch: '#2B323D',
@ -25,6 +26,7 @@ export default createTheme({
settings: { settings: {
background: '#272C35', background: '#272C35',
foreground: '#9d9b97', foreground: '#9d9b97',
muted: 'hsl(220, 14%, 41%)',
caret: '#797977', caret: '#797977',
selection: '#3d4c64', selection: '#3d4c64',
selectionMatch: '#3d4c64', selectionMatch: '#3d4c64',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#21202e', background: '#21202e',
lineBackground: '#21202e99', lineBackground: '#21202e99',
foreground: '#edecee', foreground: '#edecee',
muted: '#edecee50',
caret: '#a277ff', caret: '#a277ff',
selection: '#3d375e7f', selection: '#3d375e7f',
selectionMatch: '#3d375e7f', selectionMatch: '#3d375e7f',
@ -18,6 +19,7 @@ export default createTheme({
settings: { settings: {
background: '#21202e', background: '#21202e',
foreground: '#edecee', foreground: '#edecee',
muted: '#edecee50',
caret: '#a277ff', caret: '#a277ff',
selection: '#5a51898f', selection: '#5a51898f',
selectionMatch: '#5a51898f', selectionMatch: '#5a51898f',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#FFFFFF', background: '#FFFFFF',
lineBackground: '#FFFFFF99', lineBackground: '#FFFFFF99',
foreground: '#000000', foreground: '#000000',
muted: '#00000050',
caret: '#FBAC52', caret: '#FBAC52',
selection: '#FFD420', selection: '#FFD420',
selectionMatch: '#FFD420', selectionMatch: '#FFD420',
@ -20,6 +21,7 @@ export default createTheme({
settings: { settings: {
background: '#FFFFFF', background: '#FFFFFF',
foreground: '#000000', foreground: '#000000',
muted: '#00000050',
caret: '#FBAC52', caret: '#FBAC52',
selection: '#FFD420', selection: '#FFD420',
selectionMatch: '#FFD420', selectionMatch: '#FFD420',

View file

@ -2,7 +2,8 @@ import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from './theme-helper.mjs';
export const settings = { export const settings = {
background: 'black', background: 'black',
foreground: 'white', // whats that? foreground: 'white',
muted: '#ffffff50',
caret: 'white', caret: 'white',
selection: '#ffffff20', selection: '#ffffff20',
selectionMatch: '#036dd626', selectionMatch: '#036dd626',

View file

@ -3,7 +3,8 @@ import { createTheme } from './theme-helper.mjs';
export const settings = { export const settings = {
background: '#051DB5', background: '#051DB5',
lineBackground: '#051DB550', lineBackground: '#051DB550',
foreground: 'white', // whats that? foreground: 'white',
muted: '#ffffff50',
caret: 'white', caret: 'white',
selection: 'rgba(128, 203, 196, 0.5)', selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626', selectionMatch: '#036dd626',

View file

@ -11,6 +11,7 @@ export const settings = {
background: hex[0], background: hex[0],
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[2], foreground: hex[2],
muted: hex[3],
selection: hex[3], selection: hex[3],
selectionMatch: hex[0], selectionMatch: hex[0],
gutterBackground: hex[0], gutterBackground: hex[0],

View file

@ -9,6 +9,7 @@ export const settings = {
background: '#242424', background: '#242424',
lineBackground: '#24242499', lineBackground: '#24242499',
foreground: '#f8f8f2', foreground: '#f8f8f2',
muted: '#f8f8f250',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)', selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)', selectionMatch: 'rgba(255, 255, 255, 0.2)',
@ -23,6 +24,7 @@ export default createTheme({
settings: { settings: {
background: '#242424', background: '#242424',
foreground: '#f8f8f2', foreground: '#f8f8f2',
muted: '#f8f8f250',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)', selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)', selectionMatch: 'rgba(255, 255, 255, 0.2)',

View file

@ -11,6 +11,7 @@ export const settings = {
background: '#282a36', background: '#282a36',
lineBackground: '#282a3699', lineBackground: '#282a3699',
foreground: '#f8f8f2', foreground: '#f8f8f2',
muted: '#f8f8f250',
caret: '#f8f8f0', caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)', selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)', selectionMatch: 'rgba(255, 255, 255, 0.2)',
@ -27,6 +28,7 @@ export default createTheme({
settings: { settings: {
background: '#282a36', background: '#282a36',
foreground: '#f8f8f2', foreground: '#f8f8f2',
muted: '#f8f8f250',
caret: '#f8f8f0', caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)', selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)', selectionMatch: 'rgba(255, 255, 255, 0.2)',

View file

@ -10,6 +10,7 @@ export const settings = {
background: '#2a2734', background: '#2a2734',
lineBackground: '#2a273499', lineBackground: '#2a273499',
foreground: '#eeebff', foreground: '#eeebff',
muted: '#eeebff50',
caret: '#ffad5c', caret: '#ffad5c',
selection: 'rgba(255, 255, 255, 0.1)', selection: 'rgba(255, 255, 255, 0.1)',
gutterBackground: '#2a2734', gutterBackground: '#2a2734',
@ -22,6 +23,7 @@ export default createTheme({
settings: { settings: {
background: '#2a2734', background: '#2a2734',
foreground: '#6c6783', foreground: '#6c6783',
muted: '#eeebff50',
caret: '#ffad5c', caret: '#ffad5c',
selection: '#9a86fd', selection: '#9a86fd',
selectionMatch: '#9a86fd', selectionMatch: '#9a86fd',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#fff', background: '#fff',
lineBackground: '#ffffff99', lineBackground: '#ffffff99',
foreground: '#000', foreground: '#000',
muted: '#00000050',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#d7d4f0', selection: '#d7d4f0',
selectionMatch: '#d7d4f0', selectionMatch: '#d7d4f0',
@ -20,6 +21,7 @@ export default createTheme({
settings: { settings: {
background: '#fff', background: '#fff',
foreground: '#000', foreground: '#000',
muted: '#00000050',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#d7d4f0', selection: '#d7d4f0',
selectionMatch: '#d7d4f0', selectionMatch: '#d7d4f0',

View file

@ -23,6 +23,7 @@ export const settings = {
background: hex[0], background: hex[0],
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[10], foreground: hex[10],
muted: hex[7],
selection: hex[8], selection: hex[8],
selectionMatch: hex[0], selectionMatch: hex[0],
gutterBackground: hex[3], gutterBackground: hex[3],

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#0d1117', background: '#0d1117',
lineBackground: '#0d111799', lineBackground: '#0d111799',
foreground: '#c9d1d9', foreground: '#c9d1d9',
muted: '#c9d1d950',
caret: '#c9d1d9', caret: '#c9d1d9',
selection: '#003d73', selection: '#003d73',
selectionMatch: '#003d73', selectionMatch: '#003d73',
@ -16,6 +17,7 @@ export default createTheme({
settings: { settings: {
background: '#0d1117', background: '#0d1117',
foreground: '#c9d1d9', foreground: '#c9d1d9',
muted: '#c9d1d950',
caret: '#c9d1d9', caret: '#c9d1d9',
selection: '#003d73', selection: '#003d73',
selectionMatch: '#003d73', selectionMatch: '#003d73',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#fff', background: '#fff',
lineBackground: '#ffffff99', lineBackground: '#ffffff99',
foreground: '#24292e', foreground: '#24292e',
muted: '#24292e50',
selection: '#BBDFFF', selection: '#BBDFFF',
selectionMatch: '#BBDFFF', selectionMatch: '#BBDFFF',
gutterBackground: '#fff', gutterBackground: '#fff',
@ -17,6 +18,7 @@ export default createTheme({
settings: { settings: {
background: '#fff', background: '#fff',
foreground: '#24292e', foreground: '#24292e',
muted: '#24292e50',
selection: '#BBDFFF', selection: '#BBDFFF',
selectionMatch: '#BBDFFF', selectionMatch: '#BBDFFF',
gutterBackground: '#fff', gutterBackground: '#fff',

View file

@ -13,6 +13,7 @@ export const settings = {
background: hex[0], background: hex[0],
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[2], foreground: hex[2],
muted: hex[2] + '50',
selection: hex[4], selection: hex[4],
selectionMatch: hex[0], selectionMatch: hex[0],
gutterBackground: hex[0], gutterBackground: hex[0],

View file

@ -10,6 +10,7 @@ export const settings = {
background: '#282828', background: '#282828',
lineBackground: '#28282899', lineBackground: '#28282899',
foreground: '#ebdbb2', foreground: '#ebdbb2',
muted: '#ebdbb250',
caret: '#ebdbb2', caret: '#ebdbb2',
selection: '#bdae93', selection: '#bdae93',
selectionMatch: '#bdae93', selectionMatch: '#bdae93',
@ -23,6 +24,7 @@ export default createTheme({
settings: { settings: {
background: '#282828', background: '#282828',
foreground: '#ebdbb2', foreground: '#ebdbb2',
muted: '#ebdbb250',
caret: '#ebdbb2', caret: '#ebdbb2',
selection: '#b99d555c', selection: '#b99d555c',
selectionMatch: '#b99d555c', selectionMatch: '#b99d555c',

View file

@ -11,6 +11,7 @@ export const settings = {
background: '#fbf1c7', background: '#fbf1c7',
lineBackground: '#fbf1c799', lineBackground: '#fbf1c799',
foreground: '#3c3836', foreground: '#3c3836',
muted: '#3c383650',
caret: '#af3a03', caret: '#af3a03',
selection: '#ebdbb2', selection: '#ebdbb2',
selectionMatch: '#bdae93', selectionMatch: '#bdae93',
@ -25,6 +26,7 @@ export default createTheme({
settings: { settings: {
background: '#fbf1c7', background: '#fbf1c7',
foreground: '#3c3836', foreground: '#3c3836',
muted: '#3c383650',
caret: '#af3a03', caret: '#af3a03',
selection: '#bdae9391', selection: '#bdae9391',
selectionMatch: '#bdae9391', selectionMatch: '#bdae9391',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#212121', background: '#212121',
lineBackground: '#21212199', lineBackground: '#21212199',
foreground: '#bdbdbd', foreground: '#bdbdbd',
muted: '#bdbdbd50',
caret: '#a0a4ae', caret: '#a0a4ae',
selection: '#d7d4f0', selection: '#d7d4f0',
selectionMatch: '#d7d4f0', selectionMatch: '#d7d4f0',
@ -19,6 +20,7 @@ export default createTheme({
settings: { settings: {
background: '#212121', background: '#212121',
foreground: '#bdbdbd', foreground: '#bdbdbd',
muted: '#bdbdbd50',
caret: '#a0a4ae', caret: '#a0a4ae',
selection: '#d7d4f063', selection: '#d7d4f063',
selectionMatch: '#d7d4f063', selectionMatch: '#d7d4f063',

View file

@ -5,7 +5,8 @@ export const settings = {
light: true, light: true,
background: '#FAFAFA', background: '#FAFAFA',
lineBackground: '#FAFAFA99', lineBackground: '#FAFAFA99',
foreground: '#90A4AE', foreground: '#6182B8',
muted: '#6182B850',
caret: '#272727', caret: '#272727',
selection: '#80CBC440', selection: '#80CBC440',
selectionMatch: '#FAFAFA', selectionMatch: '#FAFAFA',
@ -19,6 +20,7 @@ export default createTheme({
settings: { settings: {
background: '#FAFAFA', background: '#FAFAFA',
foreground: '#90A4AE', foreground: '#90A4AE',
muted: '#6182B850',
caret: '#272727', caret: '#272727',
selection: '#80CBC440', selection: '#80CBC440',
selectionMatch: '#80CBC440', selectionMatch: '#80CBC440',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#272822', background: '#272822',
lineBackground: '#27282299', lineBackground: '#27282299',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#49483E', selection: '#49483E',
selectionMatch: '#49483E', selectionMatch: '#49483E',
@ -18,6 +19,7 @@ export default createTheme({
settings: { settings: {
background: '#272822', background: '#272822',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#49483E', selection: '#49483E',
selectionMatch: '#49483E', selectionMatch: '#49483E',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#f2f1f8', background: '#f2f1f8',
lineBackground: '#f2f1f899', lineBackground: '#f2f1f899',
foreground: '#0c006b', foreground: '#0c006b',
muted: '#0c006b50',
caret: '#5c49e9', caret: '#5c49e9',
selection: '#d5d1f2', selection: '#d5d1f2',
selectionMatch: '#d5d1f2', selectionMatch: '#d5d1f2',
@ -19,6 +20,7 @@ export default createTheme({
settings: { settings: {
background: '#f2f1f8', background: '#f2f1f8',
foreground: '#0c006b', foreground: '#0c006b',
muted: '#0c006b50',
caret: '#5c49e9', caret: '#5c49e9',
selection: '#d5d1f2', selection: '#d5d1f2',
selectionMatch: '#d5d1f2', selectionMatch: '#d5d1f2',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#2e3440', background: '#2e3440',
lineBackground: '#2e344099', lineBackground: '#2e344099',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#3b4252', selection: '#3b4252',
selectionMatch: '#e5e9f0', selectionMatch: '#e5e9f0',
@ -20,6 +21,7 @@ export default createTheme({
settings: { settings: {
background: '#2e3440', background: '#2e3440',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FFFFFF', caret: '#FFFFFF',
selection: '#00000073', selection: '#00000073',
selectionMatch: '#00000073', selectionMatch: '#00000073',

View file

@ -13,6 +13,7 @@ export const settings = {
background: hex[0], background: hex[0],
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[2], foreground: hex[2],
muted: hex[2] + '50',
selection: hex[4], selection: hex[4],
selectionMatch: hex[0], selectionMatch: hex[0],
gutterBackground: hex[0], gutterBackground: hex[0],

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#002b36', background: '#002b36',
lineBackground: '#002b3699', lineBackground: '#002b3699',
foreground: '#93a1a1', foreground: '#93a1a1',
muted: '#93a1a150',
caret: '#839496', caret: '#839496',
selection: '#173541', selection: '#173541',
selectionMatch: '#aafe661a', selectionMatch: '#aafe661a',
@ -45,6 +46,7 @@ export default createTheme({
settings: { settings: {
background: c.background, background: c.background,
foreground: c.foreground, foreground: c.foreground,
muted: c.muted,
caret: c.cursor, caret: c.cursor,
selection: c.selection, selection: c.selection,
selectionMatch: c.selection, selectionMatch: c.selection,

View file

@ -8,6 +8,7 @@ export const settings = {
background: '#fdf6e3', background: '#fdf6e3',
lineBackground: '#fdf6e399', lineBackground: '#fdf6e399',
foreground: '#657b83', foreground: '#657b83',
muted: '#657b8350',
caret: '#586e75', caret: '#586e75',
selection: '#dfd9c8', selection: '#dfd9c8',
selectionMatch: '#dfd9c8', selectionMatch: '#dfd9c8',
@ -19,6 +20,7 @@ export const settings = {
const c = { const c = {
background: '#FDF6E3', background: '#FDF6E3',
foreground: '#657B83', foreground: '#657B83',
muted: '#657b8350',
selection: '#EEE8D5', selection: '#EEE8D5',
selectionMatch: '#EEE8D5', selectionMatch: '#EEE8D5',
cursor: '#657B83', cursor: '#657B83',

View file

@ -13,6 +13,7 @@ export const settings = {
background: '#000000', background: '#000000',
lineBackground: 'transparent', lineBackground: 'transparent',
foreground: hex[4], foreground: hex[4],
muted: hex[6],
selection: hex[6], selection: hex[6],
gutterBackground: hex[0], gutterBackground: hex[0],
gutterForeground: hex[5], gutterForeground: hex[5],

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#222', background: '#222',
lineBackground: '#22222299', lineBackground: '#22222299',
foreground: '#fff', foreground: '#fff',
muted: '#ffffff50',
caret: '#ffcc00', caret: '#ffcc00',
selection: 'rgba(128, 203, 196, 0.5)', selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626', selectionMatch: '#036dd626',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#303841', background: '#303841',
lineBackground: '#30384199', lineBackground: '#30384199',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FBAC52', caret: '#FBAC52',
selection: '#4C5964', selection: '#4C5964',
selectionMatch: '#3A546E', selectionMatch: '#3A546E',
@ -18,6 +19,7 @@ export default createTheme({
settings: { settings: {
background: '#303841', background: '#303841',
foreground: '#FFFFFF', foreground: '#FFFFFF',
muted: '#FFFFFF50',
caret: '#FBAC52', caret: '#FBAC52',
selection: '#4C5964', selection: '#4C5964',
selectionMatch: '#3A546E', selectionMatch: '#3A546E',

View file

@ -9,7 +9,8 @@ let colorD = '#f8fc55';
export const settings = { export const settings = {
background: '#000000', background: '#000000',
foreground: colorA, // whats that? foreground: colorA,
muted: colorA + '50',
caret: colorC, caret: colorC,
selection: colorD, selection: colorD,
selectionMatch: colorA, selectionMatch: colorA,

View file

@ -4,7 +4,8 @@ import { createTheme } from './theme-helper.mjs';
export const settings = { export const settings = {
background: '#24283b', background: '#24283b',
lineBackground: '#24283b99', lineBackground: '#24283b99',
foreground: '#7982a9', foreground: '#f9f2f9',
muted: '#f9f2f950',
caret: '#c0caf5', caret: '#c0caf5',
selection: '#6f7bb630', selection: '#6f7bb630',
selectionMatch: '#1f2335', selectionMatch: '#1f2335',
@ -18,7 +19,8 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings: { settings: {
background: '#24283b', background: '#24283b',
foreground: '#7982a9', foreground: '#f9f2f9',
muted: '#f9f2f950',
caret: '#c0caf5', caret: '#c0caf5',
selection: '#6f7bb630', selection: '#6f7bb630',
selectionMatch: '#343b5f', selectionMatch: '#343b5f',

View file

@ -4,7 +4,8 @@ import { createTheme } from './theme-helper.mjs';
export const settings = { export const settings = {
background: '#1a1b26', background: '#1a1b26',
lineBackground: '#1a1b2699', lineBackground: '#1a1b2699',
foreground: '#787c99', foreground: '#f8fcf9',
muted: '#f8fcf950',
caret: '#c0caf5', caret: '#c0caf5',
selection: '#515c7e40', selection: '#515c7e40',
selectionMatch: '#16161e', selectionMatch: '#16161e',
@ -18,7 +19,8 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings: { settings: {
background: '#1a1b26', background: '#1a1b26',
foreground: '#787c99', foreground: '#f8fcf9',
muted: '#f8fcf950',
caret: '#c0caf5', caret: '#c0caf5',
selection: '#515c7e40', selection: '#515c7e40',
selectionMatch: '#16161e', selectionMatch: '#16161e',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#e1e2e7', background: '#e1e2e7',
lineBackground: '#e1e2e799', lineBackground: '#e1e2e799',
foreground: '#3760bf', foreground: '#3760bf',
muted: '#3760bf50',
caret: '#3760bf', caret: '#3760bf',
selection: '#99a7df', selection: '#99a7df',
selectionMatch: '#99a7df', selectionMatch: '#99a7df',
@ -20,6 +21,7 @@ export default createTheme({
settings: { settings: {
background: '#e1e2e7', background: '#e1e2e7',
foreground: '#3760bf', foreground: '#3760bf',
muted: '#3760bf50',
caret: '#3760bf', caret: '#3760bf',
selection: '#99a7df', selection: '#99a7df',
selectionMatch: '#99a7df', selectionMatch: '#99a7df',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#1e1e1e', background: '#1e1e1e',
lineBackground: '#1e1e1e99', lineBackground: '#1e1e1e99',
foreground: '#fff', foreground: '#fff',
muted: '#ffffff50',
caret: '#c6c6c6', caret: '#c6c6c6',
selection: '#6199ff2f', selection: '#6199ff2f',
selectionMatch: '#72a1ff59', selectionMatch: '#72a1ff59',
@ -19,6 +20,7 @@ export default createTheme({
settings: { settings: {
background: '#1e1e1e', background: '#1e1e1e',
foreground: '#fff', foreground: '#fff',
muted: '#ffffff50',
caret: '#c6c6c6', caret: '#c6c6c6',
selection: '#6199ff2f', selection: '#6199ff2f',
selectionMatch: '#72a1ff59', selectionMatch: '#72a1ff59',

View file

@ -5,6 +5,7 @@ export const settings = {
background: '#ffffff', background: '#ffffff',
lineBackground: '#ffffff50', lineBackground: '#ffffff50',
foreground: '#383a42', foreground: '#383a42',
muted: '#383a4250',
caret: '#000', caret: '#000',
selection: '#add6ff', selection: '#add6ff',
selectionMatch: '#a8ac94', selectionMatch: '#a8ac94',
@ -20,6 +21,7 @@ export default createTheme({
settings: { settings: {
background: '#ffffff', background: '#ffffff',
foreground: '#383a42', foreground: '#383a42',
muted: '#383a4250',
caret: '#000', caret: '#000',
selection: '#add6ff', selection: '#add6ff',
selectionMatch: '#a8ac94', selectionMatch: '#a8ac94',

View file

@ -2,7 +2,8 @@ import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from './theme-helper.mjs';
export const settings = { export const settings = {
background: 'white', background: 'white',
foreground: 'black', // whats that? foreground: 'black',
muted: '#00000050',
caret: 'black', caret: 'black',
selection: 'rgba(128, 203, 196, 0.5)', selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#ffffff26', selectionMatch: '#ffffff26',

View file

@ -6,6 +6,7 @@ export const settings = {
background: '#fff', background: '#fff',
lineBackground: '#ffffff99', lineBackground: '#ffffff99',
foreground: '#3D3D3D', foreground: '#3D3D3D',
muted: '#3D3D3D50',
selection: '#BBDFFF', selection: '#BBDFFF',
selectionMatch: '#BBDFFF', selectionMatch: '#BBDFFF',
gutterBackground: '#fff', gutterBackground: '#fff',
@ -18,6 +19,7 @@ export default createTheme({
settings: { settings: {
background: '#fff', background: '#fff',
foreground: '#3D3D3D', foreground: '#3D3D3D',
muted: '#3D3D3D50',
selection: '#BBDFFF', selection: '#BBDFFF',
selectionMatch: '#BBDFFF', selectionMatch: '#BBDFFF',
gutterBackground: '#fff', gutterBackground: '#fff',

View file

@ -33,6 +33,7 @@ const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL
<!-- the following variables are just a fallback to make sure everything is readable without JS --> <!-- the following variables are just a fallback to make sure everything is readable without JS -->
<style is:global> <style is:global>
:root { :root {
color-scheme: dark;
--background: #222; --background: #222;
--lineBackground: #22222299; --lineBackground: #22222299;
--foreground: #fff; --foreground: #fff;

View file

@ -32,6 +32,7 @@ const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL
<!-- the following variables are just a fallback to make sure everything is readable without JS --> <!-- the following variables are just a fallback to make sure everything is readable without JS -->
<style is:global> <style is:global>
:root { :root {
color-scheme: dark;
--background: #222; --background: #222;
--lineBackground: #22222299; --lineBackground: #22222299;
--foreground: #fff; --foreground: #fff;

View file

@ -1,15 +1,3 @@
:root {
--background: #222;
--lineBackground: #22222299;
--foreground: #fff;
--caret: #ffcc00;
--selection: rgba(128, 203, 196, 0.5);
--selectionMatch: #036dd626;
--lineHighlight: #00000050;
--gutterBackground: transparent;
--gutterForeground: #8a919966;
}
.darken::before { .darken::before {
content: ' '; content: ' ';
position: fixed; position: fixed;

View file

@ -2,149 +2,115 @@ import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon'; import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon';
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
import { useSettings, setIsZen } from '../../settings.mjs'; import { useSettings, setIsZen } from '../../settings.mjs';
import { StrudelIcon } from '@src/repl/components/icons/StrudelIcon';
import '../Repl.css'; import '../Repl.css';
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 Header({ context, embedded = false }) { export function Header({ context, isEmbedded = false }) {
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } = const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShare } = context;
context;
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily } = 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-sm select-none min-h-10',
!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 justify-between',
isEmbedded ? 'flex' : 'md:flex', 'flex items-center',
)} )}
style={{ fontFamily }} style={{ fontFamily }}
> >
<div className="px-4 flex space-x-2 md:pt-0 select-none"> <div className={cx(isEmbedded ? 'flex' : 'sm:flex', 'w-full sm:justify-between')}>
<h1 <div className="px-3 pt-1 flex space-x-2 sm:pt-0 select-none">
onClick={() => { <h1
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
}}
className={cx(
isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
'text-foreground font-bold flex space-x-2 items-center',
)}
>
<div
className={cx(
'mt-[1px]',
started && !isCSSAnimationDisabled && 'animate-spin',
'cursor-pointer text-blue-500',
isZen && 'fixed top-2 right-4',
)}
onClick={() => { onClick={() => {
if (!isEmbedded) { if (isEmbedded) window.open(window.location.href.replace('embed', ''));
setIsZen(!isZen);
}
}} }}
>
<span className="block text-foreground rotate-90"></span>
</div>
{!isZen && (
<div className="space-x-2">
<span className="">strudel</span>
<span className="text-sm font-medium">REPL</span>
{!isEmbedded && isButtonRowHidden && (
<a href={`${baseNoTrailing}/learn`} className="text-sm opacity-25 font-medium">
DOCS
</a>
)}
</div>
)}
</h1>
</div>
{!isZen && !isButtonRowHidden && (
<div className="flex max-w-full overflow-auto text-foreground px-1 md:px-2">
<button
onClick={handleTogglePlay}
title={started ? 'stop' : 'play'}
className={cx( className={cx(
!isEmbedded ? 'p-2' : 'px-2', isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
'hover:opacity-50', 'text-foreground font-bold flex space-x-2 items-center',
!started && !isCSSAnimationDisabled && 'animate-pulse',
)} )}
> >
{!pending ? ( <div
<span className={cx('flex items-center space-x-2')}>
{started ? <StopCircleIcon className="w-6 h-6" /> : <PlayCircleIcon className="w-6 h-6" />}
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
</span>
) : (
<>loading...</>
)}
</button>
<button
onClick={handleEvaluate}
title="update"
className={cx(
'flex items-center space-x-1',
!isEmbedded ? 'p-2' : 'px-2',
!isDirty || !activeCode ? 'opacity-50' : 'hover:opacity-50',
)}
>
{!isEmbedded && <span>update</span>}
</button>
{/* !isEmbedded && (
<button
title="shuffle"
className="hover:opacity-50 p-2 flex items-center space-x-1"
onClick={handleShuffle}
>
<span> shuffle</span>
</button>
) */}
{!isEmbedded && (
<button
title="share"
className={cx( className={cx(
'cursor-pointer hover:opacity-50 flex items-center space-x-1', 'mt-[1px]',
!isEmbedded ? 'p-2' : 'px-2', started && !isCSSAnimationDisabled && 'animate-spin',
'cursor-pointer text-blue-500',
isZen && 'fixed top-2 right-4',
)} )}
onClick={handleShare} onClick={() => {
if (!isEmbedded) {
setIsZen(!isZen);
}
}}
> >
<span>share</span> <span className="block text-foreground rotate-90">
</button> <StrudelIcon className="w-5 h-5 fill-foreground" />
)} </span>
{!isEmbedded && ( </div>
<a {!isZen && (
title="learn" <div className="space-x-2">
href={`${baseNoTrailing}/workshop/getting-started/`} <span className="">strudel</span>
className={cx('hover:opacity-50 flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')} <span className="text-sm font-medium">REPL</span>
> {!isEmbedded && isButtonRowHidden && (
<span>learn</span> <a href={`${baseNoTrailing}/learn`} className="text-sm opacity-25 font-medium">
</a> DOCS
)} </a>
{/* {isEmbedded && ( )}
<button className={cx('hover:opacity-50 px-2')}> </div>
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL"> )}
🚀 </h1>
</a>
</button>
)}
{isEmbedded && (
<button className={cx('hover:opacity-50 px-2')}>
<a
onClick={() => {
window.location.href = initialUrl;
window.location.reload();
}}
title="Reset"
>
💔
</a>
</button>
)} */}
</div> </div>
)} {!isZen && !isButtonRowHidden && (
<div className="flex max-w-full overflow-auto text-foreground px-3 h-10">
<button
onClick={handleTogglePlay}
title={started ? 'stop' : 'play'}
className={cx('hover:opacity-50', !started && !isCSSAnimationDisabled && 'animate-pulse')}
>
{!pending ? (
<span className={cx('flex items-center space-x-2')}>
{started ? <StopCircleIcon className="w-5 h-5" /> : <PlayCircleIcon className="w-5 h-5" />}
{!isEmbedded && <span>{started ? 'stop' : 'play'}</span>}
</span>
) : (
<>loading...</>
)}
</button>
<button
onClick={handleEvaluate}
title="update"
className={cx(
'flex items-center space-x-1 px-2',
!isDirty || !activeCode ? 'opacity-50' : 'hover:opacity-50',
)}
>
{!isEmbedded && <span>update</span>}
</button>
{!isEmbedded && (
<button
title="share"
className={cx('cursor-pointer hover:opacity-50 flex items-center space-x-1 px-2')}
onClick={handleShare}
>
<span>share</span>
</button>
)}
{!isEmbedded && (
<a
title="learn"
href={`${baseNoTrailing}/workshop/getting-started/`}
className={cx('hover:opacity-50 flex items-center space-x-1', !isEmbedded ? 'p-2' : 'px-2')}
>
<span>learn</span>
</a>
)}
</div>
)}
</div>
</header> </header>
); );
} }

View file

@ -1,5 +1,5 @@
import Loader from '@src/repl/components/Loader'; import Loader from '@src/repl/components/Loader';
import { HorizontalPanel, VerticalPanel } from '@src/repl/components/panel/Panel'; import { HorizontalPanel, VerticalPanel, PanelToggle } from '@src/repl/components/panel/Panel';
import { Code } from '@src/repl/components/Code'; import { Code } from '@src/repl/components/Code';
import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage'; import UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage';
import { Header } from './Header'; import { Header } from './Header';
@ -14,14 +14,17 @@ export default function ReplEditor(Props) {
const { containerRef, editorRef, error, init, pending } = context; const { containerRef, editorRef, error, init, pending } = context;
const settings = useSettings(); const settings = useSettings();
const { panelPosition, isZen } = settings; const { panelPosition, isZen } = settings;
const isEmbedded = typeof window !== 'undefined' && window.location !== window.parent.location;
return ( return (
<div className="h-full flex flex-col relative" {...editorProps}> <div className="h-full flex flex-col relative" {...editorProps}>
<Loader active={pending} /> <Loader active={pending} />
<Header context={context} /> <Header context={context} isEmbedded={isEmbedded} />
<div className="grow flex relative overflow-hidden"> <div className="grow flex relative overflow-hidden">
<Code containerRef={containerRef} editorRef={editorRef} init={init} /> <Code containerRef={containerRef} editorRef={editorRef} init={init} />
{!isZen && panelPosition === 'right' && <VerticalPanel context={context} />} {!isZen && panelPosition === 'right' && <VerticalPanel context={context} />}
<PanelToggle isEmbedded={isEmbedded} isZen={isZen} />
</div> </div>
<UserFacingErrorMessage error={error} /> <UserFacingErrorMessage error={error} />
{!isZen && panelPosition === 'bottom' && <HorizontalPanel context={context} />} {!isZen && panelPosition === 'bottom' && <HorizontalPanel context={context} />}

View file

@ -2,7 +2,7 @@ import cx from '@src/cx.mjs';
export function ActionButton({ children, label, labelIsHidden, className, ...buttonProps }) { export function ActionButton({ children, label, labelIsHidden, className, ...buttonProps }) {
return ( return (
<button className={cx('hover:opacity-50 text-nowrap w-fit', className)} title={label} {...buttonProps}> <button className={cx('hover:opacity-50 text-nowrap w-fit text-sm ', className)} title={label} {...buttonProps}>
{labelIsHidden !== true && label} {labelIsHidden !== true && label}
{children} {children}
</button> </button>
@ -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

@ -0,0 +1,13 @@
// Source: https://commons.wikimedia.org/wiki/File:CHAM_PUNCTUATION_SPIRAL.svg
// License: SIL Open Font License, Version 1.1. The license text is available at https://openfontlicense.org/open-font-license-official-text/
export function StrudelIcon({ className = '' }) {
return (
<svg className={className} width="100%" height="100%" viewBox="0 0 213 213">
<g>
<g id="_1" serif:id="1">
<path d="M199.905,102.467c-0,17.959 -3.695,33.45 -11.078,46.468c-7.369,13.024 -17.9,23.079 -31.586,30.173c-13.673,7.093 -29.994,10.64 -48.961,10.64c-19.964,0 -37.183,-3.874 -51.66,-11.617c-14.482,-7.749 -25.592,-18.775 -33.334,-33.103c-7.749,-14.322 -11.617,-31.407 -11.617,-51.248l17.143,-0c-0,16.95 3.187,31.503 9.561,43.666c6.373,12.15 15.485,21.48 27.346,27.989c11.874,6.509 26.061,9.766 42.561,9.766c15.485,0 28.798,-2.898 39.94,-8.687c11.154,-5.789 19.693,-14.11 25.624,-24.956c5.943,-10.858 8.918,-23.812 8.918,-38.86c-0,-20.85 -5.5,-37.202 -16.5,-49.063c-11,-11.874 -26.344,-17.811 -46.031,-17.811c-17.515,-0 -31.266,4.883 -41.251,14.649c-9.991,9.767 -14.983,23.337 -14.983,40.711c-0,15.781 4.015,28.13 12.054,37.035c8.031,8.893 19.07,13.339 33.103,13.339c12.452,0 22.186,-3.431 29.196,-10.306c7.023,-6.888 10.538,-16.333 10.538,-28.348c-0,-10.281 -2.57,-18.415 -7.711,-24.416c-5.14,-6.014 -12.413,-9.021 -21.82,-9.021c-7.813,-0 -13.93,2.178 -18.351,6.528c-4.407,4.337 -6.605,10.197 -6.605,17.579c0,1.44 0.064,2.815 0.206,4.112c4.485,-7.363 11.141,-11.051 19.97,-11.051c5.5,-0 9.875,1.561 13.133,4.678c3.27,3.103 4.909,7.324 4.909,12.67c-0,5.796 -1.966,10.506 -5.886,14.136c-3.906,3.617 -9.265,5.423 -16.063,5.423c-8.533,-0 -15.337,-2.814 -20.407,-8.456c-5.076,-5.654 -7.607,-13.114 -7.607,-22.386c-0,-11.135 3.431,-19.957 10.306,-26.472c6.888,-6.528 16.121,-9.792 27.706,-9.792c13.467,0 24.03,4.164 31.689,12.491c7.672,8.327 11.515,19.584 11.515,33.771c-0,16.057 -4.884,28.753 -14.65,38.089c-9.767,9.343 -23.195,14.008 -40.274,14.008c-12.594,-0 -23.491,-2.603 -32.692,-7.814c-9.188,-5.204 -16.243,-12.625 -21.178,-22.257c-4.921,-9.625 -7.376,-21.023 -7.376,-34.182c0,-14.342 2.93,-26.64 8.79,-36.907c5.873,-10.281 14.271,-18.203 25.187,-23.774c10.93,-5.584 23.928,-8.379 38.989,-8.379c16.359,0 30.469,3.258 42.33,9.767c11.874,6.515 20.985,15.819 27.346,27.911c6.374,12.08 9.561,26.518 9.561,43.307Zm-86.408,-6.939c-7.235,-0 -11.867,4.491 -13.904,13.467c2.756,3.033 6.528,4.549 11.308,4.549c7.659,0 11.489,-3.11 11.489,-9.329c-0,-2.757 -0.797,-4.89 -2.39,-6.4c-1.581,-1.523 -3.746,-2.287 -6.503,-2.287Z" />
</g>
</g>
</svg>
);
}

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

@ -7,7 +7,7 @@ export function ConsoleTab() {
const log = useStore($strudel_log_history); const log = useStore($strudel_log_history);
const { fontFamily } = useSettings(); const { fontFamily } = useSettings();
return ( return (
<div id="console-tab" className="break-all w-full first-line:text-sm p-2 h-full" style={{ fontFamily }}> <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 className="bg-background h-full w-full overflow-auto space-y-1 p-2 rounded-md">
{log.map((l, i) => { {log.map((l, i) => {
const message = linkify(l.message); const message = linkify(l.message);

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

@ -2,14 +2,14 @@ import cx from '@src/cx.mjs';
export function ButtonGroup({ value, onChange, items }) { export function ButtonGroup({ value, onChange, items }) {
return ( return (
<div className="flex max-w-lg"> <div className="flex max-w-lg space-x-0 text-sm">
{Object.entries(items).map(([key, label], i, arr) => ( {Object.entries(items).map(([key, label], i, arr) => (
<button <button
key={key} key={key}
id={key} id={key}
onClick={() => onChange(key)} onClick={() => onChange(key)}
className={cx( className={cx(
'px-2 border-b h-8 whitespace-nowrap', 'px-2 border-b-2 h-8 whitespace-nowrap',
// 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',

View file

@ -1,5 +1,5 @@
import cx from '@src/cx.mjs'; import cx from '@src/cx.mjs';
import { setPanelPinned, setActiveFooter as setTab, setIsPanelOpened, useSettings } from '../../../settings.mjs'; import { setActiveFooter as setTab, setIsPanelOpened, useSettings } from '../../../settings.mjs';
import { ConsoleTab } from './ConsoleTab'; import { ConsoleTab } from './ConsoleTab';
import { FilesTab } from './FilesTab'; import { FilesTab } from './FilesTab';
import { Reference } from './Reference'; import { Reference } from './Reference';
@ -8,33 +8,44 @@ import { SoundsTab } from './SoundsTab';
import { useLogger } from '../useLogger'; import { useLogger } from '../useLogger';
import { WelcomeTab } from './WelcomeTab'; import { WelcomeTab } from './WelcomeTab';
import { PatternsTab } from './PatternsTab'; import { PatternsTab } from './PatternsTab';
import { ChevronLeftIcon, XMarkIcon } from '@heroicons/react/16/solid'; import { Bars3Icon, XMarkIcon } from '@heroicons/react/16/solid';
import ExportTab from './ExportTab'; import ExportTab from './ExportTab';
const TAURI = typeof window !== 'undefined' && window.__TAURI__; const TAURI = typeof window !== 'undefined' && window.__TAURI__;
export function HorizontalPanel({ context }) { function PanelCloseButton() {
const settings = useSettings(); const { isPanelOpen } = useSettings();
const { isPanelOpen, activeFooter: tab } = settings; return (
isPanelOpen && (
<button
onClick={() => setIsPanelOpened(false)}
className={cx('px-4 py-2 text-foreground hover:opacity-50')}
aria-label="Close Menu"
>
<XMarkIcon className="w-6 h-6" />
</button>
)
);
}
export function HorizontalPanel({ context }) {
const { isPanelOpen, activeFooter: tab } = useSettings();
return ( return (
<PanelNav <PanelNav
settings={settings} className={cx(
className={cx(isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-12 max-h-12', 'overflow-hidden flex flex-col')} isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-10 max-h-10',
'overflow-hidden flex flex-col relative ',
)}
> >
<div className="flex justify-between min-h-10 max-h-10 grid-cols-2 items-center">
<Tabs setTab={setTab} tab={tab} />
<PanelCloseButton />
</div>
{isPanelOpen && ( {isPanelOpen && (
<div className="flex h-full overflow-auto pr-10 "> <div className="flex h-full overflow-auto w-full">
<PanelContent context={context} tab={tab} /> <PanelContent context={context} tab={tab} />
</div> </div>
)} )}
<div className="absolute right-4 pt-4">
<PanelActionButton settings={settings} />
</div>
<div className="flex justify-between min-h-12 max-h-12 grid-cols-2 items-center">
<Tabs setTab={setTab} tab={tab} />
</div>
</PanelNav> </PanelNav>
); );
} }
@ -42,36 +53,24 @@ export function HorizontalPanel({ context }) {
export function VerticalPanel({ context }) { export function VerticalPanel({ context }) {
const settings = useSettings(); const settings = useSettings();
const { activeFooter: tab, isPanelOpen } = settings; const { activeFooter: tab, isPanelOpen } = settings;
if (!isPanelOpen) {
return;
}
return ( return (
<PanelNav <PanelNav
settings={settings} settings={settings}
className={cx(isPanelOpen ? `min-w-[min(600px,80vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12')} className={cx(isPanelOpen ? `min-w-[min(600px,100vw)] max-w-[min(600px,80vw)]` : 'min-w-12 max-w-12')}
> >
{isPanelOpen ? ( <div className={cx('flex flex-col h-full')}>
<div className={cx('flex flex-col h-full')}> <div className="flex justify-between w-full ">
<div className="flex justify-between w-full "> <Tabs setTab={setTab} tab={tab} />
<Tabs setTab={setTab} tab={tab} /> <PanelCloseButton />
<PanelActionButton settings={settings} />
</div>
<div className="overflow-auto h-full">
<PanelContent context={context} tab={tab} />
</div>
</div> </div>
) : (
<button <div className="overflow-auto h-full">
onClick={(e) => { <PanelContent context={context} tab={tab} />
setIsPanelOpened(true); </div>
}} </div>
aria-label="open menu panel"
className={cx(
'flex flex-col hover:bg-lineBackground items-center cursor-pointer justify-center w-full h-full',
)}
>
<ChevronLeftIcon className="text-foreground opacity-50 w-6 h-6" />
</button>
)}
</PanelNav> </PanelNav>
); );
} }
@ -89,8 +88,8 @@ if (TAURI) {
tabNames.files = 'files'; tabNames.files = 'files';
} }
function PanelNav({ children, className, settings, ...props }) { function PanelNav({ children, className, ...props }) {
const isHoverBehavior = settings.togglePanelTrigger === 'hover'; const settings = useSettings();
return ( return (
<nav <nav
onClick={() => { onClick={() => {
@ -98,16 +97,6 @@ function PanelNav({ children, className, settings, ...props }) {
setIsPanelOpened(true); setIsPanelOpened(true);
} }
}} }}
onMouseEnter={() => {
if (isHoverBehavior && !settings.isPanelOpen) {
setIsPanelOpened(true);
}
}}
onMouseLeave={() => {
if (isHoverBehavior && !settings.isPanelPinned) {
setIsPanelOpened(false);
}
}}
aria-label="Menu Panel" aria-label="Menu Panel"
className={cx('bg-lineHighlight group overflow-x-auto', className)} className={cx('bg-lineHighlight group overflow-x-auto', className)}
{...props} {...props}
@ -145,7 +134,7 @@ function PanelTab({ label, isSelected, onClick }) {
<button <button
onClick={onClick} onClick={onClick}
className={cx( className={cx(
'h-8 px-2 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',
isSelected ? 'border-foreground' : 'border-transparent', isSelected ? 'border-foreground' : 'border-transparent',
)} )}
> >
@ -154,65 +143,34 @@ function PanelTab({ label, isSelected, onClick }) {
</> </>
); );
} }
function Tabs({ setTab, tab, className }) { function Tabs({ className }) {
const { isPanelOpen, activeFooter: tab } = 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 items-center', className)}>
{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 && isPanelOpen} label={key} onClick={() => setTab(val)} />;
})} })}
</div> </div>
); );
} }
function PanelActionButton({ settings }) { export function PanelToggle({ isEmbedded, isZen }) {
const { togglePanelTrigger, isPanelPinned, isPanelOpen } = settings; const { panelPosition, isPanelOpen } = useSettings();
const isHoverBehavior = togglePanelTrigger === 'hover';
if (!isPanelOpen) {
return;
}
if (isHoverBehavior) {
return <PinButton pinned={isPanelPinned} />;
}
return <CloseButton onClick={() => setIsPanelOpened(false)} />;
}
function PinButton({ pinned }) {
return ( return (
<button !isEmbedded &&
onClick={() => setPanelPinned(!pinned)} !isZen &&
className={cx( panelPosition === 'right' && (
'text-foreground max-h-8 min-h-8 max-w-8 min-w-8 items-center justify-center p-1.5 group-hover:flex', <button
pinned ? 'flex' : 'hidden', title="share"
)} className={cx(
aria-label="Pin Menu Panel" '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 ',
> isPanelOpen && 'hidden',
<svg )}
stroke="currentColor" onClick={() => setIsPanelOpened(!isPanelOpen)}
fill={'currentColor'}
strokeWidth="0"
className="w-full h-full"
opacity={pinned ? 1 : '.3'}
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
> >
<path d="M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a6 6 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707s.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a6 6 0 0 1 1.013.16l3.134-3.133a3 3 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146"></path> <Bars3Icon className="w-6 h-6" />
</svg> </button>
</button> )
);
}
function CloseButton({ onClick }) {
return (
<button
onClick={onClick}
className={cx(
'text-foreground max-h-8 min-h-8 max-w-8 min-w-8 items-center justify-center p-1.5 group-hover:flex',
)}
aria-label="Close Menu"
>
<XMarkIcon />
</button>
); );
} }

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]);
@ -172,7 +172,7 @@ export function PatternsTab({ context }) {
/> />
</div> </div>
<div className="overflow-auto h-full bg-background p-2 rounded-md"> <div className="overflow-auto h-full bg-background p-2">
{/* {patternFilter === patternFilterName.user && ( */} {/* {patternFilter === patternFilterName.user && ( */}
<PatternButtons <PatternButtons
onClick={(id) => { onClick={(id) => {

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;
@ -128,14 +128,14 @@ export const Reference = memo(function Reference() {
{selectedTag && ( {selectedTag && (
<div className="w-72"> <div className="w-72">
<span <span
className="text-foreground border-2 border-gray-500 px-1 py-0.5 my-2 rounded-md cursor-pointer font-sans" className="text-foreground border border-muted px-1 py-0.5 my-2 cursor-pointer font-sans"
onClick={onSearchTagFilterClick} onClick={onSearchTagFilterClick}
> >
{selectedTag} {selectedTag}
</span> </span>
</div> </div>
)} )}
<div className="flex flex-col h-full overflow-y-auto gap-1.5 bg-background bg-opacity-50 rounded-md"> <div className="flex flex-col h-full overflow-y-auto gap-1.5 bg-background bg-opacity-50">
{searchVisibleFunctions.map((entry, i) => ( {searchVisibleFunctions.map((entry, i) => (
<Fragment key={`entry-${entry.name}`}> <Fragment key={`entry-${entry.name}`}>
<a <a
@ -174,8 +174,8 @@ export const Reference = memo(function Reference() {
<span key={t}> <span key={t}>
<a <a
className={[ className={[
'select-none text-white border-2 border-gray-500 px-1 py-0.5 my-2 cursor-pointer text-sm/8 rounded-md no-underline font-sans', 'select-none text-white border border-muted px-1 py-0.5 my-2 cursor-pointer text-sm/8 no-underline font-sans',
`${selectedTag === t ? 'bg-gray-500 text-black' : ''}`, `${selectedTag === t ? 'bg-muted text-foreground' : ''}`,
].join(' ')} ].join(' ')}
onClick={() => toggleTag(t)} onClick={() => toggleTag(t)}
> >
@ -191,7 +191,7 @@ export const Reference = memo(function Reference() {
{entry.name} {entry.name}
</h3> </h3>
{entry.tags && ( {entry.tags && (
<span className="ml-2 text-xs text-gray-400 border-2 border-gray-500 rounded-md px-1 py-0.5"> <span className="ml-2 text-xs text-foreground border border-muted px-1 py-0.5">
{entry.tags.join(', ')} {entry.tags.join(', ')}
</span> </span>
)} )}

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-muted 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 className="text-sm">
<input disabled={disabled} type="checkbox" checked={value} onChange={onChange} /> <input
className={cx(
'bg-background text-sm border border-muted 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>
@ -59,8 +96,8 @@ 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 text-sm">
<label>{label}</label> <label className="text-sm">{label}</label>
{children} {children}
</div> </div>
); );
@ -107,7 +144,6 @@ export function SettingsTab({ started }) {
panelPosition, panelPosition,
audioDeviceName, audioDeviceName,
audioEngineTarget, audioEngineTarget,
togglePanelTrigger,
maxPolyphony, maxPolyphony,
multiChannelOrbits, multiChannelOrbits,
isTabIndentationEnabled, isTabIndentationEnabled,
@ -178,7 +214,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}
@ -219,13 +255,6 @@ export function SettingsTab({ started }) {
items={{ bottom: 'Bottom', right: 'Right' }} items={{ bottom: 'Bottom', right: 'Right' }}
></ButtonGroup> ></ButtonGroup>
</FormItem> </FormItem>
<FormItem label="Open Panel on: ">
<ButtonGroup
value={togglePanelTrigger}
onChange={(value) => settingsMap.setKey('togglePanelTrigger', value)}
items={{ click: 'Click', hover: 'Hover' }}
/>
</FormItem>
<FormItem label="More Settings"> <FormItem label="More Settings">
<Checkbox <Checkbox
label="Enable bracket matching" label="Enable bracket matching"

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

@ -7,7 +7,7 @@ export function WelcomeTab({ context }) {
const { fontFamily } = useSettings(); const { fontFamily } = useSettings();
return ( 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 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
pieces in the browser! It is free and open-source and made for beginners and experts alike. To get started: pieces in the browser! It is free and open-source and made for beginners and experts alike. To get started:
@ -30,7 +30,7 @@ export function WelcomeTab({ context }) {
</a>{' '} </a>{' '}
to ask any questions, give feedback or just say hello. to ask any questions, give feedback or just say hello.
</p> </p>
<h3> about</h3> <h3>about</h3>
<p> <p>
strudel is a JavaScript version of{' '} strudel is a JavaScript version of{' '}
<a href="https://tidalcycles.org/" target="_blank"> <a href="https://tidalcycles.org/" target="_blank">

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}
/>
);
}

View file

@ -43,7 +43,6 @@ export const defaultSettings = {
panelPosition: 'right', panelPosition: 'right',
isPanelPinned: false, isPanelPinned: false,
isPanelOpen: true, isPanelOpen: true,
togglePanelTrigger: 'click', //click | hover
userPatterns: '{}', userPatterns: '{}',
prebakeScript: '', prebakeScript: '',
audioEngineTarget: audioEngineTargets.webaudio, audioEngineTarget: audioEngineTargets.webaudio,

View file

@ -24,6 +24,7 @@ module.exports = {
background: 'var(--background)', background: 'var(--background)',
lineBackground: 'var(--lineBackground)', lineBackground: 'var(--lineBackground)',
foreground: 'var(--foreground)', foreground: 'var(--foreground)',
muted: 'var(--muted)',
caret: 'var(--caret)', caret: 'var(--caret)',
selection: 'var(--selection)', selection: 'var(--selection)',
selectionMatch: 'var(--selectionMatch)', selectionMatch: 'var(--selectionMatch)',
@ -46,28 +47,28 @@ module.exports = {
'code::after': { 'code::after': {
content: 'none', content: 'none',
}, },
color: 'var(--foreground)', color: 'var(--foreground) !important',
a: { a: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
h1: { h1: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
h2: { h2: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
h3: { h3: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
h4: { h4: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
pre: { pre: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
background: 'var(--background)', background: 'var(--background) !important',
}, },
code: { code: {
color: 'var(--foreground)', color: 'var(--foreground) !important',
}, },
}, },
}, },