themed minirepl

+ add strudelTheme
+ add lineBackground with opacity
+ add some missing light flags
+ add fallback css variables for non js context
This commit is contained in:
Felix Roos 2023-02-10 21:42:27 +01:00
parent 6170eef441
commit 14cb954213
13 changed files with 116 additions and 34 deletions

View File

@ -13,7 +13,15 @@ import { logger } from '@strudel.cycles/core';
const getTime = () => getAudioContext().currentTime;
export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTime, punchcard, canvasHeight = 200 }) {
export function MiniRepl({
tune,
hideOutsideView = false,
enableKeyboard,
drawTime,
punchcard,
canvasHeight = 200,
theme,
}) {
drawTime = drawTime || (punchcard ? [0, 4] : undefined);
const evalOnMount = !!drawTime;
const drawContext = useCallback(
@ -111,7 +119,7 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi
{error && <div className={styles.error}>{error.message}</div>}
</div>
<div className={styles.body}>
{show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} />}
{show && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} theme={theme} />}
</div>
{drawTime && (
<canvas

View File

@ -1,9 +1,9 @@
.container {
@apply rounded-md overflow-hidden bg-[#222222];
@apply overflow-hidden;
}
.header {
@apply flex justify-between bg-slate-700 border-t border-slate-500;
@apply flex justify-between bg-lineHighlight border-t border-l border-r border-lineHighlight rounded-t-md overflow-hidden;
}
.buttons {
@ -11,11 +11,11 @@
}
.button {
@apply cursor-pointer w-16 flex items-center justify-center p-1 bg-slate-700 border-r border-slate-500 text-white hover:bg-slate-600;
@apply cursor-pointer w-16 flex items-center justify-center p-1 border-r border-lineHighlight text-foreground hover:bg-background;
}
.buttonDisabled {
@apply w-16 flex items-center justify-center p-1 bg-slate-600 text-slate-400 cursor-not-allowed;
@apply w-16 flex items-center justify-center p-1 opacity-50 cursor-not-allowed border-r border-lineHighlight;
}
.error {

View File

@ -12,7 +12,3 @@
.cm-theme-light {
width: 100%;
}
.cm-line > * {
background: var(--background);
}

View File

@ -6,4 +6,5 @@ export { default as useHighlighting } from './hooks/useHighlighting';
export { default as usePostMessage } from './hooks/usePostMessage';
export { default as useStrudel } from './hooks/useStrudel';
export { default as useKeydown } from './hooks/useKeydown';
export { default as strudelTheme } from './themes/strudel-theme';
export { default as cx } from './cx';

View File

@ -5,6 +5,8 @@ import { settings } from '../repl/themes.mjs';
const { BASE_URL } = import.meta.env;
const base = BASE_URL;
const { strudelTheme } = settings;
---
<!-- Global Metadata -->
@ -28,14 +30,28 @@ const base = BASE_URL;
<script src="./make-scrollable-code-focusable.js" is:inline></script>
<script src="/src/pwa.ts"></script>
<!-- this does not work for some reason: -->
<!-- <style is:global define:vars={strudelTheme}></style> -->
<!-- the following variables are just a fallback to make sure everything is readable without JS -->
<style is:global>
:root {
--background: #222;
--lineBackground: #22222250;
--foreground: #fff;
--caret: #ffcc00;
--selection: rgba(128, 203, 196, 0.5);
--selectionMatch: #036dd626;
--lineHighlight: #00000050;
--gutterBackground: transparent;
--gutterForeground: #8a919966;
}
</style>
{pwaInfo && <Fragment set:html={pwaInfo.webManifest.linkTag} />}
<script define:vars={{ settings }}>
// const themeStyle = document.getElementById('theme');
<script define:vars={{ settings, strudelTheme }} is:inline>
const themeStyle = document.createElement('style');
themeStyle.id = 'strudel-theme';
document.head.append(themeStyle);
function getTheme(name) {
if (!settings[name]) {
console.warn('theme', name, 'has no settings');
@ -50,7 +66,8 @@ const base = BASE_URL;
// set css variables
themeStyle.innerHTML = `:root {
${Object.entries(settings)
.map(([key, value]) => `--${key}: ${value};`)
// important to override fallback
.map(([key, value]) => `--${key}: ${value} !important;`)
.join('\n')}
}`;
// tailwind dark mode
@ -60,7 +77,7 @@ const base = BASE_URL;
document.documentElement.classList.add('dark');
}
// persist theme name
localStorage.setItem('strudel-theme', name);
localStorage.setItem('strudel-theme', name || 'strudelTheme');
}
setTheme(localStorage.getItem('strudel-theme'));
document.addEventListener('strudel-theme', (e) => setTheme(e.detail));

View File

@ -0,0 +1,9 @@
.cm-activeLine {
background-color: transparent !important;
}
.cm-theme {
background-color: var(--background);
border: 1px solid var(--lineHighlight);
padding: 2px;
}

View File

@ -2,6 +2,10 @@ import { evalScope, controls } from '@strudel.cycles/core';
import { initAudioOnFirstClick } from '@strudel.cycles/webaudio';
import { useEffect, useState } from 'react';
import { prebake } from '../repl/prebake';
import { themes } from '../repl/themes.mjs';
import './MiniRepl.css';
const theme = localStorage.getItem('strudel-theme') || 'strudelTheme';
let modules;
if (typeof window !== 'undefined') {
@ -34,7 +38,14 @@ export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) {
}, []);
return Repl ? (
<div className="mb-4">
<Repl tune={tune} hideOutsideView={true} drawTime={drawTime} punchcard={punchcard} canvasHeight={canvasHeight} />
<Repl
tune={tune}
hideOutsideView={true}
drawTime={drawTime}
punchcard={punchcard}
canvasHeight={canvasHeight}
theme={themes[theme]}
/>
</div>
) : (
<pre>{tune}</pre>

View File

@ -22,7 +22,7 @@ const currentFile = `src/pages${currentPage.replace(/\/$/, '')}.mdx`;
const githubEditUrl = `${CONFIG.GITHUB_EDIT_URL}/${currentFile}`;
---
<html dir={frontmatter.dir ?? 'ltr'} lang={frontmatter.lang ?? 'en'} class="initial">
<html dir={frontmatter.dir ?? 'ltr'} lang={frontmatter.lang ?? 'en'} class="initial dark">
<head>
<HeadCommon />
<HeadSEO frontmatter={frontmatter} canonicalUrl={canonicalURL} />

View File

@ -3,7 +3,7 @@ import HeadCommon from '../components/HeadCommon.astro';
import { Repl } from '../repl/Repl.jsx';
---
<html lang="en">
<html lang="en" class="dark">
<head>
<HeadCommon />
<title>Strudel REPL</title>

View File

@ -75,7 +75,7 @@ export function Footer({ context }) {
<FooterTab name="samples" />
<FooterTab name="console" />
<FooterTab name="reference" />
<FooterTab name="settings" />
<FooterTab name="theme" />
</div>
{activeFooter !== '' && (
<button onClick={() => setActiveFooter('')} className="text-foreground" aria-label="Close Panel">
@ -167,13 +167,13 @@ export function Footer({ context }) {
</div>
)}
{activeFooter === 'reference' && <Reference />}
{activeFooter === 'settings' && (
{activeFooter === 'theme' && (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-2 p-2">
{Object.entries(themes).map(([k, t]) => (
<div
key={k}
className={classNames(
'border-2 border-transparent cursor-pointer p-4 bg-background rounded-md',
'border-2 border-transparent cursor-pointer p-4 bg-background bg-opacity-25 rounded-md',
theme === k ? '!border-foreground' : '',
)}
onClick={() => {

View File

@ -14,3 +14,7 @@
padding-top: 12px !important;
padding-left: 8px !important;
}
.cm-line > * {
background: var(--lineBackground);
}

View File

@ -30,8 +30,10 @@ import {
xcodeLight,
} from '@uiw/codemirror-themes-all';
import strudelTheme from '@strudel.cycles/react/src/themes/strudel-theme';
export const themes = {
// none: 'none',
strudelTheme,
abcdef,
androidstudio,
atomone,
@ -63,24 +65,26 @@ export const themes = {
xcodeLight,
};
// lineBackground is background with 50% opacity, to make sure the selection below is visible
export const settings = {
none: {
background: '#222',
foreground: '#FFFFFF',
lineHighlight: '#00000059',
},
strudelTheme: {
background: '#222',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#49483E',
selectionMatch: '#49483E',
gutterBackground: '#272822',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
lineBackground: '#22222250',
foreground: '#fff',
// foreground: '#75baff',
caret: '#ffcc00',
selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626',
// lineHighlight: '#8a91991a', // original
lineHighlight: '#00000050',
gutterBackground: 'transparent',
// gutterForeground: '#8a919966',
gutterForeground: '#8a919966',
},
abcdef: {
background: '#0f0f0f',
lineBackground: '#0f0f0f50',
foreground: '#defdef',
caret: '#00FF00',
selection: '#515151',
@ -91,6 +95,7 @@ export const settings = {
},
androidstudio: {
background: '#282b2e',
lineBackground: '#282b2e50',
foreground: '#a9b7c6',
caret: '#00FF00',
selection: '#343739',
@ -99,6 +104,7 @@ export const settings = {
},
atomone: {
background: '#272C35',
lineBackground: '#272C3550',
foreground: '#9d9b97',
caret: '#797977',
selection: '#ffffff30',
@ -110,6 +116,7 @@ export const settings = {
},
aura: {
background: '#21202e',
lineBackground: '#21202e50',
foreground: '#edecee',
caret: '#a277ff',
selection: '#3d375e7f',
@ -120,7 +127,9 @@ export const settings = {
lineHighlight: '#a394f033',
},
bbedit: {
light: true,
background: '#FFFFFF',
lineBackground: '#FFFFFF50',
foreground: '#000000',
caret: '#FBAC52',
selection: '#FFD420',
@ -132,6 +141,7 @@ export const settings = {
},
bespin: {
background: '#28211c',
lineBackground: '#28211c50',
foreground: '#9d9b97',
caret: '#797977',
selection: '#36312e',
@ -142,6 +152,7 @@ export const settings = {
},
darcula: {
background: '#2B2B2B',
lineBackground: '#2B2B2B50',
foreground: '#f8f8f2',
caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)',
@ -153,6 +164,7 @@ export const settings = {
},
dracula: {
background: '#282a36',
lineBackground: '#282a3650',
foreground: '#f8f8f2',
caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)',
@ -163,7 +175,9 @@ export const settings = {
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
duotoneLight: {
light: true,
background: '#faf8f5',
lineBackground: '#faf8f550',
foreground: '#b29762',
caret: '#93abdc',
selection: '#e3dcce',
@ -175,6 +189,7 @@ export const settings = {
},
duotoneDark: {
background: '#2a2734',
lineBackground: '#2a273450',
foreground: '#6c6783',
caret: '#ffad5c',
selection: 'rgba(255, 255, 255, 0.1)',
@ -185,6 +200,7 @@ export const settings = {
eclipse: {
light: true,
background: '#fff',
lineBackground: '#ffffff50',
foreground: '#000',
caret: '#FFFFFF',
selection: '#d7d4f0',
@ -197,6 +213,7 @@ export const settings = {
githubLight: {
light: true,
background: '#fff',
lineBackground: '#ffffff50',
foreground: '#24292e',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
@ -205,6 +222,7 @@ export const settings = {
},
githubDark: {
background: '#0d1117',
lineBackground: '#0d111750',
foreground: '#c9d1d9',
caret: '#c9d1d9',
selection: '#003d73',
@ -213,6 +231,7 @@ export const settings = {
},
gruvboxDark: {
background: '#282828',
lineBackground: '#28282850',
foreground: '#ebdbb2',
caret: '#ebdbb2',
selection: '#bdae93',
@ -224,6 +243,7 @@ export const settings = {
gruvboxLight: {
light: true,
background: '#fbf1c7',
lineBackground: '#fbf1c750',
foreground: '#3c3836',
caret: '#af3a03',
selection: '#ebdbb2',
@ -235,6 +255,7 @@ export const settings = {
},
materialDark: {
background: '#2e3235',
lineBackground: '#2e323550',
foreground: '#bdbdbd',
caret: '#a0a4ae',
selection: '#d7d4f0',
@ -247,6 +268,7 @@ export const settings = {
materialLight: {
light: true,
background: '#FAFAFA',
lineBackground: '#FAFAFA50',
foreground: '#90A4AE',
caret: '#272727',
selection: '#80CBC440',
@ -259,6 +281,7 @@ export const settings = {
noctisLilac: {
light: true,
background: '#f2f1f8',
lineBackground: '#f2f1f850',
foreground: '#0c006b',
caret: '#5c49e9',
selection: '#d5d1f2',
@ -269,6 +292,7 @@ export const settings = {
},
nord: {
background: '#2e3440',
lineBackground: '#2e344050',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#3b4252',
@ -280,6 +304,7 @@ export const settings = {
},
okaidia: {
background: '#272822',
lineBackground: '#27282250',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#49483E',
@ -291,6 +316,7 @@ export const settings = {
solarizedLight: {
light: true,
background: '#fdf6e3',
lineBackground: '#fdf6e350',
foreground: '#657b83',
caret: '#586e75',
selection: '#dfd9c8',
@ -301,6 +327,7 @@ export const settings = {
},
solarizedDark: {
background: '#002b36',
lineBackground: '#002b3650',
foreground: '#93a1a1',
caret: '#839496',
selection: '#173541',
@ -311,6 +338,7 @@ export const settings = {
},
sublime: {
background: '#303841',
lineBackground: '#30384150',
foreground: '#FFFFFF',
caret: '#FBAC52',
selection: '#4C5964',
@ -322,6 +350,7 @@ export const settings = {
tokyoNightDay: {
light: true,
background: '#e1e2e7',
lineBackground: '#e1e2e750',
foreground: '#3760bf',
caret: '#3760bf',
selection: '#99a7df',
@ -333,6 +362,7 @@ export const settings = {
},
tokyoNightStorm: {
background: '#24283b',
lineBackground: '#24283b50',
foreground: '#7982a9',
caret: '#c0caf5',
selection: '#6f7bb630',
@ -344,6 +374,7 @@ export const settings = {
},
tokyoNight: {
background: '#1a1b26',
lineBackground: '#1a1b2650',
foreground: '#787c99',
caret: '#c0caf5',
selection: '#515c7e40',
@ -355,6 +386,7 @@ export const settings = {
},
vscodeDark: {
background: '#1e1e1e',
lineBackground: '#1e1e1e50',
foreground: '#9cdcfe',
caret: '#c6c6c6',
selection: '#6199ff2f',
@ -368,6 +400,7 @@ export const settings = {
xcodeLight: {
light: true,
background: '#fff',
lineBackground: '#ffffff50',
foreground: '#3D3D3D',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
@ -377,6 +410,7 @@ export const settings = {
},
xcodeDark: {
background: '#292A30',
lineBackground: '#292A3050',
foreground: '#CECFD0',
caret: '#fff',
selection: '#727377',
@ -400,6 +434,7 @@ function getColors(str) {
return colors;
}
// TODO: remove
export function themeColors(theme) {
return getColors(stringifySafe(theme));
}

View File

@ -15,6 +15,7 @@ module.exports = {
highlight: '#bb8800',
// codemirror-theme settings
background: 'var(--background)',
lineBackground: 'var(--lineBackground)',
foreground: 'var(--foreground)',
caret: 'var(--caret)',
selection: 'var(--selection)',