early dark mode

This commit is contained in:
JeremyGamer13 2023-08-24 23:30:10 -06:00
commit 255c33342b
15 changed files with 312 additions and 29 deletions

18
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@blockly/continuous-toolbox": "^5.0.2",
"@blockly/theme-dark": "^6.0.1",
"@sveltejs/adapter-vercel": "^3.0.2",
"file-saver": "^2.0.5",
"js-beautify": "^1.14.9",
@ -46,6 +47,17 @@
"blockly": "^10.0.0"
}
},
"node_modules/@blockly/theme-dark": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-6.0.1.tgz",
"integrity": "sha512-fZa834SKstG31PNkoZ26DLIpevNVBWLDwDT/g99a6EtwqnkZg2VjCjbJDLA0xzrCmxN8AH6zmZU/lAdMoBH8sw==",
"engines": {
"node": ">=8.17.0"
},
"peerDependencies": {
"blockly": "^10.0.0"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz",
@ -2372,6 +2384,12 @@
"integrity": "sha512-7ayim3y4X4vwTLC+SYPijurlx/GoJI0ZemqnoYBcSuqkgnkFCYj8NSYejal1NLdzExjdVm3gsTwRVl9zJJ1cAA==",
"requires": {}
},
"@blockly/theme-dark": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-6.0.1.tgz",
"integrity": "sha512-fZa834SKstG31PNkoZ26DLIpevNVBWLDwDT/g99a6EtwqnkZg2VjCjbJDLA0xzrCmxN8AH6zmZU/lAdMoBH8sw==",
"requires": {}
},
"@esbuild/android-arm": {
"version": "0.18.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.17.tgz",

View file

@ -16,6 +16,7 @@
"type": "module",
"dependencies": {
"@blockly/continuous-toolbox": "^5.0.2",
"@blockly/theme-dark": "^6.0.1",
"@sveltejs/adapter-vercel": "^3.0.2",
"file-saver": "^2.0.5",
"js-beautify": "^1.14.9",

View file

@ -10,11 +10,17 @@
<meta name="theme-color" content="#ff4b4b" />
<meta name="og:image" content="/images/icon.png" />
<meta name="viewport" content="width=device-width" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism.min.css" rel="stylesheet" />
<style id="XTI0GZwZotMzDMi0wcGctLFttIWctMdtLPXI9M0aGGDQyMHRpMViW3E="></style>
<style>
*:not(code, .token) {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
body {
color: black;
}
body.dark {
color: white;
}
a {
color: #ff4b4b;
@ -36,6 +42,7 @@
.blocklyTreeLabel {
font-size: 10px !important;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 0 8px;
}
.categoryBubble {
border: 1px rgba(0,0,0,0.35) solid;
@ -81,9 +88,32 @@
alert.remove();
}
// prism styles
const prismStyles = {
light: null,
dark: null
};
const getPrismStyleUrl_ = (id) => {
switch (id) {
case 'light':
return 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism.min.css';
case 'dark':
return 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.22.0/themes/prism-tomorrow.min.css';
default:
return '';
}
};
const loadPrismStyle_ = (id) => {
const url = getPrismStyleUrl_(id);
console.log('grabbing prism style for', id);
return fetch(url);
};
// handle theme updating
const head = document.head;
const body = document.body;
const updateTheme = () => {
const updateTheme = async () => {
// update body
const mode = localStorage.getItem('tb:theme');
if (mode === 'dark') {
body.setAttribute("class", "dark");
@ -92,6 +122,26 @@
body.removeAttribute("class");
body.style.background = "";
}
// update head
const styleElement = document.getElementById("XTI0GZwZotMzDMi0wcGctLFttIWctMdtLPXI9M0aGGDQyMHRpMViW3E=");
let promise;
let styleCode = '';
let styleId = 'dark';
if (mode === 'dark') {
styleCode = prismStyles.dark;
if (!prismStyles.dark) promise = loadPrismStyle_('dark');
} else {
styleId = 'light';
styleCode = prismStyles.light;
if (!prismStyles.light) promise = loadPrismStyle_('light');
}
if (promise) {
const res = await promise;
const text = await res.text();
styleCode = text;
prismStyles[styleId] = styleCode;
}
styleElement.innerHTML = styleCode;
};
window.themeUpdated_ = () => {

View file

@ -1,5 +1,6 @@
<script>
import { createEventDispatcher } from "svelte";
import { createEventDispatcher, onMount } from "svelte";
import EventManager from "../../resources/events";
import ModalScript from "./createblock.js";
import ColorUtil from "./color.js";
@ -38,14 +39,28 @@
disable: false,
theme: Theme,
renderer: "zelos",
grid: {
spacing: 25,
length: 3,
colour: "#00000022",
snap: false,
},
zoom: {
controls: true,
wheel: true,
wheel: false,
startScale: 1.2,
maxScale: 4,
minScale: 0.25,
scaleSpeed: 1.1,
},
move: {
scrollbars: {
horizontal: true,
vertical: true,
},
drag: true,
wheel: true,
},
};
let workspace;
@ -57,6 +72,13 @@
},
};
onMount(() => {
EventManager.allowAttachment();
EventManager.on(EventManager.EVENT_THEME_CHANGED, () => {
workspace.refreshTheme();
});
});
export let color1 = "#ff0000";
export let color2 = "#00ff00";
export let color3 = "#0000ff";
@ -105,6 +127,7 @@
// create block style
Theme.blockStyles["core_makeablock_colors"] = getBlockStyle();
console.log(Theme);
workspace.refreshTheme();
visible = true;
state = getDefaultState();
@ -145,9 +168,7 @@
type="text"
placeholder="Block ID (ex: numberIsWithinNumbers)"
class="block-id"
style={!validation.id(state.block.id)
? "background-color: #ffaaaa"
: ""}
data-invalid={!validation.id(state.block.id)}
bind:value={state.block.id}
/>
{#if !validation.id(state.block.id)}
@ -335,6 +356,12 @@
align-items: center;
overflow: hidden;
}
:global(body.dark) .bg {
background-color: #333333b0;
}
:global(body.dark) .modal {
background-color: #111;
}
.modal-title {
width: 100%;
@ -346,6 +373,9 @@
align-items: center;
justify-content: center;
}
:global(body.dark) .modal-title {
background-color: #333;
}
.modal-content {
width: 100%;
height: 83%;
@ -377,6 +407,19 @@
outline: 4px solid #ff4b4b44;
transition: 0.25s linear;
}
:global(body.dark) .block-id {
background: transparent;
border-color: rgba(255, 255, 255, 0.7);
color: white;
}
.block-id[data-invalid="true"] {
background-color: #ffabab;
text-decoration: red underline;
}
:global(body.dark) .block-id[data-invalid="true"] {
background-color: #9b0000 !important;
text-decoration: red underline;
}
.block-id-warning {
width: 100%;
@ -395,11 +438,18 @@
border-radius: 12px;
cursor: pointer;
}
:global(body.dark) .block-addition {
color: white;
border-color: #ccc;
}
.block-addition:focus,
.block-addition:hover {
border-color: #ff4b4b;
border-color: #ff4b4b !important;
}
.block-addition:active {
border-color: black;
border-color: black !important;
}
:global(body.dark) .block-addition:active {
border-color: rgb(114, 114, 114) !important;
}
</style>

View file

@ -32,6 +32,9 @@
function getExampleData(color1, color2, color3, color3Included) {
const tokens = ["[{{COLOR1}}]", "[{{COLOR2}}]", "[{{COLOR3}}]"];
if (color3Included && !color3) {
color3 = "#000000";
}
if (!color3 || !color3Included) {
const rgb = ColorUtil.hexToRGB(color1);
const r = Math.max(0, rgb.r - 51);
@ -176,6 +179,13 @@
border: 1px solid rgba(0, 0, 0, 0.25);
}
:global(body.dark) input[type="color"]::-webkit-color-swatch {
border-color: rgba(255, 255, 255, 0.5);
}
:global(body.dark) input[type="color"]::-moz-color-swatch {
border-color: rgba(255, 255, 255, 0.5);
}
.bg {
position: fixed;
left: 0px;
@ -200,6 +210,12 @@
align-items: center;
overflow: hidden;
}
:global(body.dark) .bg {
background-color: #333333b0;
}
:global(body.dark) .modal {
background-color: #111;
}
.modal-title {
width: 100%;
@ -211,6 +227,9 @@
align-items: center;
justify-content: center;
}
:global(body.dark) .modal-title {
background-color: #333;
}
.modal-content {
width: 100%;
height: 75%;
@ -239,6 +258,13 @@
.extensionMenuPreview:active {
background-color: #e9eef2;
}
:global(body.dark) .extensionMenuPreview {
color: #ccc;
}
:global(body.dark) .extensionMenuPreview:focus,
:global(body.dark) .extensionMenuPreview:active {
background-color: #1e1e1e;
}
.extensionBubbleIcon {
width: 20px;
height: 20px;

View file

@ -28,13 +28,14 @@
font-weight: bold;
font-size: 0.75rem;
color: white;
background: #ff4b4b;
background: transparent;
cursor: pointer;
border: 0;
}
button:focus,
button:hover,
button:active {
background: rgb(211, 62, 62);
button:hover {
background: rgba(0, 0, 0, 0.2);
}
:global(body.dark) button:hover {
background: rgba(255, 255, 255, 0.2);
}
</style>

View file

@ -3,7 +3,7 @@
<style>
.divider {
border-right: 1px dashed rgba(0, 0, 0, 0.15);
margin: 0 0.5rem;
height: 90%;
margin: 0.85rem 0.5rem;
height: calc(100% - 0.85rem);
}
</style>

View file

@ -1,15 +1,33 @@
<script>
// Components
import Divider from "$lib/NavigationBar/Divider.svelte";
const switchTheme = () => {
const id = "tb:theme";
const currentData = localStorage.getItem(id);
if (currentData === "dark") {
localStorage.setItem(id, "");
} else {
localStorage.setItem(id, "dark");
}
window.themeUpdated_();
console.log(
"switched theme to",
currentData === "dark" ? "light" : "dark"
);
};
</script>
<div class="nav">
<img
src="/favicon.png"
src="/favicon_any.png"
alt="Logo"
class="logo-margin"
style="height: 100%;"
style="height: 30px;"
/>
<button class="theme-switcher" on:click={switchTheme}>
<img src="/images/theme_switcher.svg" alt="Theme Switcher" />
</button>
<Divider />
<slot />
</div>
@ -23,10 +41,8 @@
position: fixed;
left: 0px;
top: 0px;
width: calc(100% - 8px);
height: calc(var(--nav-height) - 8px);
padding: 4px;
width: 100%;
height: var(--nav-height);
display: flex;
flex-direction: row;
@ -35,6 +51,29 @@
background: #ff4b4b;
}
.logo-margin {
margin-right: 8px;
margin: 0 6px;
margin-left: 10px;
}
.theme-switcher {
background: transparent;
height: 100%;
border: 0;
margin: 0;
cursor: pointer;
}
.theme-switcher:hover {
background: rgba(0, 0, 0, 0.2);
}
.theme-switcher > img {
width: 28px;
height: 28px;
}
:global(body.dark) .theme-switcher:hover {
background: rgba(255, 255, 255, 0.2);
}
:global(body.dark) .nav {
background: #333;
}
</style>

View file

@ -28,4 +28,14 @@
button:active {
background: white;
}
:global(body.dark) button {
color: #ccc;
border-color: #c6c6c6;
}
:global(body.dark) button:focus,
:global(body.dark) button:hover,
:global(body.dark) button:active {
background: #111;
}
</style>

View file

@ -7,7 +7,7 @@ const categoryColor = '#ff4b4b';
function register() {
// used in block creation menu
registerBlock(`${categoryPrefix}builderblock`, {
message0: '...',
message0: '', // empty character breaks block shape
args0: [],
previousStatement: null,
nextStatement: null,

View file

@ -0,0 +1,21 @@
let canAccessWindow = false;
class EventManager {
static allowAttachment () {
canAccessWindow = true;
}
static on (type, callback) {
if (!canAccessWindow) {
throw new Error('EventManager must be used after onMount allows attachment.');
}
window.tbevents_.push({ type, callback });
}
// enums
static get EVENT_THEME_CHANGED () {
return 'THEME';
}
}
export default EventManager;

View file

@ -22,6 +22,7 @@
import Prism from "prismjs";
import * as FileSaver from "file-saver";
import fileDialog from "../resources/fileDialog";
import EventManager from "../resources/events";
import Blockly from "blockly/core";
import * as ContinuousToolboxPlugin from "@blockly/continuous-toolbox";
@ -67,9 +68,15 @@
disable: false,
theme: Theme,
renderer: "zelos",
grid: {
spacing: 25,
length: 3,
colour: "#00000022",
snap: false,
},
zoom: {
controls: true,
wheel: true,
wheel: false,
startScale: 0.8,
maxScale: 4,
minScale: 0.25,
@ -80,6 +87,14 @@
flyoutsVerticalToolbox: ContinuousToolboxPlugin.ContinuousFlyout,
metricsManager: ContinuousToolboxPlugin.ContinuousMetrics,
},
move: {
scrollbars: {
horizontal: true,
vertical: true,
},
drag: true,
wheel: true,
},
};
let workspace;
@ -134,6 +149,11 @@
compiler = new Compiler(workspace);
// workspace was changed
workspace.addChangeListener(updateGeneratedCode);
EventManager.allowAttachment();
EventManager.on(EventManager.EVENT_THEME_CHANGED, () => {
workspace.refreshTheme();
});
});
let fileMenu;
@ -325,10 +345,8 @@
class="project-name"
type="text"
placeholder="Extension ID (ex: extensionID)"
style={"margin-left:4px;margin-right:4px" +
(isExtensionIDInvalid(projectID)
? ";background-color:#ffabab;text-decoration:red underline;"
: "")}
style="margin-left:4px;margin-right:4px"
data-invalid={isExtensionIDInvalid(projectID)}
bind:value={projectID}
on:change={updateGeneratedCode}
/>
@ -515,6 +533,28 @@
background: white;
}
:global(body.dark) input[type="file"]::file-selector-button {
color: #ccc;
border-color: #c6c6c6;
}
:global(body.dark) input[type="file"]::file-selector-button:focus,
:global(body.dark) input[type="file"]::file-selector-button:hover,
:global(body.dark) input[type="file"]::file-selector-button:active {
background: #111;
}
:global(body.dark) input[type="text"],
:global(body.dark) input[type="number"] {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.7);
color: white;
}
:global(body.dark) input[type="text"]:hover,
:global(body.dark) input[type="number"]:hover {
background: transparent;
border: 1px solid dodgerblue;
}
.main {
position: absolute;
left: 0px;
@ -561,6 +601,15 @@
transition: 0.25s;
}
.project-name[data-invalid="true"] {
background-color: #ffabab;
text-decoration: red underline;
}
:global(body.dark) .project-name[data-invalid="true"] {
background-color: #9b0000 !important;
text-decoration: red underline;
}
.extensionIcon {
width: 96px;
height: 96px;
@ -607,6 +656,13 @@
.extensionMenuPreview:active {
background-color: #e9eef2;
}
:global(body.dark) .extensionMenuPreview {
color: #ccc;
}
:global(body.dark) .extensionMenuPreview:focus,
:global(body.dark) .extensionMenuPreview:active {
background-color: #1e1e1e;
}
.extensionBubbleIcon {
width: 20px;
height: 20px;
@ -631,6 +687,9 @@
background: #f9f9f9;
}
:global(body.dark) .blockMenuButtons {
background-color: #111;
}
.blocklyWrapper {
position: relative;
@ -656,6 +715,9 @@
background: #f9f9f9;
}
:global(body.dark) .codeActionsWrapper {
background-color: #111;
}
.codeWrapper {
position: relative;
width: 100%;
@ -674,6 +736,9 @@
white-space: pre-wrap;
font-family: monospace !important;
}
:global(body.dark) .codeDisplay {
background-color: #111;
}
.warning {
background-color: yellow;

BIN
static/favicon_any.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
static/favicon_dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,2 @@
<!-- https://material.io/resources/icons/?search=brightness_3&icon=brightness_3&style=baseline -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white" width="24px" height="24px"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 2c-1.05 0-2.05.16-3 .46 4.06 1.27 7 5.06 7 9.54 0 4.48-2.94 8.27-7 9.54.95.3 1.95.46 3 .46 5.52 0 10-4.48 10-10S14.52 2 9 2z"/></svg>

After

Width:  |  Height:  |  Size: 381 B