2023-06-02 15:24:32 +02:00
|
|
|
import { sass as langSass } from '@codemirror/lang-sass';
|
|
|
|
import { Text } from '@codemirror/state';
|
|
|
|
import { EditorView } from 'codemirror';
|
|
|
|
|
|
|
|
import { compileString } from '../sass.default.js';
|
2023-06-02 16:53:32 +02:00
|
|
|
import { editorSetup, outputSetup } from './editor-setup.js';
|
|
|
|
import { playgroundTheme } from './theme.js';
|
2023-06-02 15:24:32 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
function setupPlayground() {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
|
|
const editor = new EditorView({
|
|
|
|
extensions: [
|
|
|
|
editorSetup,
|
|
|
|
langSass(),
|
|
|
|
playgroundTheme,
|
|
|
|
EditorView.updateListener.of((v) => {
|
|
|
|
if (v.docChanged) {
|
|
|
|
updateCSS();
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
],
|
|
|
|
parent: document.getElementById('editor') || document.body,
|
|
|
|
});
|
2023-06-02 18:52:24 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
// Setup CSS view
|
|
|
|
const viewer = new EditorView({
|
|
|
|
// TODO: Confirm lang sass is good for CSS.
|
|
|
|
extensions: [outputSetup, langSass(), playgroundTheme],
|
|
|
|
parent: document.getElementById('css-view') || document.body,
|
|
|
|
});
|
2023-06-02 15:24:32 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
function getSettingsFromDOM(): {
|
|
|
|
'input-format': string;
|
|
|
|
'output-format': string;
|
|
|
|
} {
|
|
|
|
const options = document.querySelectorAll('[data-active]');
|
|
|
|
const settings = Array.from(options).reduce((acc, option) => {
|
|
|
|
acc[option.dataset.setting] = option.dataset.active as string;
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
return settings;
|
|
|
|
}
|
|
|
|
|
|
|
|
type TabbarItemDataset = {
|
|
|
|
value: string;
|
|
|
|
setting: string;
|
|
|
|
};
|
|
|
|
function attachListeners() {
|
|
|
|
const options = document.querySelectorAll('[data-value]');
|
2023-06-02 18:52:24 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
function clickHandler(event) {
|
|
|
|
const settings = event.currentTarget.dataset as TabbarItemDataset;
|
2023-06-02 18:52:24 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
const tabbar = document.querySelector(
|
|
|
|
`[data-active][data-setting="${settings.setting}"]`,
|
|
|
|
);
|
|
|
|
const currentValue = tabbar?.dataset.active;
|
|
|
|
if (currentValue !== settings.value) {
|
|
|
|
tabbar.dataset.active = settings.value;
|
2023-06-02 18:52:24 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
updateCSS();
|
|
|
|
}
|
2023-06-02 18:52:24 +02:00
|
|
|
}
|
2023-06-05 15:25:55 +02:00
|
|
|
Array.from(options).forEach((option) => {
|
|
|
|
option.addEventListener('click', clickHandler);
|
|
|
|
});
|
2023-06-02 18:52:24 +02:00
|
|
|
}
|
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
function updateCSS() {
|
|
|
|
const val = editor.state.doc.toString();
|
|
|
|
const css = parse(val);
|
|
|
|
const text = Text.of(css.split('\n'));
|
|
|
|
viewer.dispatch({
|
|
|
|
changes: {
|
|
|
|
from: 0,
|
|
|
|
to: viewer.state.doc.toString().length,
|
|
|
|
insert: text,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2023-06-02 15:24:32 +02:00
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
function parse(css: string): string {
|
|
|
|
const settings = getSettingsFromDOM();
|
|
|
|
let result = '';
|
|
|
|
try {
|
|
|
|
result = compileString(css, {
|
|
|
|
syntax: settings['input-format'],
|
|
|
|
style: settings['output-format'],
|
|
|
|
}).css;
|
|
|
|
} catch (error) {
|
|
|
|
result = error?.toString() || '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2023-06-02 15:24:32 +02:00
|
|
|
}
|
|
|
|
|
2023-06-05 15:25:55 +02:00
|
|
|
attachListeners();
|
|
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
|
|
document.addEventListener('DOMContentLoaded', setupPlayground);
|
|
|
|
} else {
|
|
|
|
setupPlayground();
|
2023-06-02 15:24:32 +02:00
|
|
|
}
|