mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 06:19:33 -04:00
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:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"devToolbar": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -198,6 +198,7 @@ export function activateTheme(name) {
|
||||
const themeSettings = settings[name] || settings.strudelTheme;
|
||||
// set css variables
|
||||
themeStyle.innerHTML = `:root {
|
||||
color-scheme: ${themeSettings.light ? 'light' : 'dark'};
|
||||
${Object.entries(themeSettings)
|
||||
// important to override fallback
|
||||
.map(([key, value]) => `--${key}: ${value} !important;`)
|
||||
|
||||
+3
-1
@@ -17,13 +17,15 @@ export const settings = {
|
||||
background: 'white',
|
||||
lineBackground: 'transparent',
|
||||
foreground: deepPurple,
|
||||
muted: deepPurple + '50',
|
||||
caret: '#797977',
|
||||
selection: yellowPink,
|
||||
selectionMatch: '#2B323D',
|
||||
gutterBackground: grey,
|
||||
gutterBackground: pinkAccent,
|
||||
gutterForeground: lightGrey,
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: pinkAccent,
|
||||
light: true,
|
||||
};
|
||||
|
||||
export default createTheme({
|
||||
|
||||
+1
@@ -31,6 +31,7 @@ const palette = palettes['Sour Watermelon B'];
|
||||
export const settings = {
|
||||
background: palette[3],
|
||||
foreground: palette[1],
|
||||
muted: palette[1] + '50',
|
||||
caret: palette[0],
|
||||
selection: palette[0],
|
||||
selectionMatch: palette[1],
|
||||
|
||||
@@ -8,6 +8,7 @@ export const settings = {
|
||||
background: '#282b2e',
|
||||
lineBackground: '#282b2e99',
|
||||
foreground: '#a9b7c6',
|
||||
muted: '#a9b7c650',
|
||||
caret: '#00FF00',
|
||||
selection: '#343739',
|
||||
selectionMatch: '#343739',
|
||||
@@ -19,6 +20,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#282b2e',
|
||||
foreground: '#a9b7c6',
|
||||
muted: '#a9b7c650',
|
||||
caret: '#00FF00',
|
||||
selection: '#4e5254',
|
||||
selectionMatch: '#4e5254',
|
||||
|
||||
+1
@@ -12,6 +12,7 @@ export const settings = {
|
||||
background: hex[0],
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[1],
|
||||
muted: hex[2],
|
||||
selection: hex[2],
|
||||
selectionMatch: hex[0],
|
||||
gutterBackground: hex[0],
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ export const settings = {
|
||||
background: '#272C35',
|
||||
lineBackground: '#272C3599',
|
||||
foreground: 'hsl(220, 14%, 71%)',
|
||||
muted: 'hsl(220, 14%, 41%)',
|
||||
caret: '#797977',
|
||||
selection: '#ffffff30',
|
||||
selectionMatch: '#2B323D',
|
||||
@@ -25,6 +26,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#272C35',
|
||||
foreground: '#9d9b97',
|
||||
muted: 'hsl(220, 14%, 41%)',
|
||||
caret: '#797977',
|
||||
selection: '#3d4c64',
|
||||
selectionMatch: '#3d4c64',
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#21202e',
|
||||
lineBackground: '#21202e99',
|
||||
foreground: '#edecee',
|
||||
muted: '#edecee50',
|
||||
caret: '#a277ff',
|
||||
selection: '#3d375e7f',
|
||||
selectionMatch: '#3d375e7f',
|
||||
@@ -18,6 +19,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#21202e',
|
||||
foreground: '#edecee',
|
||||
muted: '#edecee50',
|
||||
caret: '#a277ff',
|
||||
selection: '#5a51898f',
|
||||
selectionMatch: '#5a51898f',
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#FFFFFF',
|
||||
lineBackground: '#FFFFFF99',
|
||||
foreground: '#000000',
|
||||
muted: '#00000050',
|
||||
caret: '#FBAC52',
|
||||
selection: '#FFD420',
|
||||
selectionMatch: '#FFD420',
|
||||
@@ -20,6 +21,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#FFFFFF',
|
||||
foreground: '#000000',
|
||||
muted: '#00000050',
|
||||
caret: '#FBAC52',
|
||||
selection: '#FFD420',
|
||||
selectionMatch: '#FFD420',
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@ import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from './theme-helper.mjs';
|
||||
export const settings = {
|
||||
background: 'black',
|
||||
foreground: 'white', // whats that?
|
||||
foreground: 'white',
|
||||
muted: '#ffffff50',
|
||||
caret: 'white',
|
||||
selection: '#ffffff20',
|
||||
selectionMatch: '#036dd626',
|
||||
|
||||
+2
-1
@@ -3,7 +3,8 @@ import { createTheme } from './theme-helper.mjs';
|
||||
export const settings = {
|
||||
background: '#051DB5',
|
||||
lineBackground: '#051DB550',
|
||||
foreground: 'white', // whats that?
|
||||
foreground: 'white',
|
||||
muted: '#ffffff50',
|
||||
caret: 'white',
|
||||
selection: 'rgba(128, 203, 196, 0.5)',
|
||||
selectionMatch: '#036dd626',
|
||||
|
||||
@@ -11,6 +11,7 @@ export const settings = {
|
||||
background: hex[0],
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[2],
|
||||
muted: hex[3],
|
||||
selection: hex[3],
|
||||
selectionMatch: hex[0],
|
||||
gutterBackground: hex[0],
|
||||
|
||||
+2
@@ -9,6 +9,7 @@ export const settings = {
|
||||
background: '#242424',
|
||||
lineBackground: '#24242499',
|
||||
foreground: '#f8f8f2',
|
||||
muted: '#f8f8f250',
|
||||
caret: '#FFFFFF',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
@@ -23,6 +24,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#242424',
|
||||
foreground: '#f8f8f2',
|
||||
muted: '#f8f8f250',
|
||||
caret: '#FFFFFF',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ export const settings = {
|
||||
background: '#282a36',
|
||||
lineBackground: '#282a3699',
|
||||
foreground: '#f8f8f2',
|
||||
muted: '#f8f8f250',
|
||||
caret: '#f8f8f0',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
@@ -27,6 +28,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#282a36',
|
||||
foreground: '#f8f8f2',
|
||||
muted: '#f8f8f250',
|
||||
caret: '#f8f8f0',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ export const settings = {
|
||||
background: '#2a2734',
|
||||
lineBackground: '#2a273499',
|
||||
foreground: '#eeebff',
|
||||
muted: '#eeebff50',
|
||||
caret: '#ffad5c',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
gutterBackground: '#2a2734',
|
||||
@@ -22,6 +23,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#2a2734',
|
||||
foreground: '#6c6783',
|
||||
muted: '#eeebff50',
|
||||
caret: '#ffad5c',
|
||||
selection: '#9a86fd',
|
||||
selectionMatch: '#9a86fd',
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff99',
|
||||
foreground: '#000',
|
||||
muted: '#00000050',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#d7d4f0',
|
||||
selectionMatch: '#d7d4f0',
|
||||
@@ -20,6 +21,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#fff',
|
||||
foreground: '#000',
|
||||
muted: '#00000050',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#d7d4f0',
|
||||
selectionMatch: '#d7d4f0',
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ export const settings = {
|
||||
background: hex[0],
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[10],
|
||||
muted: hex[7],
|
||||
selection: hex[8],
|
||||
selectionMatch: hex[0],
|
||||
gutterBackground: hex[3],
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#0d1117',
|
||||
lineBackground: '#0d111799',
|
||||
foreground: '#c9d1d9',
|
||||
muted: '#c9d1d950',
|
||||
caret: '#c9d1d9',
|
||||
selection: '#003d73',
|
||||
selectionMatch: '#003d73',
|
||||
@@ -16,6 +17,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#0d1117',
|
||||
foreground: '#c9d1d9',
|
||||
muted: '#c9d1d950',
|
||||
caret: '#c9d1d9',
|
||||
selection: '#003d73',
|
||||
selectionMatch: '#003d73',
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff99',
|
||||
foreground: '#24292e',
|
||||
muted: '#24292e50',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
@@ -17,6 +18,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#fff',
|
||||
foreground: '#24292e',
|
||||
muted: '#24292e50',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ export const settings = {
|
||||
background: hex[0],
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[2],
|
||||
muted: hex[2] + '50',
|
||||
selection: hex[4],
|
||||
selectionMatch: hex[0],
|
||||
gutterBackground: hex[0],
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ export const settings = {
|
||||
background: '#282828',
|
||||
lineBackground: '#28282899',
|
||||
foreground: '#ebdbb2',
|
||||
muted: '#ebdbb250',
|
||||
caret: '#ebdbb2',
|
||||
selection: '#bdae93',
|
||||
selectionMatch: '#bdae93',
|
||||
@@ -23,6 +24,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#282828',
|
||||
foreground: '#ebdbb2',
|
||||
muted: '#ebdbb250',
|
||||
caret: '#ebdbb2',
|
||||
selection: '#b99d555c',
|
||||
selectionMatch: '#b99d555c',
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ export const settings = {
|
||||
background: '#fbf1c7',
|
||||
lineBackground: '#fbf1c799',
|
||||
foreground: '#3c3836',
|
||||
muted: '#3c383650',
|
||||
caret: '#af3a03',
|
||||
selection: '#ebdbb2',
|
||||
selectionMatch: '#bdae93',
|
||||
@@ -25,6 +26,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#fbf1c7',
|
||||
foreground: '#3c3836',
|
||||
muted: '#3c383650',
|
||||
caret: '#af3a03',
|
||||
selection: '#bdae9391',
|
||||
selectionMatch: '#bdae9391',
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#212121',
|
||||
lineBackground: '#21212199',
|
||||
foreground: '#bdbdbd',
|
||||
muted: '#bdbdbd50',
|
||||
caret: '#a0a4ae',
|
||||
selection: '#d7d4f0',
|
||||
selectionMatch: '#d7d4f0',
|
||||
@@ -19,6 +20,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#212121',
|
||||
foreground: '#bdbdbd',
|
||||
muted: '#bdbdbd50',
|
||||
caret: '#a0a4ae',
|
||||
selection: '#d7d4f063',
|
||||
selectionMatch: '#d7d4f063',
|
||||
|
||||
+3
-1
@@ -5,7 +5,8 @@ export const settings = {
|
||||
light: true,
|
||||
background: '#FAFAFA',
|
||||
lineBackground: '#FAFAFA99',
|
||||
foreground: '#90A4AE',
|
||||
foreground: '#6182B8',
|
||||
muted: '#6182B850',
|
||||
caret: '#272727',
|
||||
selection: '#80CBC440',
|
||||
selectionMatch: '#FAFAFA',
|
||||
@@ -19,6 +20,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#FAFAFA',
|
||||
foreground: '#90A4AE',
|
||||
muted: '#6182B850',
|
||||
caret: '#272727',
|
||||
selection: '#80CBC440',
|
||||
selectionMatch: '#80CBC440',
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#272822',
|
||||
lineBackground: '#27282299',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#49483E',
|
||||
selectionMatch: '#49483E',
|
||||
@@ -18,6 +19,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#272822',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#49483E',
|
||||
selectionMatch: '#49483E',
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#f2f1f8',
|
||||
lineBackground: '#f2f1f899',
|
||||
foreground: '#0c006b',
|
||||
muted: '#0c006b50',
|
||||
caret: '#5c49e9',
|
||||
selection: '#d5d1f2',
|
||||
selectionMatch: '#d5d1f2',
|
||||
@@ -19,6 +20,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#f2f1f8',
|
||||
foreground: '#0c006b',
|
||||
muted: '#0c006b50',
|
||||
caret: '#5c49e9',
|
||||
selection: '#d5d1f2',
|
||||
selectionMatch: '#d5d1f2',
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#2e3440',
|
||||
lineBackground: '#2e344099',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#3b4252',
|
||||
selectionMatch: '#e5e9f0',
|
||||
@@ -20,6 +21,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#2e3440',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#00000073',
|
||||
selectionMatch: '#00000073',
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ export const settings = {
|
||||
background: hex[0],
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[2],
|
||||
muted: hex[2] + '50',
|
||||
selection: hex[4],
|
||||
selectionMatch: hex[0],
|
||||
gutterBackground: hex[0],
|
||||
|
||||
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#002b36',
|
||||
lineBackground: '#002b3699',
|
||||
foreground: '#93a1a1',
|
||||
muted: '#93a1a150',
|
||||
caret: '#839496',
|
||||
selection: '#173541',
|
||||
selectionMatch: '#aafe661a',
|
||||
@@ -45,6 +46,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: c.background,
|
||||
foreground: c.foreground,
|
||||
muted: c.muted,
|
||||
caret: c.cursor,
|
||||
selection: c.selection,
|
||||
selectionMatch: c.selection,
|
||||
|
||||
@@ -8,6 +8,7 @@ export const settings = {
|
||||
background: '#fdf6e3',
|
||||
lineBackground: '#fdf6e399',
|
||||
foreground: '#657b83',
|
||||
muted: '#657b8350',
|
||||
caret: '#586e75',
|
||||
selection: '#dfd9c8',
|
||||
selectionMatch: '#dfd9c8',
|
||||
@@ -19,6 +20,7 @@ export const settings = {
|
||||
const c = {
|
||||
background: '#FDF6E3',
|
||||
foreground: '#657B83',
|
||||
muted: '#657b8350',
|
||||
selection: '#EEE8D5',
|
||||
selectionMatch: '#EEE8D5',
|
||||
cursor: '#657B83',
|
||||
|
||||
+1
@@ -13,6 +13,7 @@ export const settings = {
|
||||
background: '#000000',
|
||||
lineBackground: 'transparent',
|
||||
foreground: hex[4],
|
||||
muted: hex[6],
|
||||
selection: hex[6],
|
||||
gutterBackground: hex[0],
|
||||
gutterForeground: hex[5],
|
||||
|
||||
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#222',
|
||||
lineBackground: '#22222299',
|
||||
foreground: '#fff',
|
||||
muted: '#ffffff50',
|
||||
caret: '#ffcc00',
|
||||
selection: 'rgba(128, 203, 196, 0.5)',
|
||||
selectionMatch: '#036dd626',
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#303841',
|
||||
lineBackground: '#30384199',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FBAC52',
|
||||
selection: '#4C5964',
|
||||
selectionMatch: '#3A546E',
|
||||
@@ -18,6 +19,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#303841',
|
||||
foreground: '#FFFFFF',
|
||||
muted: '#FFFFFF50',
|
||||
caret: '#FBAC52',
|
||||
selection: '#4C5964',
|
||||
selectionMatch: '#3A546E',
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ let colorD = '#f8fc55';
|
||||
|
||||
export const settings = {
|
||||
background: '#000000',
|
||||
foreground: colorA, // whats that?
|
||||
foreground: colorA,
|
||||
muted: colorA + '50',
|
||||
caret: colorC,
|
||||
selection: colorD,
|
||||
selectionMatch: colorA,
|
||||
|
||||
+4
-2
@@ -4,7 +4,8 @@ import { createTheme } from './theme-helper.mjs';
|
||||
export const settings = {
|
||||
background: '#24283b',
|
||||
lineBackground: '#24283b99',
|
||||
foreground: '#7982a9',
|
||||
foreground: '#f9f2f9',
|
||||
muted: '#f9f2f950',
|
||||
caret: '#c0caf5',
|
||||
selection: '#6f7bb630',
|
||||
selectionMatch: '#1f2335',
|
||||
@@ -18,7 +19,8 @@ export default createTheme({
|
||||
theme: 'dark',
|
||||
settings: {
|
||||
background: '#24283b',
|
||||
foreground: '#7982a9',
|
||||
foreground: '#f9f2f9',
|
||||
muted: '#f9f2f950',
|
||||
caret: '#c0caf5',
|
||||
selection: '#6f7bb630',
|
||||
selectionMatch: '#343b5f',
|
||||
|
||||
+4
-2
@@ -4,7 +4,8 @@ import { createTheme } from './theme-helper.mjs';
|
||||
export const settings = {
|
||||
background: '#1a1b26',
|
||||
lineBackground: '#1a1b2699',
|
||||
foreground: '#787c99',
|
||||
foreground: '#f8fcf9',
|
||||
muted: '#f8fcf950',
|
||||
caret: '#c0caf5',
|
||||
selection: '#515c7e40',
|
||||
selectionMatch: '#16161e',
|
||||
@@ -18,7 +19,8 @@ export default createTheme({
|
||||
theme: 'dark',
|
||||
settings: {
|
||||
background: '#1a1b26',
|
||||
foreground: '#787c99',
|
||||
foreground: '#f8fcf9',
|
||||
muted: '#f8fcf950',
|
||||
caret: '#c0caf5',
|
||||
selection: '#515c7e40',
|
||||
selectionMatch: '#16161e',
|
||||
|
||||
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#e1e2e7',
|
||||
lineBackground: '#e1e2e799',
|
||||
foreground: '#3760bf',
|
||||
muted: '#3760bf50',
|
||||
caret: '#3760bf',
|
||||
selection: '#99a7df',
|
||||
selectionMatch: '#99a7df',
|
||||
@@ -20,6 +21,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#e1e2e7',
|
||||
foreground: '#3760bf',
|
||||
muted: '#3760bf50',
|
||||
caret: '#3760bf',
|
||||
selection: '#99a7df',
|
||||
selectionMatch: '#99a7df',
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#1e1e1e',
|
||||
lineBackground: '#1e1e1e99',
|
||||
foreground: '#fff',
|
||||
muted: '#ffffff50',
|
||||
caret: '#c6c6c6',
|
||||
selection: '#6199ff2f',
|
||||
selectionMatch: '#72a1ff59',
|
||||
@@ -19,6 +20,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#1e1e1e',
|
||||
foreground: '#fff',
|
||||
muted: '#ffffff50',
|
||||
caret: '#c6c6c6',
|
||||
selection: '#6199ff2f',
|
||||
selectionMatch: '#72a1ff59',
|
||||
|
||||
+2
@@ -5,6 +5,7 @@ export const settings = {
|
||||
background: '#ffffff',
|
||||
lineBackground: '#ffffff50',
|
||||
foreground: '#383a42',
|
||||
muted: '#383a4250',
|
||||
caret: '#000',
|
||||
selection: '#add6ff',
|
||||
selectionMatch: '#a8ac94',
|
||||
@@ -20,6 +21,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#ffffff',
|
||||
foreground: '#383a42',
|
||||
muted: '#383a4250',
|
||||
caret: '#000',
|
||||
selection: '#add6ff',
|
||||
selectionMatch: '#a8ac94',
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@ import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from './theme-helper.mjs';
|
||||
export const settings = {
|
||||
background: 'white',
|
||||
foreground: 'black', // whats that?
|
||||
foreground: 'black',
|
||||
muted: '#00000050',
|
||||
caret: 'black',
|
||||
selection: 'rgba(128, 203, 196, 0.5)',
|
||||
selectionMatch: '#ffffff26',
|
||||
|
||||
+2
@@ -6,6 +6,7 @@ export const settings = {
|
||||
background: '#fff',
|
||||
lineBackground: '#ffffff99',
|
||||
foreground: '#3D3D3D',
|
||||
muted: '#3D3D3D50',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
@@ -18,6 +19,7 @@ export default createTheme({
|
||||
settings: {
|
||||
background: '#fff',
|
||||
foreground: '#3D3D3D',
|
||||
muted: '#3D3D3D50',
|
||||
selection: '#BBDFFF',
|
||||
selectionMatch: '#BBDFFF',
|
||||
gutterBackground: '#fff',
|
||||
|
||||
@@ -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 -->
|
||||
<style is:global>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--background: #222;
|
||||
--lineBackground: #22222299;
|
||||
--foreground: #fff;
|
||||
|
||||
@@ -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 -->
|
||||
<style is:global>
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--background: #222;
|
||||
--lineBackground: #22222299;
|
||||
--foreground: #fff;
|
||||
|
||||
@@ -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 {
|
||||
content: ' ';
|
||||
position: fixed;
|
||||
|
||||
@@ -2,149 +2,115 @@ import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||
import StopCircleIcon from '@heroicons/react/20/solid/StopCircleIcon';
|
||||
import cx from '@src/cx.mjs';
|
||||
import { useSettings, setIsZen } from '../../settings.mjs';
|
||||
import { StrudelIcon } from '@src/repl/components/icons/StrudelIcon';
|
||||
import '../Repl.css';
|
||||
|
||||
const { BASE_URL } = import.meta.env;
|
||||
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
|
||||
|
||||
export function Header({ context, embedded = false }) {
|
||||
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShuffle, handleShare } =
|
||||
context;
|
||||
const isEmbedded = typeof window !== 'undefined' && (embedded || window.location !== window.parent.location);
|
||||
export function Header({ context, isEmbedded = false }) {
|
||||
const { started, pending, isDirty, activeCode, handleTogglePlay, handleEvaluate, handleShare } = context;
|
||||
const { isZen, isButtonRowHidden, isCSSAnimationDisabled, fontFamily } = useSettings();
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header"
|
||||
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 ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full py-1 justify-between',
|
||||
isEmbedded ? 'flex' : 'md:flex',
|
||||
isZen ? 'h-12 w-8 fixed top-0 left-0' : 'sticky top-0 w-full justify-between',
|
||||
'flex items-center',
|
||||
)}
|
||||
style={{ fontFamily }}
|
||||
>
|
||||
<div className="px-4 flex space-x-2 md:pt-0 select-none">
|
||||
<h1
|
||||
onClick={() => {
|
||||
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',
|
||||
)}
|
||||
<div className={cx(isEmbedded ? 'flex' : 'sm:flex', 'w-full sm:justify-between')}>
|
||||
<div className="px-3 pt-1 flex space-x-2 sm:pt-0 select-none">
|
||||
<h1
|
||||
onClick={() => {
|
||||
if (!isEmbedded) {
|
||||
setIsZen(!isZen);
|
||||
}
|
||||
if (isEmbedded) window.open(window.location.href.replace('embed', ''));
|
||||
}}
|
||||
>
|
||||
<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(
|
||||
!isEmbedded ? 'p-2' : 'px-2',
|
||||
'hover:opacity-50',
|
||||
!started && !isCSSAnimationDisabled && 'animate-pulse',
|
||||
isEmbedded ? 'text-l cursor-pointer' : 'text-xl',
|
||||
'text-foreground font-bold flex space-x-2 items-center',
|
||||
)}
|
||||
>
|
||||
{!pending ? (
|
||||
<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"
|
||||
<div
|
||||
className={cx(
|
||||
'cursor-pointer hover:opacity-50 flex items-center space-x-1',
|
||||
!isEmbedded ? 'p-2' : 'px-2',
|
||||
'mt-[1px]',
|
||||
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>
|
||||
</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>
|
||||
)}
|
||||
{/* {isEmbedded && (
|
||||
<button className={cx('hover:opacity-50 px-2')}>
|
||||
<a href={window.location.href} target="_blank" rel="noopener noreferrer" title="Open in REPL">
|
||||
🚀
|
||||
</a>
|
||||
</button>
|
||||
)}
|
||||
{isEmbedded && (
|
||||
<button className={cx('hover:opacity-50 px-2')}>
|
||||
<a
|
||||
onClick={() => {
|
||||
window.location.href = initialUrl;
|
||||
window.location.reload();
|
||||
}}
|
||||
title="Reset"
|
||||
>
|
||||
💔
|
||||
</a>
|
||||
</button>
|
||||
)} */}
|
||||
<span className="block text-foreground rotate-90">
|
||||
<StrudelIcon className="w-5 h-5 fill-foreground" />
|
||||
</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-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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 UserFacingErrorMessage from '@src/repl/components/UserFacingErrorMessage';
|
||||
import { Header } from './Header';
|
||||
@@ -14,14 +14,17 @@ export default function ReplEditor(Props) {
|
||||
const { containerRef, editorRef, error, init, pending } = context;
|
||||
const settings = useSettings();
|
||||
const { panelPosition, isZen } = settings;
|
||||
const isEmbedded = typeof window !== 'undefined' && window.location !== window.parent.location;
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col relative" {...editorProps}>
|
||||
<Loader active={pending} />
|
||||
<Header context={context} />
|
||||
<Header context={context} isEmbedded={isEmbedded} />
|
||||
|
||||
<div className="grow flex relative overflow-hidden">
|
||||
<Code containerRef={containerRef} editorRef={editorRef} init={init} />
|
||||
{!isZen && panelPosition === 'right' && <VerticalPanel context={context} />}
|
||||
<PanelToggle isEmbedded={isEmbedded} isZen={isZen} />
|
||||
</div>
|
||||
<UserFacingErrorMessage error={error} />
|
||||
{!isZen && panelPosition === 'bottom' && <HorizontalPanel context={context} />}
|
||||
|
||||
@@ -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', className)} title={label} {...buttonProps}>
|
||||
<button className={cx('hover:opacity-50 text-nowrap w-fit text-sm ', className)} title={label} {...buttonProps}>
|
||||
{labelIsHidden !== true && label}
|
||||
{children}
|
||||
</button>
|
||||
@@ -13,16 +13,13 @@ export function SpecialActionButton(props) {
|
||||
const { className, ...buttonProps } = props;
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
{...buttonProps}
|
||||
className={cx('bg-background p-2 max-w-[300px] rounded-md hover:opacity-50', className)}
|
||||
/>
|
||||
<ActionButton {...buttonProps} className={cx('bg-background p-2 max-w-[300px] hover:opacity-50', className)} />
|
||||
);
|
||||
}
|
||||
|
||||
export function ActionInput({ label, className, ...props }) {
|
||||
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" />
|
||||
|
||||
<span className="inline-flex items-center peer-hover:opacity-50">{label}</span>
|
||||
@@ -35,7 +32,7 @@ export function SpecialActionInput({ className, ...props }) {
|
||||
<ActionInput
|
||||
{...props}
|
||||
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>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Textbox } from '../textbox/Textbox';
|
||||
import { Textbox } from '@src/repl/components/panel/SettingsTab';
|
||||
import cx from '@src/cx.mjs';
|
||||
|
||||
function IncButton({ children, className, ...buttonProps }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { SelectInput } from './SelectInput';
|
||||
import { SelectInputDuplicate } from '@src/repl/components/panel/SettingsTab';
|
||||
import { getAudioDevices } from '@strudel/webaudio';
|
||||
|
||||
const initdevices = new Map();
|
||||
@@ -29,7 +29,7 @@ export function AudioDeviceSelector({ audioDeviceName, onChange, isDisabled }) {
|
||||
options.set(deviceName, deviceName);
|
||||
});
|
||||
return (
|
||||
<SelectInput
|
||||
<SelectInputDuplicate
|
||||
isDisabled={isDisabled}
|
||||
options={options}
|
||||
onClick={onClick}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
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
|
||||
export function AudioEngineTargetSelector({ target, onChange, isDisabled }) {
|
||||
@@ -12,8 +12,8 @@ export function AudioEngineTargetSelector({ target, onChange, isDisabled }) {
|
||||
[audioEngineTargets.osc, audioEngineTargets.osc],
|
||||
]);
|
||||
return (
|
||||
<div className=" flex flex-col gap-1">
|
||||
<SelectInput isDisabled={isDisabled} options={options} value={target} onChange={onTargetChange} />
|
||||
<div className="flex flex-col gap-1">
|
||||
<SelectInputDuplicate isDisabled={isDisabled} options={options} value={target} onChange={onTargetChange} />
|
||||
{target === audioEngineTargets.osc && (
|
||||
<div>
|
||||
<p className="text-sm italic">
|
||||
|
||||
@@ -7,7 +7,7 @@ export function ConsoleTab() {
|
||||
const log = useStore($strudel_log_history);
|
||||
const { fontFamily } = useSettings();
|
||||
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">
|
||||
{log.map((l, i) => {
|
||||
const message = linkify(l.message);
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import PlayCircleIcon from '@heroicons/react/20/solid/PlayCircleIcon';
|
||||
import cx from '@src/cx.mjs';
|
||||
import NumberInput from '@src/repl/components/NumberInput';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Textbox } from '../textbox/Textbox';
|
||||
import { useState } from 'react';
|
||||
import { Textbox } from '@src/repl/components/panel/SettingsTab';
|
||||
import { getAudioContext } from '@strudel/webaudio';
|
||||
import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
||||
|
||||
function Checkbox({ label, value, onChange, disabled = false }) {
|
||||
return (
|
||||
|
||||
@@ -2,14 +2,14 @@ import cx from '@src/cx.mjs';
|
||||
|
||||
export function ButtonGroup({ value, onChange, items }) {
|
||||
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) => (
|
||||
<button
|
||||
key={key}
|
||||
id={key}
|
||||
onClick={() => onChange(key)}
|
||||
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 === arr.length - 1 && 'rounded-r-md',
|
||||
// value === key ? 'bg-background' : 'bg-lineHighlight',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 { FilesTab } from './FilesTab';
|
||||
import { Reference } from './Reference';
|
||||
@@ -8,33 +8,44 @@ import { SoundsTab } from './SoundsTab';
|
||||
import { useLogger } from '../useLogger';
|
||||
import { WelcomeTab } from './WelcomeTab';
|
||||
import { PatternsTab } from './PatternsTab';
|
||||
import { ChevronLeftIcon, XMarkIcon } from '@heroicons/react/16/solid';
|
||||
import { Bars3Icon, XMarkIcon } from '@heroicons/react/16/solid';
|
||||
import ExportTab from './ExportTab';
|
||||
|
||||
const TAURI = typeof window !== 'undefined' && window.__TAURI__;
|
||||
|
||||
export function HorizontalPanel({ context }) {
|
||||
const settings = useSettings();
|
||||
const { isPanelOpen, activeFooter: tab } = settings;
|
||||
function PanelCloseButton() {
|
||||
const { isPanelOpen } = useSettings();
|
||||
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 (
|
||||
<PanelNav
|
||||
settings={settings}
|
||||
className={cx(isPanelOpen ? `min-h-[360px] max-h-[360px]` : 'min-h-12 max-h-12', 'overflow-hidden flex flex-col')}
|
||||
className={cx(
|
||||
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 && (
|
||||
<div className="flex h-full overflow-auto pr-10 ">
|
||||
<div className="flex h-full overflow-auto w-full">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</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>
|
||||
);
|
||||
}
|
||||
@@ -42,36 +53,24 @@ export function HorizontalPanel({ context }) {
|
||||
export function VerticalPanel({ context }) {
|
||||
const settings = useSettings();
|
||||
const { activeFooter: tab, isPanelOpen } = settings;
|
||||
|
||||
if (!isPanelOpen) {
|
||||
return;
|
||||
}
|
||||
return (
|
||||
<PanelNav
|
||||
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="flex justify-between w-full ">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelActionButton settings={settings} />
|
||||
</div>
|
||||
|
||||
<div className="overflow-auto h-full">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</div>
|
||||
<div className={cx('flex flex-col h-full')}>
|
||||
<div className="flex justify-between w-full ">
|
||||
<Tabs setTab={setTab} tab={tab} />
|
||||
<PanelCloseButton />
|
||||
</div>
|
||||
) : (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
setIsPanelOpened(true);
|
||||
}}
|
||||
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>
|
||||
)}
|
||||
|
||||
<div className="overflow-auto h-full">
|
||||
<PanelContent context={context} tab={tab} />
|
||||
</div>
|
||||
</div>
|
||||
</PanelNav>
|
||||
);
|
||||
}
|
||||
@@ -89,8 +88,8 @@ if (TAURI) {
|
||||
tabNames.files = 'files';
|
||||
}
|
||||
|
||||
function PanelNav({ children, className, settings, ...props }) {
|
||||
const isHoverBehavior = settings.togglePanelTrigger === 'hover';
|
||||
function PanelNav({ children, className, ...props }) {
|
||||
const settings = useSettings();
|
||||
return (
|
||||
<nav
|
||||
onClick={() => {
|
||||
@@ -98,16 +97,6 @@ function PanelNav({ children, className, settings, ...props }) {
|
||||
setIsPanelOpened(true);
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
if (isHoverBehavior && !settings.isPanelOpen) {
|
||||
setIsPanelOpened(true);
|
||||
}
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
if (isHoverBehavior && !settings.isPanelPinned) {
|
||||
setIsPanelOpened(false);
|
||||
}
|
||||
}}
|
||||
aria-label="Menu Panel"
|
||||
className={cx('bg-lineHighlight group overflow-x-auto', className)}
|
||||
{...props}
|
||||
@@ -145,7 +134,7 @@ function PanelTab({ label, isSelected, onClick }) {
|
||||
<button
|
||||
onClick={onClick}
|
||||
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',
|
||||
)}
|
||||
>
|
||||
@@ -154,65 +143,34 @@ function PanelTab({ label, isSelected, onClick }) {
|
||||
</>
|
||||
);
|
||||
}
|
||||
function Tabs({ setTab, tab, className }) {
|
||||
function Tabs({ className }) {
|
||||
const { isPanelOpen, activeFooter: tab } = useSettings();
|
||||
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) => {
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
function PanelActionButton({ settings }) {
|
||||
const { togglePanelTrigger, isPanelPinned, isPanelOpen } = settings;
|
||||
const isHoverBehavior = togglePanelTrigger === 'hover';
|
||||
if (!isPanelOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHoverBehavior) {
|
||||
return <PinButton pinned={isPanelPinned} />;
|
||||
}
|
||||
return <CloseButton onClick={() => setIsPanelOpened(false)} />;
|
||||
}
|
||||
|
||||
function PinButton({ pinned }) {
|
||||
export function PanelToggle({ isEmbedded, isZen }) {
|
||||
const { panelPosition, isPanelOpen } = useSettings();
|
||||
return (
|
||||
<button
|
||||
onClick={() => setPanelPinned(!pinned)}
|
||||
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',
|
||||
pinned ? 'flex' : 'hidden',
|
||||
)}
|
||||
aria-label="Pin Menu Panel"
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
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"
|
||||
!isEmbedded &&
|
||||
!isZen &&
|
||||
panelPosition === 'right' && (
|
||||
<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 ',
|
||||
isPanelOpen && 'hidden',
|
||||
)}
|
||||
onClick={() => setIsPanelOpened(!isPanelOpen)}
|
||||
>
|
||||
<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>
|
||||
</svg>
|
||||
</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>
|
||||
<Bars3Icon className="w-6 h-6" />
|
||||
</button>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Pagination } from '../pagination/Pagination.jsx';
|
||||
import { useState } from 'react';
|
||||
import { useDebounce } from '../usedebounce.jsx';
|
||||
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'> } */) {
|
||||
const meta = useMemo(() => getMetadata(pattern.code), [pattern]);
|
||||
@@ -172,7 +172,7 @@ export function PatternsTab({ context }) {
|
||||
/>
|
||||
</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 && ( */}
|
||||
<PatternButtons
|
||||
onClick={(id) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { memo, useEffect, useMemo, useState, Fragment } from 'react';
|
||||
|
||||
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;
|
||||
|
||||
@@ -128,14 +128,14 @@ export const Reference = memo(function Reference() {
|
||||
{selectedTag && (
|
||||
<div className="w-72">
|
||||
<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}
|
||||
>
|
||||
{selectedTag}
|
||||
</span>
|
||||
</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) => (
|
||||
<Fragment key={`entry-${entry.name}`}>
|
||||
<a
|
||||
@@ -174,8 +174,8 @@ export const Reference = memo(function Reference() {
|
||||
<span key={t}>
|
||||
<a
|
||||
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',
|
||||
`${selectedTag === t ? 'bg-gray-500 text-black' : ''}`,
|
||||
'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-muted text-foreground' : ''}`,
|
||||
].join(' ')}
|
||||
onClick={() => toggleTag(t)}
|
||||
>
|
||||
@@ -191,7 +191,7 @@ export const Reference = memo(function Reference() {
|
||||
{entry.name}
|
||||
</h3>
|
||||
{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(', ')}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -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 { themes } from '@strudel/codemirror';
|
||||
import { Textbox } from '../textbox/Textbox.jsx';
|
||||
import { confirmAndReloadPage, isUdels } from '../../util.mjs';
|
||||
import { ButtonGroup } from './Forms.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 { 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 }) {
|
||||
return (
|
||||
<label>
|
||||
<input disabled={disabled} type="checkbox" checked={value} onChange={onChange} />
|
||||
<label className="text-sm">
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<select
|
||||
className="p-2 bg-background rounded-md text-foreground border-foreground"
|
||||
value={value}
|
||||
disabled={isDisabled}
|
||||
onClick={onClick}
|
||||
className={cx('p-2', inputClass)}
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
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]) => (
|
||||
<option key={k} className="bg-background" value={k}>
|
||||
{label}
|
||||
@@ -37,9 +74,9 @@ function SelectInput({ value, options, onChange }) {
|
||||
|
||||
function NumberSlider({ value, onChange, step = 1, ...rest }) {
|
||||
return (
|
||||
<div className="flex space-x-2 gap-1">
|
||||
<div className="flex space-x-2 gap-1 overflow-hidden">
|
||||
<input
|
||||
className="p-2 grow"
|
||||
className="p-2 grow accent-foreground"
|
||||
type="range"
|
||||
value={value}
|
||||
step={step}
|
||||
@@ -50,7 +87,7 @@ function NumberSlider({ value, onChange, step = 1, ...rest }) {
|
||||
type="number"
|
||||
value={value}
|
||||
step={step}
|
||||
className="w-16 bg-background rounded-md"
|
||||
className={cx('w-16', inputClass)}
|
||||
onChange={(e) => onChange(Number(e.target.value))}
|
||||
/>
|
||||
</div>
|
||||
@@ -59,8 +96,8 @@ function NumberSlider({ value, onChange, step = 1, ...rest }) {
|
||||
|
||||
function FormItem({ label, children, sublabel }) {
|
||||
return (
|
||||
<div className="grid gap-2">
|
||||
<label>{label}</label>
|
||||
<div className="grid gap-2 text-sm">
|
||||
<label className="text-sm">{label}</label>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
@@ -107,7 +144,6 @@ export function SettingsTab({ started }) {
|
||||
panelPosition,
|
||||
audioDeviceName,
|
||||
audioEngineTarget,
|
||||
togglePanelTrigger,
|
||||
maxPolyphony,
|
||||
multiChannelOrbits,
|
||||
isTabIndentationEnabled,
|
||||
@@ -178,7 +214,7 @@ export function SettingsTab({ started }) {
|
||||
<FormItem label="Theme">
|
||||
<SelectInput options={themeOptions} value={theme} onChange={(theme) => settingsMap.setKey('theme', theme)} />
|
||||
</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">
|
||||
<SelectInput
|
||||
options={fontFamilyOptions}
|
||||
@@ -219,13 +255,6 @@ export function SettingsTab({ started }) {
|
||||
items={{ bottom: 'Bottom', right: 'Right' }}
|
||||
></ButtonGroup>
|
||||
</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">
|
||||
<Checkbox
|
||||
label="Enable bracket matching"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useMemo, useRef, useState } from 'react';
|
||||
import { settingsMap, soundFilterType, useSettings } from '../../../settings.mjs';
|
||||
import { ButtonGroup } from './Forms.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 { confirmDialog } from '@src/repl/util.mjs';
|
||||
import { clearIDB, userSamplesDBConfig } from '@src/repl/idbutils.mjs';
|
||||
|
||||
@@ -7,7 +7,7 @@ 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 }}>
|
||||
<h3>꩜ welcome</h3>
|
||||
<h3>welcome</h3>
|
||||
<p>
|
||||
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:
|
||||
@@ -30,7 +30,7 @@ export function WelcomeTab({ context }) {
|
||||
</a>{' '}
|
||||
to ask any questions, give feedback or just say hello.
|
||||
</p>
|
||||
<h3>꩜ about</h3>
|
||||
<h3>about</h3>
|
||||
<p>
|
||||
strudel is a JavaScript version of{' '}
|
||||
<a href="https://tidalcycles.org/" target="_blank">
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -43,7 +43,6 @@ export const defaultSettings = {
|
||||
panelPosition: 'right',
|
||||
isPanelPinned: false,
|
||||
isPanelOpen: true,
|
||||
togglePanelTrigger: 'click', //click | hover
|
||||
userPatterns: '{}',
|
||||
prebakeScript: '',
|
||||
audioEngineTarget: audioEngineTargets.webaudio,
|
||||
|
||||
@@ -24,6 +24,7 @@ module.exports = {
|
||||
background: 'var(--background)',
|
||||
lineBackground: 'var(--lineBackground)',
|
||||
foreground: 'var(--foreground)',
|
||||
muted: 'var(--muted)',
|
||||
caret: 'var(--caret)',
|
||||
selection: 'var(--selection)',
|
||||
selectionMatch: 'var(--selectionMatch)',
|
||||
@@ -46,28 +47,28 @@ module.exports = {
|
||||
'code::after': {
|
||||
content: 'none',
|
||||
},
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
a: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
h1: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
h2: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
h3: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
h4: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
pre: {
|
||||
color: 'var(--foreground)',
|
||||
background: 'var(--background)',
|
||||
color: 'var(--foreground) !important',
|
||||
background: 'var(--background) !important',
|
||||
},
|
||||
code: {
|
||||
color: 'var(--foreground)',
|
||||
color: 'var(--foreground) !important',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user