Skip to content

Commit

Permalink
feat(examples): add color themes generator example
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Feb 22, 2021
1 parent b8ceed6 commit 0675d89
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 0 deletions.
Binary file added assets/examples/color-themes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions examples/color-themes/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
build
dev
node_modules
yarn.lock
!snowpack.config.js
!*.d.ts
15 changes: 15 additions & 0 deletions examples/color-themes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# color-themes

![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/color-themes.png)

[Live demo](http://demo.thi.ng/umbrella/color-themes/)

Please refer to the [example build instructions](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions) on the wiki.

## Authors

- Karsten Schmidt

## License

© 2021 Karsten Schmidt // Apache Software License 2.0
44 changes: 44 additions & 0 deletions examples/color-themes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "color-themes",
"version": "0.0.1",
"description": "Probabilistic color theme generator",
"repository": "https://github.com/thi-ng/umbrella",
"author": "Karsten Schmidt <[email protected]>",
"license": "Apache-2.0",
"scripts": {
"clean": "../../node_modules/.bin/rimraf build node_modules/.cache",
"start": "../../node_modules/.bin/snowpack dev --reload",
"build": "../../node_modules/.bin/snowpack build"
},
"devDependencies": {
"@thi.ng/snowpack-env": "^2.3.3"
},
"dependencies": {
"@thi.ng/checks": "latest",
"@thi.ng/color": "latest",
"@thi.ng/hiccup-html": "latest",
"@thi.ng/hiccup-svg": "latest",
"@thi.ng/random": "latest",
"@thi.ng/rdom": "latest",
"@thi.ng/rdom-components": "latest",
"@thi.ng/rstream": "latest"
},
"browserslist": [
"last 3 Chrome versions"
],
"browser": {
"process": false
},
"thi.ng": {
"readme": [
"color",
"hiccup-html",
"hiccup-svg",
"random",
"rdom",
"rdom-components",
"rstream"
],
"screenshot": "examples/color-themes.png"
}
}
43 changes: 43 additions & 0 deletions examples/color-themes/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>color-themes</title>
<link
href="https://unpkg.com/tachyons@4/css/tachyons.min.css"
rel="stylesheet"
/>
<style>
.grid {
display: grid;
grid-template-columns: 2fr 1fr 3fr;
gap: 1rem;
}

.grid2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
</style>
<script
async
defer
data-domain="demo.thi.ng"
src="https://plausible.io/js/plausible.js"
></script>
</head>
<body class="sans-serif ma0 overflow-y-hidden">
<div id="app"></div>
<!-- <div>
<a
class="link"
href="https://github.com/thi-ng/umbrella/tree/develop/examples/color-themes"
>Source code</a
>
</div> -->
<script type="module" src="/_dist_/index.js"></script>
</body>
</html>
29 changes: 29 additions & 0 deletions examples/color-themes/snowpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
public: "/",
src: "/_dist_",
},
plugins: [
"@snowpack/plugin-typescript",
[
"@snowpack/plugin-webpack",
{
extendConfig: (config) => {
config.node = {
process: false,
setImmediate: false,
util: "empty",
};
return config;
},
},
],
],
installOptions: {
installTypes: true,
},
buildOptions: {
baseUrl: "/umbrella/color-themes",
},
};
217 changes: 217 additions & 0 deletions examples/color-themes/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import { isMobile, isString } from "@thi.ng/checks";
import {
ColorRangePreset,
colorsFromTheme,
ColorThemePart,
COLOR_RANGES,
css,
CSSColorName,
distCIEDE2000,
lch,
LCH,
proximity,
sort,
swatchesH,
} from "@thi.ng/color";
import {
button,
checkbox,
div,
inputColor,
inputRange,
span,
} from "@thi.ng/hiccup-html";
import { svg } from "@thi.ng/hiccup-svg";
import { SYSTEM, XsAdd } from "@thi.ng/random";
import {
$compile,
$inputNum,
$list,
$refresh,
ComponentLike,
} from "@thi.ng/rdom";
import { staticDropdown } from "@thi.ng/rdom-components";
import { debounce, reactive, Stream, sync, SyncTuple } from "@thi.ng/rstream";

