@@ -47,11 +55,12 @@ function update() {
-../ts/Synergy../ts/Styles../ts/Shared
\ No newline at end of file
+
diff --git a/web/css/demo.css b/web/css/demo.css
index 0d5c86c..56b2163 100644
--- a/web/css/demo.css
+++ b/web/css/demo.css
@@ -1,5 +1,5 @@
html {background: var(--synergy-site-bg);}
-html, body {color: var(--synergy-text-color); font-family: Cantarell, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Open Sans, Helvetica Neue, Arial, Noto Sans, Roboto, sans-serif; font-size: 18px; overflow-x: hidden;}
+html, body {color: var(--synergy-text-color); font-family: Cantarell, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Open Sans, Helvetica Neue, Arial, Noto Sans, Roboto, sans-serif; font-size: 18px; margin: 0;}
*, *::before, *::after {box-sizing: border-box;}
@@ -9,7 +9,8 @@ header h1 {font-size: 50px;}
header h1 .color {background-clip: text; -webkit-background-clip: text; background-image: linear-gradient(10deg, var(--synergy-border-active), var(--synergy-border)); color: transparent;}
-.settings {margin: 70px 0; display: grid; grid-template-columns: 1fr 1fr; gap: 25px;}
+.settings {margin: 70px 0; display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: start;}
+.settings > * {position: sticky; top: 0;}
.settings h2 {text-align: center;}
.settings .variables {display: grid; gap: 10px 20px; align-items: center; grid-template-columns: max-content 1fr;}
.settings .variables > * {display: flex; gap: 10px; align-items: center;}
@@ -18,8 +19,15 @@ header h1 .color {background-clip: text; -webkit-background-clip: text; backgrou
.settings .presets > * {display: flex; border-radius: 10px; overflow: hidden; cursor: pointer; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1);}
.settings .presets > * > * {height: 100px; flex: 1;}
+.settings .components .item {margin-bottom: 10px;}
+.settings .components .btn-row {margin-top: 15px;}
+.settings .components .box {margin-top: 15px; background-color: var(--synergy-tab-highlight); padding: 15px; border-radius: var(--synergy-border-radius);}
+.settings .components .btn small {display: block; font-weight: 400; font-size: 11px; margin-top: 3px;}
+.settings .components .export .btn-row {margin: 15px 0;}
+
@media screen and (max-width: 850px) {
- .settings {display: flex; flex-direction: column-reverse;}
+ .settings {display: flex; flex-direction: column-reverse; align-items: normal;}
+ .settings > * {position: static;}
}
@media screen and (max-width: 500px) {
@@ -41,4 +49,7 @@ header h1 .color {background-clip: text; -webkit-background-clip: text; backgrou
.inp.color {width: 40px;}
.inp input[type=color] {padding: 0; border: 0;}
-::-webkit-color-swatch, ::-moz-color-swatch {border: 0;}
\ No newline at end of file
+::-webkit-color-swatch, ::-moz-color-swatch {border: 0;}
+
+a {color: var(--synergy-btn-primary-bg);}
+a:hover {color: var(--synergy-btn-primary-bg-hover);}
\ No newline at end of file
diff --git a/web/ts/Export.ts b/web/ts/Export.ts
new file mode 100644
index 0000000..b851375
--- /dev/null
+++ b/web/ts/Export.ts
@@ -0,0 +1,89 @@
+import { Variable, components, variables } from "./Synergy";
+
+export class Export {
+
+ private variables: ComboObject;
+ private components: ComboObject;
+
+ public vars: string | null = null;
+ public css: Result[] = [];
+
+ constructor(variables: ComboObject, components: ComboObject) {
+ this.variables = variables;
+ this.components = components;
+ }
+
+ async process() {
+
+ this.vars = this.getVariables();
+ let cssParts = [this.vars];
+
+ for (let c of components) {
+ if (!this.components[c.id]) continue;
+ let value = await (await fetch(`./${c.id}.css`)).text();
+ value = `/* ${c.name} */\n\n${value}`;
+ cssParts.push(value);
+ }
+ let css = cssParts.join("\n\n/* ------------------- */\n\n");
+
+ this.css = [];
+ await this.addResult("synergy.min.css", this.minify(css));
+ await this.addResult("synergy.css", css);
+
+ return this.css;
+
+ }
+
+ getVariables() {
+ let root: string[] = [];
+ for (let v of variables) {
+ if (!this.required(v)) continue;
+ root.push(`\t--synergy-${v.name}: ${this.variables[v.name]};`);
+ }
+ return `:root {\n${root.join("\n")}\n}`;
+ }
+
+ required(variable: Variable) {
+ if (!variable.requiredBy) return true;
+ for (let id of variable.requiredBy) {
+ if (this.components[id]) return true;
+ }
+ return false;
+ }
+
+ async addResult(name: string, css: string) {
+ this.css.push({
+ name,
+ css,
+ size: this.getSize(css),
+ size_gzip: await this.getCompressedSize(css)
+ });
+ }
+
+ async getCompressedSize(content: string) {
+ let ds = new CompressionStream("gzip");
+ let blob = new Blob([content]);
+ let compressedStream = blob.stream().pipeThrough(ds);
+ return (await new Response(compressedStream).blob()).size;
+ }
+
+ getSize(content: string) {
+ return (new TextEncoder().encode(content)).length
+ }
+
+ minify(value: string) {
+ return value
+ .replace(/([^0-9a-zA-Z\.#])\s+/g, "$1")
+ .replace(/\s([^0-9a-zA-Z\.#]+)/g, "$1")
+ .replace(/;}/g, "}")
+ .replace(/\/\*.*?\*\//g, "");
+ }
+
+}
+
+export interface Result {
+ name: string,
+ css: string,
+ size: number,
+ size_gzip: number
+}
diff --git a/web/ts/Shared.ts b/web/ts/Shared.ts
index fe37e25..f1132c6 100644
--- a/web/ts/Shared.ts
+++ b/web/ts/Shared.ts
@@ -1,19 +1,13 @@
import { reactive, watch } from "vue";
-import { getDefaultVariables } from "./Synergy";
+import { getDefaultComponents, getDefaultVariables } from "./Synergy";
import { setVariables } from "./Styles";
-let values = getDefaultVariables();
+export let variableValues = reactive
(getDefaultVariables());
-export let variableValues = reactive(values);
+export let selectedComponents = reactive(getDefaultComponents());
watch(() => variableValues, () => {
setVariables(variableValues);
}, {deep: true});
-setVariables(values);
-
-export function applyVariables(variables: ComboObject) {
- Object.keys(variables).forEach(key => {
- variableValues[key] = variables[key];
- });
-}
+setVariables(variableValues);
\ No newline at end of file
diff --git a/web/ts/Synergy.ts b/web/ts/Synergy.ts
index ac6e21b..5891ed3 100644
--- a/web/ts/Synergy.ts
+++ b/web/ts/Synergy.ts
@@ -1,38 +1,60 @@
import { Preset } from "./Preset";
-export let variables: Variable[] = [
- {name: "border", type: "color"},
- {name: "border-active", type: "color"},
- {name: "border-width", type: "number"},
- {name: "border-radius", type: "number"},
- {name: "focus-highlight", type: "color"},
- {name: "tab-highlight", type: "color"},
- {name: "tab-bar-height", type: "number"},
- {name: "label", type: "color"},
- {name: "label-active", type: "color"},
- {name: "btn-primary-bg", type: "color"},
- {name: "btn-primary-bg-hover", type: "color"},
- {name: "btn-primary-bg-active", type: "color"},
- {name: "btn-bg", type: "color"},
- {name: "btn-bg-hover", type: "color"},
- {name: "btn-bg-active", type: "color"},
- {name: "text-color", type: "color"},
- {name: "bg", type: "color"},
+export const variables: Variable[] = [
+ {name: "border", type: "color", requiredBy: ["input", "checkbox", "toggle", "tabs"]},
+ {name: "border-active", type: "color", requiredBy: ["input", "checkbox", "toggle", "tabs"]},
+ {name: "border-width", type: "number", requiredBy: ["input", "checkbox", "toggle"]},
+ {name: "border-radius", type: "number", requiredBy: ["input", "button", "checkbox", "tabs"]},
+ {name: "focus-highlight", type: "color", requiredBy: ["input", "button", "checkbox"]},
+ {name: "tab-highlight", type: "color", requiredBy: ["tabs"]},
+ {name: "tab-bar-height", type: "number", requiredBy: ["tabs"]},
+ {name: "label", type: "color", requiredBy: ["input"]},
+ {name: "label-active", type: "color", requiredBy: ["input"]},
+ {name: "btn-primary-bg", type: "color", requiredBy: ["button"]},
+ {name: "btn-primary-bg-hover", type: "color", requiredBy: ["button"]},
+ {name: "btn-primary-bg-active", type: "color", requiredBy: ["button"]},
+ {name: "btn-bg", type: "color", requiredBy: ["button"]},
+ {name: "btn-bg-hover", type: "color", requiredBy: ["button"]},
+ {name: "btn-bg-active", type: "color", requiredBy: ["button"]},
+ {name: "text-color", type: "color", requiredBy: ["input", "button"]},
+ {name: "bg", type: "color", requiredBy: ["input", "checkbox", "toggle"]},
{name: "site-bg", type: "color"}
];
+export const components: Component[] = [
+ {name: "Button", id: "button"},
+ {name: "Input", id: "input"},
+ {name: "Checkbox & radio", id: "checkbox"},
+ {name: "Tabs", id: "tabs"},
+ {name: "Toggle", id: "toggle"},
+];
+
export interface Variable {
name: string,
- type: VariableType
+ type: VariableType,
+ requiredBy?: ComponentID[]
+}
+
+export type ComponentID = "button" | "input" | "checkbox" | "tabs" | "toggle";
+
+export interface Component {
+ name: string,
+ id: ComponentID
}
export type VariableType = "color" | "number";
export function getDefaultVariables() {
return {
- "border-width": "2px",
+ "border-width": "2px",
"border-radius": ".375rem",
- "tab-bar-height": "3px",
+ "tab-bar-height": "2px",
...Preset.getRandom().getVariables()
};
}
+
+export function getDefaultComponents() {
+ let res: ComboObject = {};
+ components.forEach(c => res[c.id] = true);
+ return res;
+}
\ No newline at end of file