From d43e573fb1635f9283c79697306a881ca2be170b Mon Sep 17 00:00:00 2001 From: disconcision Date: Tue, 30 Jan 2024 21:52:08 -0500 Subject: [PATCH 01/14] enter the world tree --- src/data/Tools.tsx | 28 ++++++++++++---- src/data/World.tsx | 46 ++++++++------------------ src/index.css | 49 +++++++++++++++++++++++++++- src/syntax/Exp.tsx | 29 +++++++++++++++++ src/syntax/ExpToPat.tsx | 22 +++++-------- src/syntax/Node.tsx | 6 ++++ src/view/ExpView.tsx | 71 +++++++++++++++++++++++++---------------- src/view/ToolsView.tsx | 24 +++++++++++--- 8 files changed, 189 insertions(+), 86 deletions(-) diff --git a/src/data/Tools.tsx b/src/data/Tools.tsx index 5305cc4..4d98bf2 100644 --- a/src/data/Tools.tsx +++ b/src/data/Tools.tsx @@ -4,8 +4,6 @@ import * as Transform from "../Transform"; type Base = { source: Pat.t; result: Pat.t; sound: Sound.Sfxbank }; - - const zero = Pat.p_const("๐ŸŒ‘"); const one = Pat.p_const("๐ŸŒ˜"); const hole = Pat.p_const("โ“"); @@ -31,6 +29,20 @@ const times_x = bin_x("โœ–๏ธ"); const times_y = bin_y("โœ–๏ธ"); const equals_x = bin_x("๐ŸŸฐ"); +const B = Pat.p_const("ษ–"); +const B_ = bin_x("ษ–"); + +const b_def: Base = { + source: B_(var_a, var_b), + result: plus_x(times_x(B_(one, zero), var_a), var_b), + sound: "tiup", +}; +const b_def2: Base = { + source: plus_x(one, one), + result: B_(one, zero), + sound: "tiup", +}; + const commute_plus: Base = { source: plus_x(var_a, var_b), result: plus_x(var_b, var_a), @@ -87,13 +99,13 @@ const distribute_times_plus: Base = { const mk_mk = (result: Pat.t): Base => ({ source: hole, - result:result, - sound: "klohk",//TODO + result: result, + sound: "klohk", //TODO }); const mk_wrap = (result: Pat.t): Base => ({ source: var_a, - result:result, - sound: "klohk",//TODO + result: result, + sound: "klohk", //TODO }); const mk_one = mk_mk(one); const mk_zero = mk_mk(zero); @@ -156,6 +168,8 @@ export const init = [ identity_times, distribute_times_plus, double_neg, + b_def, + b_def2, ].map(mk); -export const _init =makers.map(mk); \ No newline at end of file +export const _init = makers.map(mk); diff --git a/src/data/World.tsx b/src/data/World.tsx index f0217fb..0df6c8f 100644 --- a/src/data/World.tsx +++ b/src/data/World.tsx @@ -1,9 +1,12 @@ -import { Exp, atom, comp } from "../syntax/Exp"; +import { Exp, atom, comp, flat } from "../syntax/Exp"; +import { empty } from "../syntax/Path"; // โ˜๏ธ ๐Ÿงฉ ๐Ÿฆท ๐Ÿฆ  ๐ŸŒธ ๐Ÿ„ ๐ŸŽฒ ๐Ÿ -// โž• โž– โœ–๏ธ โž— ๐ŸŸฐ ๐ŸŒ• ๐ŸŒ˜ 0๏ธโƒฃ 1๏ธโƒฃ +// โž• โž– โœ–๏ธ โž— ๐ŸŸฐ ๐ŸŒ• ๐ŸŒ˜ ๐ŸŒ‘ 0๏ธโƒฃ 1๏ธโƒฃ โ“ -export const init: Exp = comp([ +const B = flat("ษ–"); + +export const alg: Exp = comp([ atom("โž•"), comp([ atom("โž•"), @@ -17,41 +20,20 @@ export const init: Exp = comp([ ]), ]); -export const _init:Exp = atom("โ“"); +const lab: Exp = comp([atom("โž•"), atom("โ“"), atom("โ“")]); -export const moons: Exp = comp([ - atom("โž•"), - comp([ - atom("โž•"), - comp([atom("โž•"), atom("๐ŸŒ˜๐ŸŒ•"), comp([atom("โž–"), atom("๐ŸŒ˜๐ŸŒ•๐ŸŒ•๐ŸŒ•๐ŸŒ˜")])]), - atom("๐ŸŒ˜๐ŸŒ• "), - ]), - comp([ - atom("โž•"), - comp([atom("โœ–๏ธ"), atom("๐ŸŒ•"), atom("๐ŸŒ˜")]), - comp([atom("โœ–๏ธ"), atom("๐ŸŒ˜๐ŸŒ•๐ŸŒ˜๐ŸŒ• "), atom("๐ŸŒ˜๐ŸŒ˜")]), - ]), -]); - -const pv = (hd: string, tl: Exp) => comp([atom("."), atom(hd), tl]); - -export const moons2: Exp = comp([ +const moons: Exp = comp([ atom("โž•"), comp([ atom("โž•"), comp([ atom("โž•"), - pv("๐ŸŒ˜", atom("๐ŸŒ•")), - comp([atom("โž–"), pv("๐ŸŒ˜", pv("๐ŸŒ•", pv("๐ŸŒ•", pv("๐ŸŒ•", atom("๐ŸŒ˜")))))]), - ]), - pv("๐ŸŒ˜", atom("๐ŸŒ•")), - ]), - comp([ - atom("โž•"), - comp([ - atom("โœ–๏ธ"), - pv("๐ŸŒ˜", pv("๐ŸŒ•", pv("๐ŸŒ˜", atom("๐ŸŒ•")))), - pv("๐ŸŒ˜", atom("๐ŸŒ˜")), + B(["๐ŸŒ˜", "๐ŸŒ‘"]), + comp([atom("โž–"), B(["๐ŸŒ˜", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ˜"]), atom("๐ŸŒ˜")]), ]), + B(["๐ŸŒ˜", "๐ŸŒ‘"]), ]), + comp([atom("โœ–๏ธ"), B(["๐ŸŒ˜", "๐ŸŒ‘", "๐ŸŒ˜", "๐ŸŒ‘"]), B(["๐ŸŒ˜", "๐ŸŒ˜"])]), ]); + +export const init: Exp = comp([atom("ไทถ"), alg, moons, lab]); diff --git a/src/index.css b/src/index.css index a43f631..79fef06 100644 --- a/src/index.css +++ b/src/index.css @@ -447,7 +447,7 @@ code { } .node-container.TreeLeft .node.comp .head { grid-column: 1; - grid-row: 1/3; + grid-row: 1/4; } #seed:has(.LinearPrefix), @@ -1198,3 +1198,50 @@ body:has(#main.Dark) { -0.1em -0.1em 0.2em #ebfff744, -0.2em -0.2em 0.4em #d2fff044, -0.4em -0.4em 0.8em #cff2e644, -0.8em -0.8em 1.6em #d2fff044; } + +#stage .node.ไทถ { + border-radius: 2.7em 0.3em 0.3em 2.7em; + display: grid; + grid-auto-flow: unset; + grid-template-columns: fit-content(1em) 1fr; + grid-template-rows: repeat(1fr); + background: none; + box-shadow: -1em 0em 1.5em #34b59516; + border: none; + border-left: 0.3px solid #19dac5; +} +#noolbox .node.digits .node, +#stage .node.digits .node { + /* background: none; */ + box-shadow: none; + padding: 0; + border: none; + /* width: 1.1em; */ + /* border-radius: 0.1em; */ + /* height: 1.7em; */ +} + +#noolbox .node.digits, +#stage .node.digits { + border-radius: 0.8em; + padding: 0; + margin: 0; + /* height: 1em; */ +} + +#noolbox .node.comp.digits .head, +#stage .node.comp.digits .head { + color: black; + text-shadow: none; + padding: 0; +} + +#stage .node.comp.digits.selected .head { + /* filter: brightness(0.8) !important; */ +} + +#noolbox .node:not(.digits):has(.digits) > .digits, +#stage .node:not(.digits):has(.digits) > .digits { + padding-left: 0.15em; + padding-right: 0.15em; +} \ No newline at end of file diff --git a/src/syntax/Exp.tsx b/src/syntax/Exp.tsx index b4c951e..738dda2 100644 --- a/src/syntax/Exp.tsx +++ b/src/syntax/Exp.tsx @@ -11,3 +11,32 @@ export const equals = Node.equals; export const equals_id = Node.equals_id; export const erase = Node.erase; export const depth = Node.depth; + +export const head = (e: Exp): string => + e.t == "Comp" && e.kids.length > 0 && e.kids[0].t == "Atom" + ? e.kids[0].sym + : "headless"; + +export const head_is = (s: string, e: Exp): boolean => head(e) === s; + +export const head_id = (e: Exp): number | undefined => + e.t == "Comp" && e.kids.length > 0 && e.kids[0].t == "Atom" + ? e.kids[0].id + : undefined; + +const cons = + (base: string) => + (hd: string, tl: Exp): Exp => + comp([atom(base), atom(hd), tl]); + +export const flat = + (base: string) => + (contents: string[]): Exp => + contents.length == 0 + ? atom("ษ–") + : contents + .slice(0, -1) + .reduceRight( + (acc, cur) => cons(base)(cur, acc), + atom(contents.slice(-1)[0]) + ); diff --git a/src/syntax/ExpToPat.tsx b/src/syntax/ExpToPat.tsx index 5905310..749950e 100644 --- a/src/syntax/ExpToPat.tsx +++ b/src/syntax/ExpToPat.tsx @@ -1,4 +1,4 @@ -import { Exp } from "../syntax/Exp"; +import * as Exp from "../syntax/Exp"; import * as Pat from "../syntax/Pat"; import * as Id from "../syntax/ID"; import * as ToolsExp from "../data/ToolsExp"; @@ -44,7 +44,7 @@ type MapIdToSymbol = Map; type res = "NotTool" | { source: Pat.t; result: Pat.t }; -const extract_id_symbol_list = (e: Exp): pair_of_id_and_symbol[] => { +const extract_id_symbol_list = (e: Exp.t): pair_of_id_and_symbol[] => { switch (e.t) { case "Atom": return [{ id: e.id, symbol: e.sym }]; @@ -58,7 +58,7 @@ const extract_id_symbol_list = (e: Exp): pair_of_id_and_symbol[] => { } }; // like above but instead returning MapIdToSymbol -const extract_id_symbol_map = (e: Exp): MapIdToSymbol => { +const extract_id_symbol_map = (e: Exp.t): MapIdToSymbol => { const res = new Map(); switch (e.t) { case "Atom": @@ -91,18 +91,12 @@ const get_or_fresh_id = (map: map_of_ids, id: number): number => { return Id.mk(); }; -const head_id = (e: Exp): number | undefined => { - if (e.t == "Comp" && e.kids.length > 0 && e.kids[0].t == "Atom") - return e.kids[0].id; - return undefined; -}; - //try to get id from head using above; if it's there, comp id becomes that id + 1000 -const get_of_fresh_comp_id = (map: map_of_ids, e: Exp): number => - get_or_fresh_id(map, head_id(e) ?? Id.mk()) + 1000; +const get_of_fresh_comp_id = (map: map_of_ids, e: Exp.t): number => + get_or_fresh_id(map, Exp.head_id(e) ?? Id.mk()) + 1000; const convert_exp_to_pat_getting_ids_from_map = ( - e: Exp, + e: Exp.t, map: map_of_ids ): Pat.t => { switch (e.t) { @@ -225,7 +219,7 @@ const match_up_consts = ( return res; }; -const convert_inner = (s: Exp, r: Exp): res => { +const convert_inner = (s: Exp.t, r: Exp.t): res => { const source_symbols = extract_id_symbol_map(s); const [source_vars, source_consts] = parition_symbol_map_into_vars_and_consts(source_symbols); @@ -243,7 +237,7 @@ const convert_inner = (s: Exp, r: Exp): res => { /* If the expression is rooted in binop =, treat lhs and rhs as source and result of a transformation */ -export const convert = (e: Exp): res => { +export const convert = (e: Exp.t): res => { if ( e.t == "Comp" && e.kids.length == 3 && diff --git a/src/syntax/Node.tsx b/src/syntax/Node.tsx index 2fa8143..eeee93a 100644 --- a/src/syntax/Node.tsx +++ b/src/syntax/Node.tsx @@ -37,6 +37,12 @@ export function map_ids(f: (id: ID.t) => ID.t, e: t): t { } } +export function head(e: t): T | undefined { + return e.t == "Comp" && e.kids.length > 0 && e.kids[0].t == "Atom" + ? e.kids[0].sym + : undefined; +} + /* Zero out all ids */ export function erase(x: t): t { return map_ids((_) => 0, x); diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index 0f01ffd..1615025 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -1,8 +1,8 @@ -import { Component } from "solid-js"; +import { Component, Switch, Match } from "solid-js"; import { For, Show, Index } from "solid-js"; //import Rand from "rand-seed"; import * as Pat from "../syntax/Pat"; -import { Exp } from "../syntax/Exp"; +import * as Exp from "../syntax/Exp"; import * as Action from "../Action"; import * as Path from "../syntax/Path"; import * as Statics from "../Statics"; @@ -11,7 +11,7 @@ import * as Names from "../Names"; import * as Settings from "../Settings"; type expviewprops = { - node: Exp; + node: Exp.t; info: Statics.InfoMap; selection: Stage.selection; animate: boolean; @@ -64,7 +64,9 @@ const ExpViewGo: Component = (props) => { classList={{ animate: props.animate }} onpointerdown={setSelect(props)} > -
{Names.get(props.symbols, props.node.sym)}
+
+ {Names.get(props.symbols, props.node.sym)} +
} > @@ -79,29 +81,42 @@ const ExpViewGo: Component = (props) => { ); case "Comp": return ( -
- { - - {(kid, i) => ( - - )} - - } -
+ error}> + +
+ { + + {(kid, i) => ( + + )} + + } +
+
+
); } }; @@ -124,7 +139,7 @@ export const ExpView: Component<{ }); export const ViewOnly: Component<{ - node: Exp; + node: Exp.t; symbols: Settings.symbols; }> = (props) => ExpViewGo({ diff --git a/src/view/ToolsView.tsx b/src/view/ToolsView.tsx index 9eef6a5..e222282 100644 --- a/src/view/ToolsView.tsx +++ b/src/view/ToolsView.tsx @@ -13,6 +13,7 @@ import * as Sound from "../Sound"; import { map_ids } from "../syntax/Node"; import * as Util from "../Util"; import * as Stage from "../Stage"; +import { head } from "../syntax/Node"; export const Toolbar: Component<{ model: Model; inject: Action.Inject }> = ( props @@ -24,6 +25,8 @@ export const Toolbar: Component<{ model: Model; inject: Action.Inject }> = ( ); }; +const head_is = (sym: string, node: Pat.t): boolean => head(node)?.name === sym; + const PatView: Component<{ p: Pat.t; is_head: boolean; @@ -34,9 +37,13 @@ const PatView: Component<{ return (
{Names.get(props.symbols, props.p.sym.name)}
@@ -44,8 +51,14 @@ const PatView: Component<{ } case "Comp": return ( -
- +
+ {(kid, i) => PatView({ p: kid, is_head: i() === 0, symbols: props.symbols }) } @@ -210,12 +223,15 @@ const TransformView: Component<{ ); }; -const select_transforms = (stage:Stage.t,tools: ToolBox.t): [number, Transform][] => { +const select_transforms = ( + stage: Stage.t, + tools: ToolBox.t +): [number, Transform][] => { //const filtered_transforms = filter_transforms(stage, tools.transforms); const filtered_transforms = tools.transforms; /* want to take tools.size tools starting at tools.offset (index into tools) and treat the list as a ring buffer */ - + const len = filtered_transforms.length; const offset = tools.offset % len; const size = tools.size; From 41163d9c7f26d511174412892d9921f561430133 Mon Sep 17 00:00:00 2001 From: disconcision Date: Fri, 2 Feb 2024 01:46:01 -0500 Subject: [PATCH 02/14] experimentation with reconcile --- src/Update.tsx | 10 +++++----- src/data/World.tsx | 2 +- src/index.css | 9 +++++++-- src/view/ExpView.tsx | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Update.tsx b/src/Update.tsx index 1e779ca..19180a6 100644 --- a/src/Update.tsx +++ b/src/Update.tsx @@ -15,7 +15,7 @@ import { SetStoreFunction } from "solid-js/store"; import * as Path from "./syntax/Path"; import * as Animate from "./Animate"; import * as Util from "./Util"; - +import { reconcile } from "solid-js/store"; export type result = Model.t | "NoChange"; @@ -206,7 +206,8 @@ export const update = (model: Model.t, action: Action.t): result => { }, }; case "wheelNumTools": - const clamp = (x:number, a:number, b:number) => Math.max( a, Math.min(x, b) ); + const clamp = (x: number, a: number, b: number) => + Math.max(a, Math.min(x, b)); console.log("wheelNumTools:" + action.offset + ":" + model.tools.size); return { ...model, @@ -215,9 +216,7 @@ export const update = (model: Model.t, action: Action.t): result => { size: clamp( model.tools.size + action.offset, 1, - model.tools.transforms.length, - - + model.tools.transforms.length ), }, }; @@ -244,6 +243,7 @@ export const go = ( } else { console.log("Action Success: " + action.t); setModel(result); + //setModel(reconcile(result, { merge: true, key: "kids" })); } /* HACK: We want transforms the duplicate subtrees e.g. distributivity to * retain their duplicate ids for animations, but then we need to freshen diff --git a/src/data/World.tsx b/src/data/World.tsx index 0df6c8f..35551fb 100644 --- a/src/data/World.tsx +++ b/src/data/World.tsx @@ -29,7 +29,7 @@ const moons: Exp = comp([ comp([ atom("โž•"), B(["๐ŸŒ˜", "๐ŸŒ‘"]), - comp([atom("โž–"), B(["๐ŸŒ˜", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ˜"]), atom("๐ŸŒ˜")]), + comp([atom("โž•"), B(["๐ŸŒ˜", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ‘", "๐ŸŒ˜"]), atom("๐ŸŒ˜")]), ]), B(["๐ŸŒ˜", "๐ŸŒ‘"]), ]), diff --git a/src/index.css b/src/index.css index 79fef06..3a59bab 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,8 @@ + +:root { + --anim-factor: 1.5; +} + .notransition * { transition: none !important; } @@ -1146,7 +1151,7 @@ body:has(#main.Dark) { ::view-transition-group(flip-node-selected) { view-transition-name: selected; animation-timing-function: easeInBack; /*easeInBack; easeOutBounce;*/ - animation-duration: 0.2s; + animation-duration: calc(var(--anim-factor) * 0.2s); } ::view-transition-old(flip-node-selected) { } @@ -1155,7 +1160,7 @@ body:has(#main.Dark) { ::view-transition-group(*) { /*pointer-events: none;*/ - animation-duration: 0.25s; + animation-duration: calc(var(--anim-factor) * 0.25s); animation-fill-mode: both; animation-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6); } diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index 1615025..82f9f3e 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -105,7 +105,7 @@ const ExpViewGo: Component = (props) => { info={props.info} selection={props.selection} node={kid()} - animate={props.animate && eff(props)} + animate={props.animate /*&& eff(props)*/} is_head={i === 0} inject={props.inject} mask={props.mask} From 7d9b29a4a7919abd3529eb378be0988ad0697cff Mon Sep 17 00:00:00 2001 From: disconcision Date: Sun, 11 Feb 2024 00:59:03 -0500 Subject: [PATCH 03/14] arithmetic fixes --- src/data/Tools.tsx | 5 +++-- src/index.css | 5 ++--- src/view/ToolsView.tsx | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/data/Tools.tsx b/src/data/Tools.tsx index 2a9a45c..4122b93 100644 --- a/src/data/Tools.tsx +++ b/src/data/Tools.tsx @@ -6,6 +6,7 @@ type Base = { source: Pat.t; result: Pat.t; sound: Sound.Sfxbank }; const zero = Pat.p_const("๐ŸŒ‘"); const one = Pat.p_const("๐ŸŒ˜"); +const one2 = Pat.p_const("๐ŸŒ˜"); const hole = Pat.p_const("โ“"); const var_a = Pat.p_var("โ™ซ"); @@ -60,8 +61,8 @@ const b_thm_2: Base = { sound: "tiup", }; const b_thm_3: Base = { - source: plus_x(Bx(one, var_a), By(one, var_b)), - result: Bx(zero, plus_x(plus_x(var_a, var_b), one)), + source: plus_x(Bx(one, var_a), By(one2, var_b)), + result: Bx(zero, plus_x(var_a, plus_x(var_b, one2))), sound: "tiup", }; diff --git a/src/index.css b/src/index.css index 884e96e..d61322c 100644 --- a/src/index.css +++ b/src/index.css @@ -1232,10 +1232,9 @@ body:has(#main.Dark) { #noolbox .node.digits, #stage .node.digits { - border-radius: 0.8em; + border-radius: 3rem 1.2rem 1.2rem 3rem; padding: 0; margin: 0; - /* height: 1em; */ } #noolbox .node.comp.digits .head, @@ -1246,7 +1245,7 @@ body:has(#main.Dark) { } #stage .node.comp.digits.selected .head { - /* filter: brightness(0.8) !important; */ + filter: brightness(1) !important; } #noolbox .node:not(.digits):has(.digits) > .digits, diff --git a/src/view/ToolsView.tsx b/src/view/ToolsView.tsx index e222282..40faec1 100644 --- a/src/view/ToolsView.tsx +++ b/src/view/ToolsView.tsx @@ -271,7 +271,7 @@ export const ToolsView: Component<{ t: "wheelNumTools", offset, }); - }, 1000)(); + }, 250)(); } else { throttle(() => { const offset = e.deltaY == 0 ? 0 : e.deltaY / Math.abs(e.deltaY); @@ -280,7 +280,7 @@ export const ToolsView: Component<{ t: "wheelTools", offset: offset, }); - }, 1000)(); + }, 250)(); } }} > From 22d6bd47012efa71d99cb3a871e1b63bdb97520c Mon Sep 17 00:00:00 2001 From: disconcision Date: Thu, 22 Feb 2024 23:58:18 -0500 Subject: [PATCH 04/14] adjust digit padding. up anim count for now --- src/Animate.tsx | 2 +- src/data/Tools.tsx | 1 - src/index.css | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Animate.tsx b/src/Animate.tsx index 52370bc..e1c6432 100644 --- a/src/Animate.tsx +++ b/src/Animate.tsx @@ -8,7 +8,7 @@ const blah = (s: string) => ` export const init = ():void => { //TODO: unhardcode id max var style = document.createElement("style"); - for (let id = 0; id < 100; id++) { + for (let id = 0; id < 200; id++) { style.innerHTML += `#node-${id}.animate { view-transition-name: flip-node-${id}; }\n`; style.innerHTML += `#main.unsetSelections #sym-${id}, #main.setSelect #sym-${id}, #main.moveStage #sym-${id} { view-transition-name: flip-sym-${id}; }\n`; diff --git a/src/data/Tools.tsx b/src/data/Tools.tsx index 4122b93..7a6c901 100644 --- a/src/data/Tools.tsx +++ b/src/data/Tools.tsx @@ -30,7 +30,6 @@ const times_x = bin_x("โœ–๏ธ"); const times_y = bin_y("โœ–๏ธ"); const equals_x = bin_x("๐ŸŸฐ"); -const B = Pat.p_const("ษ–"); const Bx = bin_x("ษ–"); const By = bin_y("ษ–"); const two = Bx(zero, one); diff --git a/src/index.css b/src/index.css index d61322c..14f20f8 100644 --- a/src/index.css +++ b/src/index.css @@ -1232,7 +1232,7 @@ body:has(#main.Dark) { #noolbox .node.digits, #stage .node.digits { - border-radius: 3rem 1.2rem 1.2rem 3rem; + border-radius: 1.1em; padding: 0; margin: 0; } From 1009488e153b1a276d2966fa52a4edc553d2a17c Mon Sep 17 00:00:00 2001 From: disconcision Date: Fri, 23 Feb 2024 00:15:14 -0500 Subject: [PATCH 05/14] cleaner digit formatting --- src/index.css | 9 +++++++-- src/view/ToolsView.tsx | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/index.css b/src/index.css index 14f20f8..5c30f22 100644 --- a/src/index.css +++ b/src/index.css @@ -1219,8 +1219,10 @@ body:has(#main.Dark) { outline: none; border-left: 0.07em solid white; } -#noolbox .node.digits .node, -#stage .node.digits .node { +#noolbox .node.digits .node.digits , +#stage .node.digits .node.digits, +#noolbox .node.digits .atom , +#stage .node.digits .atom { /* background: none; */ box-shadow: none; padding: 0; @@ -1235,6 +1237,9 @@ body:has(#main.Dark) { border-radius: 1.1em; padding: 0; margin: 0; + background-color: #0000; + box-shadow: none; + border-color: #0000; } #noolbox .node.comp.digits .head, diff --git a/src/view/ToolsView.tsx b/src/view/ToolsView.tsx index 40faec1..ed1baa0 100644 --- a/src/view/ToolsView.tsx +++ b/src/view/ToolsView.tsx @@ -60,7 +60,7 @@ const PatView: Component<{ each={head_is("ษ–", props.p) ? props.p.kids.slice(1) : props.p.kids} > {(kid, i) => - PatView({ p: kid, is_head: i() === 0, symbols: props.symbols }) + PatView({ p: kid, is_head: i() === 0 && !head_is("ษ–", props.p), symbols: props.symbols }) }
From 246bd9744b2815b112fa635475b56c8192412368 Mon Sep 17 00:00:00 2001 From: disconcision Date: Tue, 27 Feb 2024 21:37:29 -0500 Subject: [PATCH 06/14] worldtree style --- src/data/World.tsx | 8 +++++++- src/index.css | 39 ++++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/data/World.tsx b/src/data/World.tsx index c06a947..fe09f39 100644 --- a/src/data/World.tsx +++ b/src/data/World.tsx @@ -32,4 +32,10 @@ const moons: Exp = comp([ ]), ]); -export const init: Exp = comp([atom("ไทถ"), alg, moons, lab]); +// โ–จ ไท€ ไท‚ แ–›แ™Š เขฅ แŽฃ โ—ต +export const init: Exp = comp([ + atom("ไทถ"), + comp([atom("แ–›"), alg]), + comp([atom("แ™Š"), moons]), + comp([atom("แ"), lab]), +]); diff --git a/src/index.css b/src/index.css index 5c30f22..f3c9e76 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,3 @@ - :root { --anim-factor: 1.5; } @@ -345,10 +344,8 @@ code { .node.selected, .node.selected:hover { - border: 0; - outline: 0.03em solid #ffffff; + border: none; /* HACK */ box-shadow: 0px 0px 0.6em #ffffff; - /* mix-blend-mode: color-dodge; */ outline: 2px solid white; } @@ -1204,6 +1201,25 @@ body:has(#main.Dark) { -0.4em -0.4em 0.8em #cff2e644, -0.8em -0.8em 1.6em #d2fff044; } +#stage .node.ไทถ > .node { + background: none; + box-shadow: none; + border-left: 0.3px solid #6b19da52; + border-top: none; + border-bottom: none; +} + +#stage .node.ไทถ > .head, +#stage .node.ไทถ > .node > .head { + text-shadow: 0.01em 0.02em 0.02em rgb(212 245 228); +} +#stage .node.ไทถ.selected > .head, +#stage .node.ไทถ > .node.selected > .head { + animation-name: none; + color: black; + text-shadow: 0.01em 0.02em 0.02em rgb(32 100 65); +} + #stage .node.ไทถ { border-radius: 2.7em 0.3em 0.3em 2.7em; display: grid; @@ -1215,14 +1231,15 @@ body:has(#main.Dark) { border: none; border-left: 0.3px solid #19dac5; } -#stage .node.ไทถ.selected { +#stage .node.ไทถ.selected, +#stage .node.ไทถ > .node.selected { outline: none; border-left: 0.07em solid white; } -#noolbox .node.digits .node.digits , +#noolbox .node.digits .node.digits, #stage .node.digits .node.digits, -#noolbox .node.digits .atom , -#stage .node.digits .atom { +#noolbox .node.digits .atom, +#stage .node.digits .atom { /* background: none; */ box-shadow: none; padding: 0; @@ -1231,6 +1248,10 @@ body:has(#main.Dark) { /* border-radius: 0.1em; */ /* height: 1.7em; */ } +.node.comp:has(> .node.digits) { + /* display: flex; */ + /* justify-items: flex-end; */ +} #noolbox .node.digits, #stage .node.digits { @@ -1257,4 +1278,4 @@ body:has(#main.Dark) { #stage .node:not(.digits):has(.digits) > .digits { padding-left: 0.15em; padding-right: 0.15em; -} \ No newline at end of file +} From bd8ed138c7830ca351f1302b2779c0312944b094 Mon Sep 17 00:00:00 2001 From: disconcision Date: Tue, 27 Feb 2024 23:39:04 -0500 Subject: [PATCH 07/14] basic folding --- src/Action.tsx | 9 +++++--- src/App.tsx | 22 +----------------- src/Projector.tsx | 38 +++++++++++++++++++++++++++++-- src/Update.tsx | 38 ++++++++++++++++++++++++++++--- src/index.css | 13 ++++++++++- src/view/ExpView.tsx | 52 ++++++++++++++++++++++++++++++++----------- src/view/SeedView.tsx | 3 ++- 7 files changed, 131 insertions(+), 44 deletions(-) diff --git a/src/Action.tsx b/src/Action.tsx index 072fdfe..03fe8c5 100644 --- a/src/Action.tsx +++ b/src/Action.tsx @@ -4,6 +4,8 @@ import * as Hover from "./Hover"; import * as Settings from "./Settings"; import * as Transform from "./Transform"; import * as Pat from "./syntax/Pat"; +import * as Projector from "./Projector"; +import * as ID from "./syntax/ID"; export type Inject = (_: Action) => void; @@ -16,8 +18,8 @@ export type Action = | { t: "setSelect"; path: Path.t } | { t: "moveStage"; direction: Direction } | { t: "moveTool"; direction: Direction } - | { t: "wheelTools"; offset: number} - | { t: "wheelNumTools"; offset: number} + | { t: "wheelTools"; offset: number } + | { t: "wheelNumTools"; offset: number } | { t: "unsetSelections" } | { t: "transformNode"; @@ -35,6 +37,7 @@ export type Action = | { t: "applyTransform"; idx: number; direction: "forward" | "reverse" } | { t: "applyTransformSelected" } | { t: "flipTransform"; idx: number } - | { t: "Noop" }; + | { t: "Noop" } + | { t: "Project"; id: ID.t; action: Projector.Action }; export type t = Action; diff --git a/src/App.tsx b/src/App.tsx index ceb24c5..8b7609c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,44 +8,24 @@ import { SettingsView } from "./view/SettingsView"; import { Seed } from "./view/SeedView"; import * as ExpToPat from "./syntax/ExpToPat"; import * as Animate from "./Animate"; -//import { Toolbar } from "./view/ToolsView"; export type SetModel = SetStoreFunction; - const App: Component = () => { const [model, setModel] = createStore({ ...Model.init }); Animate.init(); const inject = (a: Action.t) => { console.log(a); - if (a.t === "setHover" || !document.startViewTransition) { - console.log("sethover dont transition:" + a.t); - go(model, setModel, a); - return; - } - const guy2 = document.getElementById("main"); - guy2 ? guy2.classList.add(a.t) : console.log("no guy r add"); - let v = document.startViewTransition(() => go(model, setModel, a)); - v.finished.then(() => - guy2 ? guy2.classList.remove(a.t) : console.log("no guy 2 rm") - ); + go(model, setModel, a); }; document.addEventListener("keydown", Keyboard.keydown(inject), false); document.addEventListener("keyup", Keyboard.keyup(inject), false); - // document.addEventListener("transitionstart", (e) => { - // in_transition = true; - // }); - // document.addEventListener("transitionend", (e) => { - // in_transition = false; - // }); return (
- {/* diff --git a/src/Projector.tsx b/src/Projector.tsx index a8b9506..8e400cb 100644 --- a/src/Projector.tsx +++ b/src/Projector.tsx @@ -4,15 +4,49 @@ type PaintColor = "Cyan" | "Magenta" | "Yellow"; type Painter = PaintColor | "Unpainted"; +type Folded = "Folded" | "Quasifolded" | "Enfolded" | "NotFolded"; + type Projector = { - painter: Painter; + //painter: Painter; + folded: Folded; }; type t = Projector; export type PMap = Map; -export const init: PMap = new Map(); +export const init: PMap = (() => { + const map = new Map(); + map.set(66, { folded: "Folded" }); + map.set(68, { folded: "Folded" }); + return map; +})(); + +export type Action = "toggleFoldCurrent"; + +export const update = (id: ID.t, action: Action, projectors: PMap): PMap => { + switch (action) { + case "toggleFoldCurrent": + const map: PMap = new Map(projectors); + const current = map.get(id); + if (current === undefined) { + console.log("Projector.update: id not found, adding new entry:" + id); + map.set(id, { folded: "Folded" }); + } else { + console.log("Projector.update: id found, changing folding state:" + id); + map.set(id, { + ...current, + folded: current.folded === "Folded" ? "NotFolded" : "Folded", + }); + } + return map; + } +}; + +export const is_folded = (id: ID.t, projectors: PMap): boolean => { + const proj = projectors.get(id); + return proj !== undefined && proj.folded === "Folded"; +}; /* paint plan: diff --git a/src/Update.tsx b/src/Update.tsx index 19180a6..1675d60 100644 --- a/src/Update.tsx +++ b/src/Update.tsx @@ -16,6 +16,7 @@ import * as Path from "./syntax/Path"; import * as Animate from "./Animate"; import * as Util from "./Util"; import { reconcile } from "solid-js/store"; +import * as Projectors from "./Projector"; export type result = Model.t | "NoChange"; @@ -57,6 +58,9 @@ export const sound = (model: Model.t, action: Action.t): void => { case "Noop": Sound.noop(); break; + case "Project": + Sound.sfx("pew")(); + break; case "setHover": case "flipTransform": case "applyTransform": @@ -220,9 +224,33 @@ export const update = (model: Model.t, action: Action.t): result => { ), }, }; + case "Project": + return { + ...model, + stage: { + ...model.stage, + projectors: Projectors.update( + action.id, + action.action, + model.stage.projectors + ), + }, + }; } }; +export const viewTransition = ( + action: Action.t, + f: () => void +) => { + const guy2 = document.getElementById("main"); + guy2 ? guy2.classList.add(action.t) : console.log("no guy 1"); + let v = document.startViewTransition(f); + v.finished.then(() => + guy2 ? guy2.classList.remove(action.t) : console.log("no guy 2") + ); +}; + export const go = ( model: Model.t, setModel: SetStoreFunction, @@ -236,13 +264,17 @@ export const go = ( console.error(e); } const result = update(model, action); - if (result == "NoChange") { - //Sound.noop(); + if (result == "NoChange") { console.log("Action NoChange:" + action.t); return; } else { console.log("Action Success: " + action.t); - setModel(result); + if (action.t === "setHover" || !document.startViewTransition) { + console.log("sethover dont transition:" + action.t); + setModel(result); + return; + } + viewTransition(action, () => setModel(result)); //setModel(reconcile(result, { merge: true, key: "kids" })); } /* HACK: We want transforms the duplicate subtrees e.g. distributivity to diff --git a/src/index.css b/src/index.css index f3c9e76..a53f534 100644 --- a/src/index.css +++ b/src/index.css @@ -1,5 +1,5 @@ :root { - --anim-factor: 1.5; + --anim-factor: 1.25; } .notransition * { @@ -378,10 +378,19 @@ code { .node:active { /*animation-name: wobble; animation-duration: 1s;*/ + animation-delay: 0.25s; animation-name: wobble2; animation-duration: 0.15s; animation-iteration-count: infinite; } +.node.comp.folded { + border-radius: 10em; +} +.node.comp.folded > .head:after { + font-size: 0.4em; + content: "\00a0โ‹ฏ"; +} + #stage .node.comp { /*background-color: #005bff26;*/ background: linear-gradient( @@ -397,6 +406,8 @@ code { border-top: 0.3px solid rgb(226 255 244); } .node.comp .head { + display: flex; + align-items: center; background-color: #284a37; /* mix-blend-mode: color-burn; */ color: transparent; diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index 82f9f3e..ee85828 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -9,6 +9,7 @@ import * as Statics from "../Statics"; import * as Stage from "../Stage"; import * as Names from "../Names"; import * as Settings from "../Settings"; +import * as Projector from "../Projector"; type expviewprops = { node: Exp.t; @@ -19,9 +20,10 @@ type expviewprops = { inject: Action.Inject; mask: Pat.Binding[]; symbols: Settings.symbols; + projectors: Projector.PMap; }; -const setSelect = (props: expviewprops) => (e: Event) => { +const setSelect = (props: expviewprops) => (e: MouseEvent) => { e.preventDefault(); //above modulates whether shake occurs for some reason? e.stopPropagation(); @@ -55,8 +57,7 @@ const ExpViewGo: Component = (props) => { switch (props.node.t) { case "Atom": return ( - = (props) => {
} > -
- {Names.get(props.symbols, props.node.sym)} -
- + +
+ {Names.get(props.symbols, props.node.sym)} +
+
+ ); case "Comp": return ( @@ -89,13 +92,33 @@ const ExpViewGo: Component = (props) => { classList={{ animate: props.animate, digits: Exp.head_is("ษ–", props.node), + folded: Projector.is_folded(props.node.id, props.projectors), + }} + onclick={(e) => { + e.preventDefault(); + e.stopPropagation(); + console.log("clicks: " + e.detail); + switch (e.detail) { + case 1: + setSelect(props)(e); + break; + case 2: + case 3: + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); + break; + } }} - onpointerdown={setSelect(props)} > { = (props) => { inject={props.inject} mask={props.mask} symbols={props.symbols} + projectors={props.projectors} /> )} @@ -136,6 +160,7 @@ export const ExpView: Component<{ is_head: false, animate: true, symbols: props.symbols, + projectors: props.stage.projectors, }); export const ViewOnly: Component<{ @@ -151,4 +176,5 @@ export const ViewOnly: Component<{ inject: (_) => {}, mask: [], symbols: props.symbols, + projectors: Projector.init, }); diff --git a/src/view/SeedView.tsx b/src/view/SeedView.tsx index b08c6a2..31fcff9 100644 --- a/src/view/SeedView.tsx +++ b/src/view/SeedView.tsx @@ -30,8 +30,9 @@ export const Seed: Component<{ model: Model.t; inject: Action.Inject }> = ( noanimation: props.model.settings.motion === "Off", notransformation: props.model.settings.motion === "Off", }} - onmousedown={(e) => { + onclick={(e) => { e.preventDefault(); + e.stopPropagation(); props.inject({ t: "unsetSelections" }); }} > From 3dc248a78e9813b544a13f08f5f052f551a5c9f1 Mon Sep 17 00:00:00 2001 From: disconcision Date: Thu, 29 Feb 2024 00:03:15 -0500 Subject: [PATCH 08/14] basic quasifolding --- src/Action.tsx | 2 +- src/Keyboard.tsx | 2 ++ src/Projector.tsx | 84 +++++++++++++++++++++++++++++++++++++++----- src/Stage.tsx | 7 ++++ src/Update.tsx | 48 ++++++++++++------------- src/index.css | 18 ++++++++-- src/view/ExpView.tsx | 18 +++++++--- 7 files changed, 138 insertions(+), 41 deletions(-) diff --git a/src/Action.tsx b/src/Action.tsx index 03fe8c5..8781a9d 100644 --- a/src/Action.tsx +++ b/src/Action.tsx @@ -38,6 +38,6 @@ export type Action = | { t: "applyTransformSelected" } | { t: "flipTransform"; idx: number } | { t: "Noop" } - | { t: "Project"; id: ID.t; action: Projector.Action }; + | { t: "Project"; id: ID.t | undefined; action: Projector.Action }; export type t = Action; diff --git a/src/Keyboard.tsx b/src/Keyboard.tsx index 90c3bf5..09c3e2b 100644 --- a/src/Keyboard.tsx +++ b/src/Keyboard.tsx @@ -30,6 +30,8 @@ const action_of = (key: string): Action.t | "NoBinding" => { return { t: "moveTool", direction: "right" }; case " ": return { t: "applyTransformSelected" }; + case "f": + return { t: "Project", action: "toggleEnfoldCurrent", id: undefined }; default: return "NoBinding"; } diff --git a/src/Projector.tsx b/src/Projector.tsx index 8e400cb..ceae9c8 100644 --- a/src/Projector.tsx +++ b/src/Projector.tsx @@ -1,4 +1,5 @@ import * as ID from "./syntax/ID"; +import * as Exp from "./syntax/Exp"; type PaintColor = "Cyan" | "Magenta" | "Yellow"; @@ -13,6 +14,8 @@ type Projector = { type t = Projector; +export const basic: Projector = { folded: "NotFolded" }; + export type PMap = Map; export const init: PMap = (() => { @@ -22,30 +25,95 @@ export const init: PMap = (() => { return map; })(); -export type Action = "toggleFoldCurrent"; +export type Action = "toggleFoldCurrent" | "toggleEnfoldCurrent"; + +export const get = (projectors: PMap, id: ID.t): t => { + const res = projectors.get(id); + return res == undefined ? basic : res; +}; export const update = (id: ID.t, action: Action, projectors: PMap): PMap => { + const map: PMap = new Map(projectors); + const current = get(map, id); switch (action) { case "toggleFoldCurrent": - const map: PMap = new Map(projectors); - const current = map.get(id); if (current === undefined) { - console.log("Projector.update: id not found, adding new entry:" + id); map.set(id, { folded: "Folded" }); } else { - console.log("Projector.update: id found, changing folding state:" + id); map.set(id, { ...current, folded: current.folded === "Folded" ? "NotFolded" : "Folded", }); } return map; + case "toggleEnfoldCurrent": + if (current === undefined) { + console.log("Projector.update: id not found, adding new entry:" + id); + map.set(id, { folded: "Enfolded" }); + } else { + console.log("Projector.update: id found, changing folding state:" + id); + map.set(id, { + ...current, + folded: current.folded === "Enfolded" ? "NotFolded" : "Enfolded", + }); + } + return map; } }; -export const is_folded = (id: ID.t, projectors: PMap): boolean => { - const proj = projectors.get(id); - return proj !== undefined && proj.folded === "Folded"; +export const is_folded = (id: ID.t, projectors: PMap): boolean => + get(projectors, id).folded === "Folded"; + +export const is_enfolded = (id: ID.t, projectors: PMap): boolean => + get(projectors, id).folded === "Enfolded"; + +const get_enfolded = (projectors: PMap, node: Exp.t): Exp.t[] => { + let p = get(projectors, node.id); + if (p.folded == "Enfolded") { + return [node]; + } else { + switch (node.t) { + case "Atom": + return []; + case "Comp": + if (p.folded == "Folded") { + return []; + } else { + return node.kids.map((kid) => get_enfolded(projectors, kid)).flat(); + } + } + } +}; + +let oneatom: Exp.t[] = [{ t: "Atom", id: ID.mk(), sym: "" }]; +let oneatom_ = (sym: string): Exp.t[] => [{ t: "Atom", id: ID.mk(), sym }]; + +/* TODO: maybe dont allow enfolds inside enfolds */ +export const project_folds = (projectors: PMap, node: Exp.t): Exp.t => { + switch (node.t) { + case "Atom": + return node; + case "Comp": + switch (get(projectors, node.id).folded) { + case "Folded": + const oneatom2 = oneatom_(Exp.head(node)); + return { + ...node, + kids: oneatom2.concat(node.kids.map((kid) => get_enfolded(projectors, kid)).flat()), + //kids: node.kids.length == 0 ? [] : { ...node }.kids.toSpliced(1), + }; + // case "Quasifolded": + // return { + // ...node, + // kids: oneatom.concat(get_enfolded(projectors, node)), + // }; + default: + return { + ...node, + kids: node.kids.map((kid) => project_folds(projectors, kid)), + }; + } + } }; /* diff --git a/src/Stage.tsx b/src/Stage.tsx index 325068e..e24b505 100644 --- a/src/Stage.tsx +++ b/src/Stage.tsx @@ -4,6 +4,8 @@ import * as Path from "./syntax/Path"; import * as Projector from "./Projector"; import * as World from "./data/World"; import { is_path_valid } from "./syntax/Node"; +import * as ID from "./syntax/ID"; +import { id_at } from "./syntax/Node"; export type selection = "unselected" | Path.t; @@ -114,3 +116,8 @@ export const move = ( stage: Stage, direction: "up" | "down" | "left" | "right" ) => put_selection(stage, move_(stage, direction)); + +export const indicated_id = (stage: Stage): ID.t | undefined => + stage.selection === "unselected" + ? undefined + : id_at(stage.selection, stage.exp); \ No newline at end of file diff --git a/src/Update.tsx b/src/Update.tsx index 1675d60..eab9398 100644 --- a/src/Update.tsx +++ b/src/Update.tsx @@ -1,5 +1,4 @@ import { at_path } from "./Transform"; -import Flipping from "flipping/lib/adapters/web"; import * as Model from "./Model"; import * as Sound from "./Sound"; import * as Settings from "./Settings"; @@ -13,7 +12,6 @@ import * as Exp from "./syntax/Exp"; import * as Pat from "./syntax/Pat"; import { SetStoreFunction } from "solid-js/store"; import * as Path from "./syntax/Path"; -import * as Animate from "./Animate"; import * as Util from "./Util"; import { reconcile } from "solid-js/store"; import * as Projectors from "./Projector"; @@ -225,12 +223,20 @@ export const update = (model: Model.t, action: Action.t): result => { }, }; case "Project": + const indicated_id = Stage.indicated_id(model.stage); + console.log("Project: Indicated ID: " + indicated_id); + const id = + action.id != undefined + ? action.id + : indicated_id != undefined + ? indicated_id + : -666; return { ...model, stage: { ...model.stage, projectors: Projectors.update( - action.id, + id, action.action, model.stage.projectors ), @@ -239,10 +245,7 @@ export const update = (model: Model.t, action: Action.t): result => { } }; -export const viewTransition = ( - action: Action.t, - f: () => void -) => { +export const viewTransition = (action: Action.t, f: () => void) => { const guy2 = document.getElementById("main"); guy2 ? guy2.classList.add(action.t) : console.log("no guy 1"); let v = document.startViewTransition(f); @@ -250,32 +253,33 @@ export const viewTransition = ( guy2 ? guy2.classList.remove(action.t) : console.log("no guy 2") ); }; +// document.addEventListener("transitionstart", (e) => { +// in_transition = true; +// }); +// document.addEventListener("transitionend", (e) => { +// in_transition = false; +// }); export const go = ( model: Model.t, setModel: SetStoreFunction, action: Action.t ): void => { - if (model.settings.sound) sound(model, action); - /* Catching because problem on build server */ - try { - //Animate.read(model, action); - } catch (e) { - console.error(e); - } const result = update(model, action); - if (result == "NoChange") { + if (result == "NoChange") { console.log("Action NoChange:" + action.t); return; } else { console.log("Action Success: " + action.t); + const doIt = () => setModel(result); + //setModel(reconcile(result, { merge: true, key: "kids" })); if (action.t === "setHover" || !document.startViewTransition) { - console.log("sethover dont transition:" + action.t); - setModel(result); + console.log("setHover: Don't transition:" + action.t); + doIt(); return; + } else { + viewTransition(action, doIt); } - viewTransition(action, () => setModel(result)); - //setModel(reconcile(result, { merge: true, key: "kids" })); } /* HACK: We want transforms the duplicate subtrees e.g. distributivity to * retain their duplicate ids for animations, but then we need to freshen @@ -289,10 +293,4 @@ export const go = ( stage: Stage.put_exp(model.stage, freshened), }); }, 250);*/ - /* Catching because problem on build server */ - try { - //Animate.flip(model, action); - } catch (e) { - console.error(e); - } }; diff --git a/src/index.css b/src/index.css index a53f534..a854faa 100644 --- a/src/index.css +++ b/src/index.css @@ -185,6 +185,7 @@ } body { + user-select: none; height: 100vh; overflow: hidden; margin: 0; @@ -383,13 +384,23 @@ code { animation-duration: 0.15s; animation-iteration-count: infinite; } -.node.comp.folded { - border-radius: 10em; +.node.comp.folded:has(> .head:only-child) { + border-radius: 2em; +} +.node.comp.folded > .head{ + font-size: 0.8em; } .node.comp.folded > .head:after { font-size: 0.4em; content: "\00a0โ‹ฏ"; } +.node.comp.enfolded, +.node.atom.enfolded { + outline: solid 0.3px #009571; + box-shadow: 0 0 0.8em #00543c; + /* filter: sepia(1) saturate(0) contrast(0.8); */ + /* background-color: #9d9d9d4f; */ +} #stage .node.comp { /*background-color: #005bff26;*/ @@ -457,10 +468,11 @@ code { /*align-items: center;*/ display: grid; grid-auto-flow: column; + grid-column: 2; } .node-container.TreeLeft .node.comp .head { grid-column: 1; - grid-row: 1/4; + grid-row: 1/100; } #seed:has(.LinearPrefix), diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index ee85828..305d9a2 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -62,7 +62,13 @@ const ExpViewGo: Component = (props) => {
@@ -93,6 +99,10 @@ const ExpViewGo: Component = (props) => { animate: props.animate, digits: Exp.head_is("ษ–", props.node), folded: Projector.is_folded(props.node.id, props.projectors), + enfolded: Projector.is_enfolded( + props.node.id, + props.projectors + ), }} onclick={(e) => { e.preventDefault(); @@ -116,9 +126,9 @@ const ExpViewGo: Component = (props) => { { Date: Thu, 29 Feb 2024 00:10:45 -0500 Subject: [PATCH 09/14] for sale: style idea, never used --- src/index.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/index.css b/src/index.css index a854faa..73cdc15 100644 --- a/src/index.css +++ b/src/index.css @@ -401,6 +401,15 @@ code { /* filter: sepia(1) saturate(0) contrast(0.8); */ /* background-color: #9d9d9d4f; */ } +/* .node.selected .node.enfolded { + background-color: #d2f5e4 !important; + box-shadow: 0em 0em 1em white; + filter:none !important; +} +.node.selected:has(.node.enfolded) { + background-color: #ffffff75 !important; + filter:none !important; +} */ #stage .node.comp { /*background-color: #005bff26;*/ From 0a1563546d27e3710ffd788aa0e17d56faa32dc8 Mon Sep 17 00:00:00 2001 From: disconcision Date: Thu, 29 Feb 2024 22:27:28 -0500 Subject: [PATCH 10/14] better un/enfold style. noticing audio is broken? also transitions feel slightly janky re: backgrounds --- src/Projector.tsx | 36 ++++++++------ src/index.css | 30 ++++++++++-- src/view/ExpView.tsx | 114 ++++++++++++++++++++++++++++++++----------- 3 files changed, 131 insertions(+), 49 deletions(-) diff --git a/src/Projector.tsx b/src/Projector.tsx index ceae9c8..6bf659d 100644 --- a/src/Projector.tsx +++ b/src/Projector.tsx @@ -1,11 +1,10 @@ import * as ID from "./syntax/ID"; import * as Exp from "./syntax/Exp"; -type PaintColor = "Cyan" | "Magenta" | "Yellow"; +//type PaintColor = "Cyan" | "Magenta" | "Yellow"; +//type Painter = PaintColor | "Unpainted"; -type Painter = PaintColor | "Unpainted"; - -type Folded = "Folded" | "Quasifolded" | "Enfolded" | "NotFolded"; +type Folded = "Folded" | "Enfolded" | "NotFolded"; type Projector = { //painter: Painter; @@ -20,8 +19,10 @@ export type PMap = Map; export const init: PMap = (() => { const map = new Map(); - map.set(66, { folded: "Folded" }); + map.set(69, { folded: "Folded" }); map.set(68, { folded: "Folded" }); + map.set(66, { folded: "Folded" }); + map.set(20, { folded: "Enfolded" }); return map; })(); @@ -79,14 +80,20 @@ const get_enfolded = (projectors: PMap, node: Exp.t): Exp.t[] => { if (p.folded == "Folded") { return []; } else { - return node.kids.map((kid) => get_enfolded(projectors, kid)).flat(); + return node.kids + .map((kid) => + get_enfolded(projectors, project_folds(projectors, kid)) + ) + .flat(); } } } }; -let oneatom: Exp.t[] = [{ t: "Atom", id: ID.mk(), sym: "" }]; -let oneatom_ = (sym: string): Exp.t[] => [{ t: "Atom", id: ID.mk(), sym }]; +export const has_enfolded = (projectors: PMap, node: Exp.t): boolean => + get_enfolded(projectors, node).length > 0; + +let fold_head = (sym: string): Exp.t[] => [{ t: "Atom", id: ID.mk(), sym }]; /* TODO: maybe dont allow enfolds inside enfolds */ export const project_folds = (projectors: PMap, node: Exp.t): Exp.t => { @@ -96,17 +103,14 @@ export const project_folds = (projectors: PMap, node: Exp.t): Exp.t => { case "Comp": switch (get(projectors, node.id).folded) { case "Folded": - const oneatom2 = oneatom_(Exp.head(node)); + const enfolded = node.kids + .map((kid) => get_enfolded(projectors, kid)) + .flat(); + const atom = fold_head(enfolded.length == 0 ? Exp.head(node) : ""); return { ...node, - kids: oneatom2.concat(node.kids.map((kid) => get_enfolded(projectors, kid)).flat()), - //kids: node.kids.length == 0 ? [] : { ...node }.kids.toSpliced(1), + kids: atom.concat(enfolded), }; - // case "Quasifolded": - // return { - // ...node, - // kids: oneatom.concat(get_enfolded(projectors, node)), - // }; default: return { ...node, diff --git a/src/index.css b/src/index.css index 73cdc15..aa74b14 100644 --- a/src/index.css +++ b/src/index.css @@ -304,7 +304,7 @@ code { .node:hover { /*mix-blend-mode: color-dodge;*/ /*transform: scale(1.03);*/ - filter: brightness(1.05); + /* filter: brightness(1.05); */ border-bottom: 0.3px solid rgb(187, 0, 255); border-top: 0.3px solid rgb(255, 100, 212); /* scale: 1.03; */ @@ -384,11 +384,23 @@ code { animation-duration: 0.15s; animation-iteration-count: infinite; } +.node-container > .node.comp.folded { + background: none !important; + border: none !important; + box-shadow: none; +} +.node-container > .node.folded > .node.enfolded { + border-left: none !important; +} +.node.comp.folded { + background-color: antiquewhite !important; +} .node.comp.folded:has(> .head:only-child) { border-radius: 2em; } -.node.comp.folded > .head{ +.node.comp.folded > .head { font-size: 0.8em; + color: black; } .node.comp.folded > .head:after { font-size: 0.4em; @@ -396,10 +408,18 @@ code { } .node.comp.enfolded, .node.atom.enfolded { - outline: solid 0.3px #009571; - box-shadow: 0 0 0.8em #00543c; + /* outline: solid 0.3px #009571; */ + /* box-shadow: 0 0 0.8em #00543c; */ + border-left: 5px solid #9c7bdf !important; + border-top: 0.7px solid #9c7bdf !important; + border-bottom: 0.7px solid #9c7bdf !important; + /* filter: sepia(1) saturate(0) contrast(0.8); */ - /* background-color: #9d9d9d4f; */ +} + +.node.folded .node.enfolded { + background-color: #c7eee9 !important; + border-color: antiquewhite !important; } /* .node.selected .node.enfolded { background-color: #d2f5e4 !important; diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index 305d9a2..6e77de5 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -33,6 +33,87 @@ const setSelect = (props: expviewprops) => (e: MouseEvent) => { }); }; +const eff = (props: expviewprops): boolean => { + /* search mask for a binding whose first id is this node's id. + then check if it's a val binding. if so return true. else false. */ + const binding = props.mask.find( + ({ ids: [_, id_stage], t }) => id_stage == props.node.id && t == "Val" + ); + // if binding is undefind rerturn false. else return true. + return binding?.t == "Val" ? false : true; +}; + +const enfold = (props: expviewprops)=> ( e: MouseEvent) => { + if (e.shiftKey) { + return; + } else { + e.preventDefault(); + e.stopPropagation(); + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleEnfoldCurrent", + }); + } +}; + +const enfoldAction = (props: expviewprops)=> ( e: MouseEvent) => { + if (e.shiftKey) { + return; + } else if (Projector.has_enfolded(props.projectors, props.node)) + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }) + else { + switch(Projector.get(props.projectors, props.node.id).folded) { + case "Enfolded": + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); + break; + case "Folded": + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); + break; + default: + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleEnfoldCurrent", + }); + break; + } + } + e.preventDefault(); + e.stopPropagation(); +}; + +const selectOrFold = (props: expviewprops)=> ( e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + console.log("clicks: " + e.detail); + switch (e.detail) { + case 1: + setSelect(props)(e); + break; + case 2: + case 3: + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); + break; + } +}; + const common_clss = ({ node, mask, info, selection }: expviewprops): string => { const { path, depth } = Statics.get(info, node.id); const is_selected = @@ -45,15 +126,6 @@ const common_clss = ({ node, mask, info, selection }: expviewprops): string => { }; const ExpViewGo: Component = (props) => { - const eff = (props: expviewprops): boolean => { - /* search mask for a binding whose first id is this node's id. - then check if it's a val binding. if so return true. else false. */ - const binding = props.mask.find( - ({ ids: [_, id_stage], t }) => id_stage == props.node.id && t == "Val" - ); - // if binding is undefind rerturn false. else return true. - return binding?.t == "Val" ? false : true; - }; switch (props.node.t) { case "Atom": return ( @@ -69,7 +141,9 @@ const ExpViewGo: Component = (props) => { props.projectors ), }} - onpointerdown={setSelect(props)} + onclick={selectOrFold(props)} + //onpointerdown={setSelect(props)} + oncontextmenu={enfoldAction(props)} >
{Names.get(props.symbols, props.node.sym)} @@ -104,24 +178,8 @@ const ExpViewGo: Component = (props) => { props.projectors ), }} - onclick={(e) => { - e.preventDefault(); - e.stopPropagation(); - console.log("clicks: " + e.detail); - switch (e.detail) { - case 1: - setSelect(props)(e); - break; - case 2: - case 3: - props.inject({ - t: "Project", - id: props.node.id, - action: "toggleFoldCurrent", - }); - break; - } - }} + oncontextmenu={enfoldAction(props)} + onclick={selectOrFold(props)} > { Date: Fri, 1 Mar 2024 22:38:51 -0500 Subject: [PATCH 11/14] better enfold UI. massive css cleanup --- src/Animate.tsx | 1 - src/App.tsx | 1 + src/Projector.tsx | 22 +- src/Stage.tsx | 23 +- src/Update.tsx | 15 +- src/data/Symbols.tsx | 3 + src/data/Tools.tsx | 5 +- src/data/World.tsx | 4 +- src/index.css | 1044 +++++++++++++++++----------------------- src/syntax/Exp.tsx | 19 +- src/syntax/Node.tsx | 17 +- src/syntax/Pat.tsx | 35 +- src/view/ExpView.tsx | 50 +- src/view/StageView.tsx | 16 +- src/view/ToolsView.tsx | 30 +- 15 files changed, 588 insertions(+), 697 deletions(-) create mode 100644 src/data/Symbols.tsx diff --git a/src/Animate.tsx b/src/Animate.tsx index e1c6432..5955450 100644 --- a/src/Animate.tsx +++ b/src/Animate.tsx @@ -11,7 +11,6 @@ export const init = ():void => { for (let id = 0; id < 200; id++) { style.innerHTML += `#node-${id}.animate { view-transition-name: flip-node-${id}; }\n`; style.innerHTML += `#main.unsetSelections #sym-${id}, #main.setSelect #sym-${id}, #main.moveStage #sym-${id} { view-transition-name: flip-sym-${id}; }\n`; - //style.innerHTML += `#main.setSelect #pat-${id} { view-transition-name: flip-pat-${id}; }`; //style.innerHTML += blah(`flip-node-${id}`); //style.innerHTML += blah(`flip-pat-${id}`); diff --git a/src/App.tsx b/src/App.tsx index 8b7609c..95a4ba5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import { SettingsView } from "./view/SettingsView"; import { Seed } from "./view/SeedView"; import * as ExpToPat from "./syntax/ExpToPat"; import * as Animate from "./Animate"; +import * as Tone from "tone"; export type SetModel = SetStoreFunction; diff --git a/src/Projector.tsx b/src/Projector.tsx index 6bf659d..3bc77ea 100644 --- a/src/Projector.tsx +++ b/src/Projector.tsx @@ -93,7 +93,22 @@ const get_enfolded = (projectors: PMap, node: Exp.t): Exp.t[] => { export const has_enfolded = (projectors: PMap, node: Exp.t): boolean => get_enfolded(projectors, node).length > 0; -let fold_head = (sym: string): Exp.t[] => [{ t: "Atom", id: ID.mk(), sym }]; +let get_id = (node: Exp.t) => { + const res = Exp.head_id(node); + return res == undefined ? -1 : res; +}; + +let summary_head = (node: Exp.t): Exp.t => ({ + t: "Atom", + id: get_id(node), + sym: Exp.head(node), +}); + +let blank_head = (node: Exp.t): Exp.t => ({ + t: "Atom", + id: get_id(node), + sym: "", +}); /* TODO: maybe dont allow enfolds inside enfolds */ export const project_folds = (projectors: PMap, node: Exp.t): Exp.t => { @@ -106,10 +121,11 @@ export const project_folds = (projectors: PMap, node: Exp.t): Exp.t => { const enfolded = node.kids .map((kid) => get_enfolded(projectors, kid)) .flat(); - const atom = fold_head(enfolded.length == 0 ? Exp.head(node) : ""); + const head = + enfolded.length == 0 ? [summary_head(node)] : [blank_head(node)]; return { ...node, - kids: atom.concat(enfolded), + kids: head.concat(enfolded), }; default: return { diff --git a/src/Stage.tsx b/src/Stage.tsx index e24b505..cba10aa 100644 --- a/src/Stage.tsx +++ b/src/Stage.tsx @@ -1,16 +1,15 @@ -import { Exp } from "./syntax/Exp"; +import * as Exp from "./syntax/Exp"; import * as Statics from "./Statics"; import * as Path from "./syntax/Path"; import * as Projector from "./Projector"; import * as World from "./data/World"; -import { is_path_valid } from "./syntax/Node"; +import { is_path_valid, id_at } from "./syntax/Node"; import * as ID from "./syntax/ID"; -import { id_at } from "./syntax/Node"; export type selection = "unselected" | Path.t; export type Stage = { - exp: Exp; + exp: Exp.t; selection: selection; info: Statics.InfoMap; //derived from exp projectors: Projector.PMap; //annotations @@ -18,7 +17,7 @@ export type Stage = { export type t = Stage; -const exp: Exp = World.init; +const exp: Exp.t = World.init; export const init: Stage = { exp, @@ -46,7 +45,7 @@ const rev = (path: Path.t): Path.t => { return blah.reverse(); }; -const move_up = (exp: Exp, selection: number[]): Path.t => { +const move_up = (exp: Exp.t, selection: number[]): Path.t => { if (selection.length === 0) return selection; const [last, ...tl] = rev(selection); const new_path = rev([last - 1, ...tl]); @@ -56,7 +55,7 @@ const move_up = (exp: Exp, selection: number[]): Path.t => { } else return selection; }; -const move_down = (exp: Exp, selection: number[]): Path.t => { +const move_down = (exp: Exp.t, selection: number[]): Path.t => { /* first, try to increment last idx of selection. if that gives a valid path, return it. then try to increment second last index, etc. @@ -77,7 +76,7 @@ const move_down = (exp: Exp, selection: number[]): Path.t => { return move_down(exp, Array(selection.length).fill(0)); }; -const move_left = (_exp: Exp, selection: number[]): Path.t => { +const move_left = (_exp: Exp.t, selection: number[]): Path.t => { if (selection.length === 0) { return selection; } else { @@ -85,7 +84,7 @@ const move_left = (_exp: Exp, selection: number[]): Path.t => { } }; -const move_right = (exp: Exp, selection: number[]): Path.t => { +const move_right = (exp: Exp.t, selection: number[]): Path.t => { const new_selection = [...selection, 1]; if (is_path_valid(new_selection, exp)) { return new_selection; @@ -120,4 +119,8 @@ export const move = ( export const indicated_id = (stage: Stage): ID.t | undefined => stage.selection === "unselected" ? undefined - : id_at(stage.selection, stage.exp); \ No newline at end of file + : id_at(stage.selection, stage.exp); + +export const projected_width = (stage: t) =>{ + console.log("width: " +Exp.width(Projector.project_folds(stage.projectors, stage.exp))) + return Exp.width(Projector.project_folds(stage.projectors, stage.exp));} diff --git a/src/Update.tsx b/src/Update.tsx index eab9398..e9304d0 100644 --- a/src/Update.tsx +++ b/src/Update.tsx @@ -15,6 +15,7 @@ import * as Path from "./syntax/Path"; import * as Util from "./Util"; import { reconcile } from "solid-js/store"; import * as Projectors from "./Projector"; +import * as Tone from "tone"; export type result = Model.t | "NoChange"; @@ -27,7 +28,8 @@ export const of_theme = (theme: Settings.theme): [number, number] => { } }; -export const sound = (model: Model.t, action: Action.t): void => { +export const sound = async (model: Model.t, action: Action.t): Promise => { + await Tone.start(); const [pitch, volume] = of_theme(model.settings.theme); switch (action.t) { case "transformNodeAndFlipTransform": @@ -246,12 +248,17 @@ export const update = (model: Model.t, action: Action.t): result => { }; export const viewTransition = (action: Action.t, f: () => void) => { + const r = document.querySelector(":root"); + if (action.t == "Project") { + if (r != null) r.style.setProperty("--anim-factor", "2"); + } const guy2 = document.getElementById("main"); guy2 ? guy2.classList.add(action.t) : console.log("no guy 1"); let v = document.startViewTransition(f); - v.finished.then(() => - guy2 ? guy2.classList.remove(action.t) : console.log("no guy 2") - ); + v.finished.then(() => { + guy2 ? guy2.classList.remove(action.t) : console.log("no guy 2"); + if (r != null) r.style.setProperty("--anim-factor", "1"); + }); }; // document.addEventListener("transitionstart", (e) => { // in_transition = true; diff --git a/src/data/Symbols.tsx b/src/data/Symbols.tsx new file mode 100644 index 0000000..523f2ac --- /dev/null +++ b/src/data/Symbols.tsx @@ -0,0 +1,3 @@ +import * as Exp from "../syntax/Exp"; + +export const digit = "ษ–"; diff --git a/src/data/Tools.tsx b/src/data/Tools.tsx index 7a6c901..34b0802 100644 --- a/src/data/Tools.tsx +++ b/src/data/Tools.tsx @@ -1,6 +1,7 @@ import * as Pat from "../syntax/Pat"; import * as Sound from "../Sound"; import * as Transform from "../Transform"; +import * as Symbols from "./Symbols"; type Base = { source: Pat.t; result: Pat.t; sound: Sound.Sfxbank }; @@ -30,8 +31,8 @@ const times_x = bin_x("โœ–๏ธ"); const times_y = bin_y("โœ–๏ธ"); const equals_x = bin_x("๐ŸŸฐ"); -const Bx = bin_x("ษ–"); -const By = bin_y("ษ–"); +const Bx = bin_x(Symbols.digit); +const By = bin_y(Symbols.digit); const two = Bx(zero, one); const b_def_0: Base = { diff --git a/src/data/World.tsx b/src/data/World.tsx index fe09f39..d445f94 100644 --- a/src/data/World.tsx +++ b/src/data/World.tsx @@ -1,10 +1,10 @@ import { Exp, atom, comp, flat } from "../syntax/Exp"; -import { empty } from "../syntax/Path"; +import * as Symbols from "../data/Symbols"; // โ˜๏ธ ๐Ÿงฉ ๐Ÿฆท ๐Ÿฆ  ๐ŸŒธ ๐Ÿ„ ๐ŸŽฒ ๐Ÿ // โž• โž– โœ–๏ธ โž— ๐ŸŸฐ ๐ŸŒ• ๐ŸŒ˜ ๐ŸŒ‘ 0๏ธโƒฃ 1๏ธโƒฃ โ“ -const B = flat("ษ–"); +const B = flat(Symbols.digit); export const alg: Exp = comp([ atom("โž•"), diff --git a/src/index.css b/src/index.css index aa74b14..7543372 100644 --- a/src/index.css +++ b/src/index.css @@ -1,5 +1,5 @@ :root { - --anim-factor: 1.25; + --anim-factor: 1; } .notransition * { @@ -184,6 +184,35 @@ } } +/* styles for mask */ +@keyframes mask-pulse-โœฟ { + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.03); + } +} +@keyframes mask-pulse-โ™ซ { + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.03); + } +} +@keyframes mask-pulse-โ™ฅ { + 0%, + 100% { + transform: scale(1); + } + 50% { + transform: scale(1.03); + } +} + body { user-select: none; height: 100vh; @@ -217,7 +246,7 @@ code { transition: border-radius 0.5s ease-in-out; /* padding: 1em; */ /* main scale factor: */ - font-size: 3em; + font-size: 4em; border-radius: 0em; box-shadow: inset 0px 0px 0.6em #ffffff; /* mix-blend-mode: color-dodge; */ @@ -249,17 +278,14 @@ code { } .node-container { - /*width: fit-content;*/ user-select: none; cursor: pointer; } .node.atom { - /*background-color: #ba65ff55;*/ - /*box-shadow: none*/ color: white; width: fit-content; - border-radius: 1em; /*0.5em 1.3em 0.9em 0.9em;*/ + border-radius: 1em; padding: 0 0.25em; justify-content: center; } @@ -270,7 +296,6 @@ code { animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: cubic-bezier(0.35, 0, 0.25, 0.35); - /*filter: brightness(1.1) drop-shadow(2px 4px 6px #f5f6);*/ } .transform .source, @@ -278,78 +303,42 @@ code { transition: filter 0.2s cubic-bezier(0.4, 0, 1, 1); } -/* balances out display of identity transform, mostly so - clicking the arrow to reverse the transform doesn't - end up moving the arrow */ -.transform .source > .node.atom, -.transform .result > .node.atom { - /*margin: 1.1em 0.5em 1.1em 1.8em;*/ -} - .node { transition: all 0.3s ease-in-out; transition: scale 0.1s linear; width: fit-content; display: flex; border-radius: 3em 1.2em 0.6em 32%; - padding: 0.07em; /*prev: both 0.20em*/ + padding: 0.07em; margin: 0.07em; align-items: center; box-shadow: 0.25em 0.25em 0.5em #773fcc40; - /*border-bottom: 0.3px solid rgba(13, 0, 95, 22); - border-top: 0.3px solid rgba(255, 255, 255, 66);*/ border-bottom: 0.3px solid rgb(45 93 111 / 18%); border-top: 0.3px solid rgb(173 207 229 / 55%); } .node:hover { - /*mix-blend-mode: color-dodge;*/ - /*transform: scale(1.03);*/ - /* filter: brightness(1.05); */ border-bottom: 0.3px solid rgb(187, 0, 255); border-top: 0.3px solid rgb(255, 100, 212); - /* scale: 1.03; */ } .node:hover:not(:has(.node:hover)) { scale: 1.02; } -.node:hover > .node { - /*scale: 0.99;*/ -} .node:has(.node:hover) { scale: 1; } .node.depth-0:hover { scale: 1 !important; } -/*.node.depth-0:hover { - transform: scale(1.01); -} -.node.depth-1:hover { - transform: scale(1.02); -} -.node.depth-2:hover { - transform: scale(1.02); -} -.node.depth-3:hover { - transform: scale(1.03); -} -.node.depth-4:hover { - transform: scale(1.03); -} -.node.depth-5:hover { - transform: scale(1.04); + +.node.comp { + text-shadow: 0 0 0 #50b0ff; } -.node.depth-6:hover { - transform: scale(1.04); -}*/ .node.selected, .node.selected:hover { - border: none; /* HACK */ box-shadow: 0px 0px 0.6em #ffffff; outline: 2px solid white; } - .node.selected > .head, .node.selected > .head { animation-name: pulse-scale; @@ -357,81 +346,56 @@ code { animation-iteration-count: infinite; animation-timing-function: cubic-bezier(0.35, 0, 0.25, 0.35); } - -.node.floatselect { - position: absolute; - /* left: -3px; */ - outline: 2px solid red; - /* margin: 0 auto; */ - left: 0; - top: 0; - opacity: 20%; -} -.node.floatselect > * { - /*opacity: 0;*/ -} - -.node.comp { - /* display: flex; - color: transparent; */ - text-shadow: 0 0 0 #50b0ff; -} .node:active { - /*animation-name: wobble; - animation-duration: 1s;*/ animation-delay: 0.25s; animation-name: wobble2; animation-duration: 0.15s; animation-iteration-count: infinite; } -.node-container > .node.comp.folded { + +/* FOLDS */ + +.node-container > .node.folded { background: none !important; border: none !important; box-shadow: none; } -.node-container > .node.folded > .node.enfolded { - border-left: none !important; -} -.node.comp.folded { - background-color: antiquewhite !important; +#stage .node.atom.folded, +#stage .node.comp.folded { + background: antiquewhite; } -.node.comp.folded:has(> .head:only-child) { +.node.folded:has(> .head:only-child) { border-radius: 2em; } -.node.comp.folded > .head { +.node.folded > .head { font-size: 0.8em; color: black; } -.node.comp.folded > .head:after { - font-size: 0.4em; +.node.folded > .head:after { content: "\00a0โ‹ฏ"; } -.node.comp.enfolded, -.node.atom.enfolded { - /* outline: solid 0.3px #009571; */ - /* box-shadow: 0 0 0.8em #00543c; */ - border-left: 5px solid #9c7bdf !important; - border-top: 0.7px solid #9c7bdf !important; - border-bottom: 0.7px solid #9c7bdf !important; - - /* filter: sepia(1) saturate(0) contrast(0.8); */ -} -.node.folded .node.enfolded { - background-color: #c7eee9 !important; - border-color: antiquewhite !important; +.node.enfolded { + border-left: 3.5px solid #9c7bdf ; + /* border-top: 0.7px solid #9c7bdf ; + border-bottom: 0.7px solid #9c7bdf ; */ +} +*:not(.node-container) > .node.folded > .node.enfolded { + border-left: 1px solid #9c7bdf; + background-color: #c7f0e3; + box-shadow: inset 0.5em 0 1em #dacae6aa; +} +.node-container > .node.folded > .node.enfolded { + border-left: none; + background: none; } -/* .node.selected .node.enfolded { - background-color: #d2f5e4 !important; - box-shadow: 0em 0em 1em white; - filter:none !important; +.node-container > .node.folded > .node.enfolded { + /* border-left: none !important; */ } -.node.selected:has(.node.enfolded) { - background-color: #ffffff75 !important; - filter:none !important; -} */ -#stage .node.comp { +/* STAGE */ + +.node.comp:not(.pat) { /*background-color: #005bff26;*/ background: linear-gradient( 222deg, @@ -482,153 +446,7 @@ code { grid-column: 1/3; } -/* nool 3d */ -/*#stage .node-container.TreeTop .node.comp { - transform: perspective(10em) rotateX(37deg); - background: linear-gradient( 222deg, #32b7bd, #43dddc, #00ffba, #ffb7ec, #7f91ff ); - border-bottom: 0.3px solid rgb(255 0 220 / 53%); - border-top: 1px solid rgb(255 255 255); - border-left: 0.3px solid white; - border-right: 0.3px solid white; -}*/ - -.node-container.TreeLeft .node.comp { - /* grid-template-columns: fit-content(1.5em) 1fr; */ - /*align-items: center;*/ - display: grid; - grid-auto-flow: column; - grid-column: 2; -} -.node-container.TreeLeft .node.comp .head { - grid-column: 1; - grid-row: 1/100; -} - -#seed:has(.LinearPrefix), -#seed:has(.LinearInfix) { - flex-direction: column-reverse; -} - -.node-container.LinearPrefix:has(.selected) .node.atom, -.node-container.LinearInfix:has(.selected) .node.atom, -.node-container.LinearPrefix:has(.selected) .head, -.node-container.LinearInfix:has(.selected) .head { - opacity: 50%; -} - -.node-container.LinearPrefix .node.selected, -.node-container.LinearInfix .node.selected, -.node-container.LinearPrefix .node.selected .node.atom, -.node-container.LinearInfix .node.selected .node.atom, -.node-container.LinearPrefix .node.selected .head, -.node-container.LinearInfix .node.selected .head { - opacity: 100% !important; -} - -.node-container.LinearPrefix .node.comp, -.node-container.LinearInfix .node.comp { - margin: 0; - padding: 0; - border-radius: 1.5em; - box-shadow: none; -} -.node-container.LinearPrefix .node.atom, -.node-container.LinearInfix .node.atom { - border-radius: 1.5em; - border-color: #0000; - box-shadow: none; -} - -.node-container.LinearInfix .node.atom:not(.selected) { - box-shadow: #0000; -} - -.node-container.LinearInfix .node.selected:has(> *), -.node-container.LinearInfix .node.selected:has(> *):hover { - border: 0; - outline: 0.03em solid #ffffff; - box-shadow: 0px 0px 0.6em #ffffff; - /* mix-blend-mode: color-dodge; */ - /* outline: 1px solid #258b86; */ - background: none; - outline: 0 !important; - box-shadow: none !important; - border-color: #0000 !important; -} - -.node-container.LinearInfix .node.selected > .node { - outline: 2px dotted white; - border-color: #0000 !important; - /*transform: scale(1.03);*/ - box-shadow: 7px 7px 15px #008750aa !important; -} - -.node-container.LinearInfix .node:hover { - transform: scale(1.01); -} - -.node-container.LinearInfix .node.comp *:nth-child(1) { - order: 2; -} -.node-container.LinearInfix .node.comp *:nth-child(2) { - order: 1; -} -.node-container.LinearInfix .node.comp *:nth-child(3) { - order: 3; -} -/* Special case for unary ops (TODO: Betterize) */ -.node-container.LinearInfix - .node.comp:has(> :nth-child(2):last-child) - *:nth-child(1) { - order: 1; -} - -#seed.SingleChar #stage .node.comp, -#seed.SingleChar #noolbox .node.comp { - border-left: 0.3px solid rgb(255 0 220 / 53%); - border-right: 0.3px solid rgb(119 198 168); - border-top: none; - border-bottom: none; - border-radius: 0.8em; -} -/* HACKY */ -#seed.SingleChar #stage .node.comp:not(.mask), -#seed.SingleChar #noolbox .node.comp:not(.mask) { - background: none; -} - -#seed.SingleChar .node.atom, -#seed.SingleChar .head { - font-family: "Roboto"; - font-weight: 700; - font-family: monospace; - - border-top: none; - border-bottom: none; - box-shadow: none; -} -#seed.SingleChar .node.atom { - padding: 0 0.4em 0 0.4em; - color: #474646; -} -#seed.SingleChar .head { - padding: 0 0.35em 0 0.35em; - color: #2d8b7e; -} -#seed.SingleChar .selected > .head { - -webkit-text-stroke-width: 0.02em; - -webkit-text-stroke-color: black; -} - -#seed.SingleChar .NoMatch .node.comp { - box-shadow: none; -} - -/*#seed.LinearPrefix { - flex-direction: column-reverse; - justify-content: center; - align-items: flex-start; -}*/ +/* NOOLBOX */ #noolbox { box-shadow: inset -8px 0px 8px #3ca38211, inset -4px 0px 4px #3ca38211, @@ -638,22 +456,14 @@ code { display: grid; grid-template-columns: 1fr 0.7em 1fr; user-select: none; - /* background-color: #aee7e866; */ border-radius: 0 0.9em 0.9em 0em; - /* border-top: 0.04em solid #5bf296; */ border-bottom: 0.04em solid #53f5ff66; - /* border-top: 0.02em solid #f8a7ff66; */ width: fit-content; padding: 0.3em 0.4em 0.3em 0; } .TreeLeft #noolbox { height: 9.2em; } -/*#noolbox .result .node.comp, -#noolbox .source .node.comp { - border-radius: 0.6em 2em 2.5em 0.5em; - flex-direction: row-reverse; -}*/ .transform-view { position: relative; @@ -666,9 +476,6 @@ code { grid-template-columns: subgrid; grid-column: 1 / span 3; align-items: center; - /*background-color: #f0f0f077; - border-top: 0.4px solid #b0b0b099; - border-bottom: 1.1px solid #f0f0f1;*/ transition: all 0.05s; font-variant: diagonal-fractions; text-shadow: 0 -0.3px 0 #469aa5; @@ -704,10 +511,7 @@ v .transform-view .label { /*animation-name: wobble3; animation-duration: 0.15s;*/ } -.transform-view .result .node, -.transform-view .source .node { - /*transition: all 0.1s ease-in;*/ -} + .transform-view .result.selected > .node, .transform-view .source.selected > .node { outline: 0.14em solid #9e00ff; @@ -720,14 +524,9 @@ v .transform-view .label { } .transform-view .node.comp { - /*transition: all 0.1s ease-in-out; - box-shadow: 0.25em 0.25em 0.5em #55ac8740;*/ box-shadow: 0.1em 0.1em 1.4em #55ac8740; border-bottom: 0.1px solid #8ee347; } -.Light .transform-view .node-container.match > .node:hover { - outline: 2px solid white; -} .transform-view:active { color: black; @@ -738,41 +537,6 @@ v .transform-view .label { box-shadow: none; } -.previews { - display: flex; - flex-direction: column; - gap: 0.2em; - /* font-size: 0.25em; */ - border-radius: 0.8em 0 0 0.8em; - padding: 0.5em 0 0.5em 0.5em; - border-top: 0.04em solid #d4a4d8; - border-bottom: 0.04em solid #7ae0e6; -} -.previews .node-container { - font-size: 0.25em; - mix-blend-mode: color-burn !important; - filter: saturate(1) opacity(0.5) hue-rotate(277deg) blur(0.2em) !important; -} -.previews .node-container:hover { - filter: saturate(1) brightness(0.1) invert(1) opacity(1) hue-rotate(210deg); - mix-blend-mode: exclusion; -} -.previews .node.comp { - background-color: #005bff26; - transition: all 0.05s ease-in-out; -} -.previews .node-container:hover .node.comp { - box-shadow: none; - background-color: #0000; - transform: none; -} -.previews .id-view { - display: none; -} -#main.setSelect.selected #seed .previews { - mix-blend-mode: color-burn !important; -} - #toolbar { grid-row: 2 / span 1; grid-column: 1 / span 1; @@ -785,11 +549,6 @@ v .transform-view .label { opacity: 80%; } -#stage { - /*grid-row: 2 / span 1; - grid-column: 3 / span 1;*/ -} - .transform-arrow { display: flex; justify-content: center; @@ -797,17 +556,9 @@ v .transform-view .label { -moz-background-clip: text; background-clip: text; } -.Light .transform-arrow { - background-color: #009f46; - text-shadow: 0.01em 0.02em 0.02em rgb(216 248 227); -} -.Dark .transform-arrow { - background-color: #5aae3a; - text-shadow: 0.01em 0.02em 0.02em rgb(8 90 111); -} -.match:hover + .transform-arrow, -.transform-arrow:has(+ .match:hover) { - color: white; +.match:hover + .transform-arrow, +.transform-arrow:has(+ .match:hover) { + color: white; } .source.match:hover + div + .result .atom { color: black; @@ -826,250 +577,399 @@ v .transform-view .label { color: #00e6f0; box-shadow: none; border-color: #0000; - /*box-shadow: 0 0 1em #0ffa; - mix-blend-mode: lighten;*/ } .pat.node.atom.โ™ฅ { background-color: #ffd5fc; color: #f8abf2; box-shadow: none; border-color: #0000; - /*box-shadow: 0 0 1em #f0fa; - mix-blend-mode: lighten;*/ } .pat.node.atom.โœฟ { background-color: #ffffb2; color: #f7e300; box-shadow: none; border-color: #0000; - /*box-shadow: 0 0 1em #ff0a; - mix-blend-mode: lighten;*/ +} +.pat.node.comp { + position: relative; + display: flex; + flex-direction: row; } -/* styles for mask */ -@keyframes mask-pulse-โœฟ { - 0%, - 100% { - transform: scale(1); - } - 50% { - transform: scale(1.03); - } +.NoMatch .node.pat.atom, +.NoMatch .head { + color: #682828; + opacity: 20%; } -@keyframes mask-pulse-โ™ซ { - 0%, - 100% { - transform: scale(1); - } - 50% { - transform: scale(1.03); - } +.NoMatch .node.pat.atom, +.NoMatch .head .NoMatch .node.comp { + box-shadow: 0.1em 0.1em 1.4em #55ac8740; } -@keyframes mask-pulse-โ™ฅ { - 0%, - 100% { - transform: scale(1); - } - 50% { - transform: scale(1.03); - } + +.NoMatch { + opacity: 0.9; } -#stage .node.mask.โœฟ { +.node.mask.โœฟ { animation-name: mask-pulse-โœฟ; background-color: yellow; filter: sepia(100%) saturate(240%) brightness(98%) hue-rotate(-10deg); } -#stage .node.mask.โ™ซ { +.node.mask.โ™ซ { animation-name: mask-pulse-โ™ซ; background-color: cyan; filter: sepia(100%) saturate(240%) brightness(98%) hue-rotate(140deg); } -#stage .node.mask.โ™ฅ { +.node.mask.โ™ฅ { animation-name: mask-pulse-โ™ฅ; background-color: #f772f7; filter: sepia(100%) saturate(240%) brightness(98%) hue-rotate(280deg); } -#stage .node.mask { +.node.mask { animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: cubic-bezier(0.35, 0, 0.25, 0.35); - /*filter: brightness(1.1) drop-shadow(2px 4px 6px #f5f6);*/ } .node.mask .node { - /* border-top: 1px solid #a3a3a3; */ border-bottom: 1px solid #0007; } -.pat.node.comp { - position: relative; - display: flex; - flex-direction: row; +.id-view { + display: contents; + font-size: 3pt; } -.NoMatch .node.pat.atom, -.NoMatch .head { - color: #682828; - opacity: 20%; +.๐ŸŒ‘ { + filter: brightness(1.4); } -.NoMatch .node.pat.atom, -.NoMatch .head .NoMatch .node.comp { - box-shadow: 0.1em 0.1em 1.4em #55ac8740; + +/* SEED */ + +#seed { + height: 100vh; + display: flex; + align-items: center; + justify-content: center; } -.NoMatch { - opacity: 0.9; - /* filter: opacity(0.6) sepia(1) saturate(0) brightness(0.6) contrast(5); */ +#seed .icon { + padding: 0.5em 0.5em 0.5em 0.5em; + filter: sepia(1) hue-rotate(210deg) saturate(4) brightness(1); + opacity: 0.4; + cursor: default; + transition: transform 1s cubic-bezier(0.68, -0.6, 0.32, 1.6); } -.id-view { - display: contents; - font-size: 3pt; - /* position: absolute; - left: 1em; - color: #c8cfff; - text-shadow: 0.3px 0.2px 0.5px #7856ba;*/ +/* Wrapper to hold space */ +#seed .icon2 { + width: calc(1.9766em * 0.5); + height: calc(1em * 0.5); + position: relative; + margin: 0.5em 0.05em 0.5em 0.5em; + transition: transform 1s cubic-bezier(0.68, -0.6, 0.32, 1.6), + margin 0.1s linear; } -.๐ŸŒ‘ { - filter: brightness(1.4); +#seed .icon2:has(+ #stage .selected) .inner { + filter: invert(1) brightness(10.5) sepia(1) hue-rotate(200deg) saturate(2); } -#settings-panel { +/* Actual image container */ +#seed .icon2 .inner { + filter: invert(1) brightness(0.5) sepia(1) hue-rotate(200deg) saturate(2); + opacity: 0.8; + width: 100%; + height: 100%; + background-image: url("/src/assets/nool-seed-infinity-only.svg"); + background-size: 100% 100%; + transition: all 0.3s ease; position: absolute; - right: 0; - top: 0; + left: 50%; + transform: translateX(-50%); +} + +/* Image change on hover */ +#seed .icon2:active .inner { + background-image: url("/src/assets/nool-seed.svg"); + width: calc(4.1232em * 0.5); +} +#seed .icon2:active { + margin: 1em; + opacity: 1; + transform: rotate(-359deg); +} + +/* PREVIEWS PANEL */ + +.previews { display: flex; - gap: 0.25em; + flex-direction: column; + gap: 0.2em; + /* font-size: 0.25em; */ + border-radius: 0.8em 0 0 0.8em; + padding: 0.5em 0 0.5em 0.5em; + border-top: 0.04em solid #d4a4d8; + border-bottom: 0.04em solid #7ae0e6; +} +.previews .node-container { + font-size: 0.25em; + mix-blend-mode: color-burn !important; + filter: saturate(1) opacity(0.5) hue-rotate(277deg) blur(0.2em) !important; +} +.previews .node-container:hover { + filter: saturate(1) brightness(0.1) invert(1) opacity(1) hue-rotate(210deg); + mix-blend-mode: exclusion; +} +.previews .node.comp { + background-color: #005bff26; + transition: all 0.05s ease-in-out; +} +.previews .node-container:hover .node.comp { + box-shadow: none; + background-color: #0000; + transform: none; +} +.previews .id-view { + display: none; +} +#main.setSelect.selected #seed .previews { + mix-blend-mode: color-burn !important; } -#settings-panel .icon:hover { - opacity: 100%; - filter: invert(0); +/* ROOM NODES */ + +.node.ไทถ > .node:where(.แ–›, .แ™Š, .แ) { + background: none; + box-shadow: none; + border-left: 0.3px solid #6b19da52; + border-top: none; + border-bottom: none; } -#settings-panel .icon { - opacity: 90%; - width: 0.5em; - padding: 0.15em; - filter: invert(1); - position: fixed; - scale: 0.8; +.node.ไทถ > .head, +.node.ไทถ > .node:where(.แ–›, .แ™Š, .แ) > .head { + text-shadow: 0.01em 0.02em 0.02em rgb(212 245 228); +} +.node.ไทถ.selected > .head, +.node.ไทถ > .node:where(.แ–›, .แ™Š, .แ).selected > .head { + animation-name: none; + color: black; + text-shadow: 0.01em 0.02em 0.02em rgb(32 100 65); } -#settings-panel .icon:nth-child(1) { - left: 0; - top: 0; +.node.comp.ไทถ { + border-radius: 2.7em 0.3em 0.3em 2.7em; + display: grid; + grid-auto-flow: unset; + grid-template-columns: fit-content(1em) 1fr; + grid-template-rows: repeat(1fr); + background: none; + box-shadow: -1em 0em 1.5em #34b59516; + border: none; + border-left: 0.3px solid #19dac5; +} +.node.ไทถ.selected, +.node.ไทถ > .node:where(.แ–›, .แ™Š, .แ).selected { + outline: none; + border-left: 0.07em solid white; } -#settings-panel .icon:nth-child(2) { - right: 0; - bottom: 0; +/* NODE LAYOUT: DIGITS */ + +#noolbox .node.digits .node.digits, +#stage .node.digits .node.digits, +#noolbox .node.digits .atom, +#stage .node.digits .atom { + box-shadow: none; + padding: 0; + border: none; } -#settings-panel .icon:nth-child(3) { - left: 0; - bottom: 0; +#noolbox .node.digits, +#stage .node.digits { + border-radius: 1.1em; + padding: 0; + margin: 0; + background-color: #0000; + box-shadow: none; + border-color: #0000; +} + +#noolbox .node.comp.digits .head, +#stage .node.comp.digits .head { + color: black; + text-shadow: none; + padding: 0; +} + +#stage .node.comp.digits.selected .head { + filter: brightness(1) !important; +} + +#noolbox .node:not(.digits):has(.digits) > .digits, +#stage .node:not(.digits):has(.digits) > .digits { + padding-left: 0.15em; + padding-right: 0.15em; +} + +/* NODE LAYOUTS */ + +/* nool 3d */ +/*#stage .node-container.TreeTop .node.comp { + transform: perspective(10em) rotateX(37deg); + background: linear-gradient( 222deg, #32b7bd, #43dddc, #00ffba, #ffb7ec, #7f91ff ); + border-bottom: 0.3px solid rgb(255 0 220 / 53%); + border-top: 1px solid rgb(255 255 255); + border-left: 0.3px solid white; + border-right: 0.3px solid white; +}*/ + +.node-container.TreeLeft .node.comp { + display: grid; + grid-auto-flow: column; +} +.node-container.TreeLeft .node.comp .head { + grid-column: 1; + grid-row: 1/100; +} + +#seed:has(.LinearPrefix), +#seed:has(.LinearInfix) { + flex-direction: column-reverse; +} + +.node-container.LinearPrefix:has(.selected) .node.atom, +.node-container.LinearInfix:has(.selected) .node.atom, +.node-container.LinearPrefix:has(.selected) .head, +.node-container.LinearInfix:has(.selected) .head { + opacity: 50%; +} + +.node-container.LinearPrefix .node.selected, +.node-container.LinearInfix .node.selected, +.node-container.LinearPrefix .node.selected .node.atom, +.node-container.LinearInfix .node.selected .node.atom, +.node-container.LinearPrefix .node.selected .head, +.node-container.LinearInfix .node.selected .head { + opacity: 100% !important; +} + +.node-container.LinearPrefix .node.comp, +.node-container.LinearInfix .node.comp { + margin: 0; + padding: 0; + border-radius: 1.5em; + box-shadow: none; +} +.node-container.LinearPrefix .node.atom, +.node-container.LinearInfix .node.atom { + border-radius: 1.5em; + border-color: #0000; + box-shadow: none; +} + +.node-container.LinearInfix .node.atom:not(.selected) { + box-shadow: #0000; +} + +.node-container.LinearInfix .node.selected:has(> *), +.node-container.LinearInfix .node.selected:has(> *):hover { + border: 0; + outline: 0.03em solid #ffffff; + box-shadow: 0px 0px 0.6em #ffffff; + background: none; + outline: 0 !important; + box-shadow: none !important; + border-color: #0000 !important; } -#settings-panel .icon:nth-child(4) { - right: 0; - top: 0; +.node-container.LinearInfix .node.selected > .node { + outline: 2px dotted white; + border-color: #0000 !important; + box-shadow: 7px 7px 15px #008750aa !important; } -#settings-panel .icon:nth-child(5) { - right: 0.75em; - top: 0; +.node-container.LinearInfix .node:hover { + transform: scale(1.01); } -#settings-panel .icon:nth-child(6) { - right: 0em; - top: 0.75em; +.node-container.LinearInfix .node.comp *:nth-child(1) { + order: 2; } - -.toolbar2 { +.node-container.LinearInfix .node.comp *:nth-child(2) { + order: 1; } -.toolbar2 ul { +.node-container.LinearInfix .node.comp *:nth-child(3) { + order: 3; } -.toolbar2 li { +/* Special case for unary ops (TODO: Betterize) */ +.node-container.LinearInfix + .node.comp:has(> :nth-child(2):last-child) + *:nth-child(1) { + order: 1; } -#seed { - height: 100vh; - display: flex; - align-items: center; - justify-content: center; - /* gap: 0.7em; */ +#seed.SingleChar #stage .node.comp, +#seed.SingleChar #noolbox .node.comp { + border-left: 0.3px solid rgb(255 0 220 / 53%); + border-right: 0.3px solid rgb(119 198 168); + border-top: none; + border-bottom: none; + border-radius: 0.8em; +} +/* HACKY */ +#seed.SingleChar #stage .node.comp:not(.mask), +#seed.SingleChar #noolbox .node.comp:not(.mask) { + background: none; } -/*#seed { - display: grid; - grid-template-columns: fit-content(30%) 2em fit-content(30%); - grid-auto-flow: row; - align-content: center; - align-items: center; -}*/ +#seed.SingleChar .node.atom, +#seed.SingleChar .head { + font-family: "Roboto"; + font-weight: 700; + font-family: monospace; -#seed .icon { - padding: 0.5em 0.5em 0.5em 0.5em; - filter: sepia(1) hue-rotate(210deg) saturate(4) brightness(1); - opacity: 0.4; - cursor: default; - transition: transform 1s cubic-bezier(0.68, -0.6, 0.32, 1.6); + border-top: none; + border-bottom: none; + box-shadow: none; } - -/* Wrapper to hold space */ -#seed .icon2 { - width: calc(1.9766em * 0.5); - height: calc(1em * 0.5); - position: relative; - margin: 0.5em; - transition: transform 1s cubic-bezier(0.68, -0.6, 0.32, 1.6), - margin 0.1s linear; +#seed.SingleChar .node.atom { + padding: 0 0.4em 0 0.4em; + color: #474646; +} +#seed.SingleChar .head { + padding: 0 0.35em 0 0.35em; + color: #2d8b7e; +} +#seed.SingleChar .selected > .head { + -webkit-text-stroke-width: 0.02em; + -webkit-text-stroke-color: black; } -/* Actual image container */ -#seed .icon2 .inner { - filter: invert(1) brightness(0.5) sepia(1) hue-rotate(200deg) saturate(2); - opacity: 0.8; - width: 100%; - height: 100%; - background-image: url("/src/assets/nool-seed-infinity-only.svg"); - /* background-size: cover; */ - background-size: 100% 100%; - transition: all 0.3s ease; - position: absolute; - left: 50%; - transform: translateX(-50%); +#seed.SingleChar .NoMatch .node.comp { + box-shadow: none; } -/* Image change on hover */ -#seed .icon2:active .inner { - background-image: url("/src/assets/nool-seed.svg"); - width: calc(4.1232em * 0.5); +/* LIGHT MODE*/ + +.Light .transform-arrow { + background-color: #009f46; + text-shadow: 0.01em 0.02em 0.02em rgb(216 248 227); } -#seed .icon2:active { - /* animation: spin 0.4s infinite linear; */ - margin: 1em; - opacity: 1; - transform: rotate(-359deg); +.Light .transform-view .node-container.match > .node:hover { + outline: 2px solid white; +} +.Light .transform-view .pat.node { + box-shadow: 0.05em 0.05em 0.1em #90c2b344, 0.1em 0.1em 0.2em #90c2b344, + 0.2em 0.2em 0.4em #90c2b344, 0.4em 0.4em 0.8em #90c2b344, + 0.8em 0.8em 1.6em #90c2b344, -0.05em -0.05em 0.1em #e0ffe544, + -0.1em -0.1em 0.2em #ebfff744, -0.2em -0.2em 0.4em #d2fff044, + -0.4em -0.4em 0.8em #cff2e644, -0.8em -0.8em 1.6em #d2fff044; } -#seed .icon2:active .inner { - /* animation: spin 0.4s infinite linear; */ - /* filter: invert(1) drop-shadow(0px 0px 8px rgb(0, 93, 52)); */ -} -/*#seed .icon2:hover .inner { -mix-blend-mode: plus-lighter; -transition: all; -transition-duration: 2s; -animation: flare; -animation-duration: 2s; -animation-timing-function: linear; -}*/ -/* dark mode */ +/* DARK MODE */ body:has(#main.Dark) { background-image: linear-gradient( @@ -1119,11 +1019,6 @@ body:has(#main.Dark) { animation-duration: 1s; animation-iteration-count: infinite; } -.Dark .node.selected, -.Dark .node.selected:hover { - /*box-shadow: none; - outline: 1.4px solid #00ffb6;*/ -} .Dark .node.selected:has(.mask) { box-shadow: none; outline: none; @@ -1139,6 +1034,10 @@ body:has(#main.Dark) { inset 0px -2px 2px #a000ff, inset 0px -4px 4px #9d80ff33, inset 0px -8px 8px #9d80ff33, inset 0px -16px 16px #9d80ff33; } +.Dark .transform-arrow { + background-color: #5aae3a; + text-shadow: 0.01em 0.02em 0.02em rgb(8 90 111); +} /* HACKY INTERACTIONS */ .Dark .Emoji #stage .node.mask.โœฟ { @@ -1164,26 +1063,70 @@ body:has(#main.Dark) { color: black !important; } -::view-transition-old(flip-node-selected), -::view-transition-new(flip-node-selected) { - /*transition: none; - transition: transform 250ms cubic-bezier(0.68, -0.6, 0.32, 1.6) !important;*/ - /*animation-duration: 200ms !important; - transition: transform 250ms cubic-bezier(0.68, -0.6, 0.32, 1.6) !important; - height: auto; +/* SETTINGS RING */ + +#settings-panel { + position: absolute; + right: 0; + top: 0; + display: flex; + gap: 0.25em; +} + +#settings-panel .icon:hover { + opacity: 100%; + filter: invert(0); +} + +#settings-panel .icon { + opacity: 90%; + width: 0.5em; + padding: 0.15em; + filter: invert(1); + position: fixed; + scale: 0.8; +} + +#settings-panel .icon:nth-child(1) { + left: 0; + top: 0; +} + +#settings-panel .icon:nth-child(2) { + right: 0; + bottom: 0; +} + +#settings-panel .icon:nth-child(3) { + left: 0; + bottom: 0; +} + +#settings-panel .icon:nth-child(4) { right: 0; - left: auto; - transform-origin: right center;*/ + top: 0; +} + +#settings-panel .icon:nth-child(5) { + right: 0.75em; + top: 0; +} + +#settings-panel .icon:nth-child(6) { + right: 0em; + top: 0.75em; } + + +/* VIEW TRANSITIONS */ + .selected { - /* needs some tlc. dont want internals to show during transition - */ + /* needs some tlc. dont want internals to show during transition */ view-transition-name: flip-node-selected; } #main.setSelect .selected, #main.unsetSelections .selected { - /* needs some tlc. dont want internals to show during transition - */ + /* needs some tlc. dont want internals to show during transition */ view-transition-name: flip-node-selected !important; } @@ -1193,22 +1136,14 @@ body:has(#main.Dark) { #seed #noolbox { view-transition-name: flip-noolbox; } -#seed .previews { - /* view-transition-name: flip-previews; */ -} ::view-transition-group(flip-node-selected) { view-transition-name: selected; - animation-timing-function: easeInBack; /*easeInBack; easeOutBounce;*/ + animation-timing-function: easeInBack; animation-duration: calc(var(--anim-factor) * 0.2s); } -::view-transition-old(flip-node-selected) { -} -::view-transition-new(flip-node-selected) { -} ::view-transition-group(*) { - /*pointer-events: none;*/ animation-duration: calc(var(--anim-factor) * 0.25s); animation-fill-mode: both; animation-timing-function: cubic-bezier(0.68, -0.6, 0.32, 1.6); @@ -1217,24 +1152,10 @@ body:has(#main.Dark) { ::view-transition-new(*) { height: 100%; width: 100%; - /*animation-name: none !important;*/ - /*animation-name: none !important; - animation-fill-mode: forwards; - opacity: 0;*/ - /*animation-name: none;*/ } ::view-transition-old(*) { height: 100%; width: 100%; - /*animation-name: none !important;*/ - /*animation-name: none !important;*/ - - /*pointer-events: none;*/ - /*animation-name: none;*/ -} - -::view-transition { - /*pointer-events: none;*/ } .selected-transition * { @@ -1244,90 +1165,3 @@ body:has(#main.Dark) { background-color: red !important; outline: 0.2em solid red; } - -.Light .transform-view .pat.node { - box-shadow: 0.05em 0.05em 0.1em #90c2b344, 0.1em 0.1em 0.2em #90c2b344, - 0.2em 0.2em 0.4em #90c2b344, 0.4em 0.4em 0.8em #90c2b344, - 0.8em 0.8em 1.6em #90c2b344, -0.05em -0.05em 0.1em #e0ffe544, - -0.1em -0.1em 0.2em #ebfff744, -0.2em -0.2em 0.4em #d2fff044, - -0.4em -0.4em 0.8em #cff2e644, -0.8em -0.8em 1.6em #d2fff044; -} - -#stage .node.ไทถ > .node { - background: none; - box-shadow: none; - border-left: 0.3px solid #6b19da52; - border-top: none; - border-bottom: none; -} - -#stage .node.ไทถ > .head, -#stage .node.ไทถ > .node > .head { - text-shadow: 0.01em 0.02em 0.02em rgb(212 245 228); -} -#stage .node.ไทถ.selected > .head, -#stage .node.ไทถ > .node.selected > .head { - animation-name: none; - color: black; - text-shadow: 0.01em 0.02em 0.02em rgb(32 100 65); -} - -#stage .node.ไทถ { - border-radius: 2.7em 0.3em 0.3em 2.7em; - display: grid; - grid-auto-flow: unset; - grid-template-columns: fit-content(1em) 1fr; - grid-template-rows: repeat(1fr); - background: none; - box-shadow: -1em 0em 1.5em #34b59516; - border: none; - border-left: 0.3px solid #19dac5; -} -#stage .node.ไทถ.selected, -#stage .node.ไทถ > .node.selected { - outline: none; - border-left: 0.07em solid white; -} -#noolbox .node.digits .node.digits, -#stage .node.digits .node.digits, -#noolbox .node.digits .atom, -#stage .node.digits .atom { - /* background: none; */ - box-shadow: none; - padding: 0; - border: none; - /* width: 1.1em; */ - /* border-radius: 0.1em; */ - /* height: 1.7em; */ -} -.node.comp:has(> .node.digits) { - /* display: flex; */ - /* justify-items: flex-end; */ -} - -#noolbox .node.digits, -#stage .node.digits { - border-radius: 1.1em; - padding: 0; - margin: 0; - background-color: #0000; - box-shadow: none; - border-color: #0000; -} - -#noolbox .node.comp.digits .head, -#stage .node.comp.digits .head { - color: black; - text-shadow: none; - padding: 0; -} - -#stage .node.comp.digits.selected .head { - filter: brightness(1) !important; -} - -#noolbox .node:not(.digits):has(.digits) > .digits, -#stage .node:not(.digits):has(.digits) > .digits { - padding-left: 0.15em; - padding-right: 0.15em; -} diff --git a/src/syntax/Exp.tsx b/src/syntax/Exp.tsx index 738dda2..873daee 100644 --- a/src/syntax/Exp.tsx +++ b/src/syntax/Exp.tsx @@ -1,4 +1,5 @@ import * as Node from "./Node"; +import * as Symbols from "../data/Symbols"; export type t = Node.t; export type Exp = t; @@ -28,15 +29,29 @@ const cons = (base: string) => (hd: string, tl: Exp): Exp => comp([atom(base), atom(hd), tl]); - + export const flat = (base: string) => (contents: string[]): Exp => contents.length == 0 - ? atom("ษ–") + ? atom(base) : contents .slice(0, -1) .reduceRight( (acc, cur) => cons(base)(cur, acc), atom(contents.slice(-1)[0]) ); + +export const is_digits = (e: t) => head_is(Symbols.digit, e); + +export const width = (node: t): number => { + //TODO: Currently special casting on treeleft projection + switch (node.t) { + case "Atom": + return 1; + case "Comp": + return is_digits(node) + ? 1 + : Math.max(1, -1 + node.kids.reduce((acc, n) => acc + width(n), 0)); + } +}; diff --git a/src/syntax/Node.tsx b/src/syntax/Node.tsx index eeee93a..2770c77 100644 --- a/src/syntax/Node.tsx +++ b/src/syntax/Node.tsx @@ -39,9 +39,9 @@ export function map_ids(f: (id: ID.t) => ID.t, e: t): t { export function head(e: t): T | undefined { return e.t == "Comp" && e.kids.length > 0 && e.kids[0].t == "Atom" - ? e.kids[0].sym - : undefined; -} + ? e.kids[0].sym + : undefined; +} /* Zero out all ids */ export function erase(x: t): t { @@ -63,6 +63,17 @@ export function depth(node: t): number { } } +export function width(node: t): number { + //TODO: Minus max/-1 special casting on treeleft projection + //TODO: This doesn't work with digits... need to unabstract + switch (node.t) { + case "Atom": + return 1; + case "Comp": + return Math.max(1, -1 + node.kids.reduce((acc, n) => acc + width(n), 0)); + } +} + /* Structural equality modulo ids */ export function equals(a: t, b: t): boolean { switch (a.t) { diff --git a/src/syntax/Pat.tsx b/src/syntax/Pat.tsx index f89bfb4..9298c8b 100644 --- a/src/syntax/Pat.tsx +++ b/src/syntax/Pat.tsx @@ -3,6 +3,7 @@ import * as Node from "./Node"; import * as Exp from "./Exp"; import * as ID from "./ID"; import * as Path from "./Path"; +import * as Symbols from "../data/Symbols"; export type Symbol = { t: "Var"; name: string } | { t: "Const"; name: string }; @@ -266,31 +267,9 @@ export const transform_at_path = ( } }; -export const transform_at_path2 = ( - exp: Exp.t, - pat: Pat, - template: Pat, - path: Path.t -): TransformResult => { - if (path.length === 0) { - return transform(exp, pat, template); - } else { - let [hd, ...tl] = path; - switch (exp.t) { - case "Atom": - return "NoMatch"; - case "Comp": - //TODO: cleanup... - const res = transform_at_path(exp.kids[hd], pat, template, tl); - if (res === "NoMatch") return "NoMatch"; - let kids = exp.kids.map((kid, index) => { - if (index === hd) { - const res = transform_at_path(kid, pat, template, tl); - if (res === "NoMatch") return kid; - else return res; - } else return kid; - }); - return { ...exp, kids }; - } - } -}; +export const head_is = + (sym: string) => + (node: t): boolean => + Node.head(node)?.name === sym; + +export const is_digits = head_is(Symbols.digit); \ No newline at end of file diff --git a/src/view/ExpView.tsx b/src/view/ExpView.tsx index 6e77de5..bebe71c 100644 --- a/src/view/ExpView.tsx +++ b/src/view/ExpView.tsx @@ -43,7 +43,7 @@ const eff = (props: expviewprops): boolean => { return binding?.t == "Val" ? false : true; }; -const enfold = (props: expviewprops)=> ( e: MouseEvent) => { +const enfold = (props: expviewprops) => (e: MouseEvent) => { if (e.shiftKey) { return; } else { @@ -57,31 +57,41 @@ const enfold = (props: expviewprops)=> ( e: MouseEvent) => { } }; -const enfoldAction = (props: expviewprops)=> ( e: MouseEvent) => { +const enfoldAction = (props: expviewprops) => (e: MouseEvent) => { + const p = Projector.get(props.projectors, props.node.id); if (e.shiftKey) { return; - } else if (Projector.has_enfolded(props.projectors, props.node)) - props.inject({ - t: "Project", - id: props.node.id, - action: "toggleFoldCurrent", - }) + } else if (p.folded == "Folded") { + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); + } else if ( + Projector.has_enfolded(props.projectors, props.node) && + p.folded != "Enfolded" + ) + props.inject({ + t: "Project", + id: props.node.id, + action: "toggleFoldCurrent", + }); else { - switch(Projector.get(props.projectors, props.node.id).folded) { + switch (p.folded) { case "Enfolded": props.inject({ t: "Project", id: props.node.id, - action: "toggleFoldCurrent", - }); - break; - case "Folded": - props.inject({ - t: "Project", - id: props.node.id, - action: "toggleFoldCurrent", + action: "toggleEnfoldCurrent", }); break; + // case "Folded": + // props.inject({ + // t: "Project", + // id: props.node.id, + // action: "toggleFoldCurrent", + // }); + // break; default: props.inject({ t: "Project", @@ -95,7 +105,7 @@ const enfoldAction = (props: expviewprops)=> ( e: MouseEvent) => { e.stopPropagation(); }; -const selectOrFold = (props: expviewprops)=> ( e: MouseEvent) => { +const selectOrFold = (props: expviewprops) => (e: MouseEvent) => { e.preventDefault(); e.stopPropagation(); console.log("clicks: " + e.detail); @@ -171,7 +181,7 @@ const ExpViewGo: Component = (props) => { class={`comp ${Exp.head(props.node)} ${common_clss(props)}`} classList={{ animate: props.animate, - digits: Exp.head_is("ษ–", props.node), + digits: Exp.is_digits(props.node), folded: Projector.is_folded(props.node.id, props.projectors), enfolded: Projector.is_enfolded( props.node.id, @@ -186,7 +196,7 @@ const ExpViewGo: Component = (props) => { each={ /*Projector.is_folded(props.node.id, props.projectors) ? props.node.kids.slice(0, 1) - :*/ Exp.head_is("ษ–", props.node) + :*/ Exp.is_digits(props.node) ? props.node.kids.slice(1) : props.node.kids } diff --git a/src/view/StageView.tsx b/src/view/StageView.tsx index c9ca4c4..299b60d 100644 --- a/src/view/StageView.tsx +++ b/src/view/StageView.tsx @@ -4,9 +4,17 @@ import { Model } from "../Model"; import * as Action from "../Action"; import { ExpView } from "./ExpView"; import * as Hover from "../Hover"; -import { depth } from "../syntax/Node"; +import { depth, width } from "../syntax/Node"; +import * as Projector from "../Projector"; +import * as Stage from "../Stage"; -const stage_scale = (d: number) => (d == 0 ? 1 : 4 / (d + 1)); +const stage_scale = (w: number) => { + if (w < 10) { + return '0.8em'; + } else { + return `${100/1.85/w}vh`; + } +}; export const StageView: Component<{ model: Model; @@ -14,7 +22,9 @@ export const StageView: Component<{ }> = (props) => (