// pre-sort range preset IDs for dropdown menus
const RANGE_IDs = <ColorRangePreset[]>Object.keys(COLOR_RANGES).sort();

///////////////////////// UI widgets

const themePartControls = ([id, part]: [string, ColorThemePart]) => {
const stream = <Stream<ColorThemePart>>parts.getSourceForID(id);
return div(
".grid.mb3",
{},
staticDropdown(RANGE_IDs, reactive(<string>part.range), {
attribs: {
title: "color range preset",
oninput: (e) =>
stream.next({
...part,
range: <ColorRangePreset>(
(<HTMLInputElement>e.target).value
),
}),
},
}),
inputColor({
value: css(<LCH>part.base),
title: "base color",
onchange: (e) =>
stream.next({
...part,
base: lch((<HTMLInputElement>e.target).value),
}),
}),
inputRange({
min: 0,
max: 1,
step: 0.01,
value: part.weight,
title: "weight",
onchange: (e) =>
stream.next({
...part,
weight: parseFloat((<HTMLInputElement>e.target).value),
}),
})
);
};

const control = (label: string, body: ComponentLike) =>
div(".grid2.mb3", {}, span({}, label), body);

const themeSwatches = async ({
parts,
num,
variance,
seed,
sorted,
}: SyncTuple<typeof mainInputs>) => {
const colors = [
...colorsFromTheme(Object.values(parts), {
num,
variance,
rnd: new XsAdd(seed),
}),
];
if (sorted) {
sort(colors, proximity(lch(1, 0, 0), distCIEDE2000()));
}
return <ComponentLike>svg(
{
width: "100vw",
height: "100vh",
viewBox: `0 0 ${num * 5} 100`,
preserveAspectRatio: "none",
convert: true,
},
swatchesH(colors, 5, 100)
);
};

///////////////////////// streams / app state

const themePart = (
range: ColorRangePreset,
base: LCH | CSSColorName,
weight = 1
) =>
reactive<ColorThemePart>({
range,
base: isString(base) ? lch(base) : base,
weight,
});

const randomizeThemeParts = () => {
for (let part of Object.values(parts.getSources())) {
part.next({
range: RANGE_IDs[SYSTEM.int() % RANGE_IDs.length],
base: lch.random(),
weight: SYSTEM.float(),
});
}
};

const parts = sync({
src: {
0: themePart("bright", "goldenrod"),
1: themePart("hard", "turquoise", 0.33),
2: themePart("cool", "fuchsia", 0.5),
3: themePart("warm", "seagreen", 0.1),
},
});

// debounce needed for batch update via randomizeTheme()
const debouncedParts = parts.subscribe(debounce(16));

const num = reactive(isMobile() ? 100 : 200);
const variance = reactive(0.05);
const sorted = reactive(false);
const seed = reactive(0xdecafbad);
const mainInputs = <const>{
parts: debouncedParts,
num,
variance,
seed,
sorted,
};
const main = sync({ src: mainInputs });

///////////////////////// UI components

$compile(
div(
{},
// color swatches
$refresh<SyncTuple<typeof mainInputs>>(main, themeSwatches),
// theme controls in HUD UI
div(
".z-1.fixed.top-0.left-0.bg-white-80.ma3-m.ma3-l.pa3.w-100.w-50-m.w-33-l",
{},
// list of controls for each theme part
$list<[string, ColorThemePart]>(
debouncedParts.map((parts) => Object.entries(parts)),
"div",
{},
themePartControls
),
// global controls: variance, random seed, sorting
control(
"variance",
inputRange({
min: 0,
max: 0.2,
step: 0.005,
value: variance,
oninput: $inputNum(variance),
})
),
control(
"random seed",
inputRange({
min: 0,
max: 1 << 30,
value: seed,
oninput: $inputNum(seed),
})
),
control(
"sort",
checkbox({
checked: sorted,
onchange: (e) =>
sorted.next(
Boolean((<HTMLInputElement>e.target).checked)
),
})
),
button(
".bg-black.white.w4",
{ onclick: randomizeThemeParts },
"randomize"
)
)
)
).mount(document.getElementById("app")!);
Loading

0 comments on commit 0675d89

Please sign in to comment.