set up lustre and sass
This commit is contained in:
parent
9c1c11a277
commit
afafb49cd6
27 changed files with 814 additions and 61 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,6 +2,8 @@ target
|
||||||
.env
|
.env
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
|
css_dist
|
||||||
|
glm_dist
|
||||||
js_dist
|
js_dist
|
||||||
pgdata
|
pgdata
|
||||||
.vite
|
.vite
|
||||||
|
|
|
||||||
132
components/src/add-selection-button.ts
Normal file
132
components/src/add-selection-button.ts
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
import { css, html, LitElement } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators.js";
|
||||||
|
import { createRef, ref } from "lit/directives/ref.js";
|
||||||
|
|
||||||
|
import "./add-selection-modal-contents.tsx";
|
||||||
|
|
||||||
|
@customElement("add-selection-button")
|
||||||
|
export class AddSelectionButton extends LitElement {
|
||||||
|
@property({ attribute: true })
|
||||||
|
columns = "";
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private _active = false;
|
||||||
|
|
||||||
|
private _labelInputRef = createRef<HTMLInputElement>();
|
||||||
|
|
||||||
|
private _nameInputRef = createRef<HTMLInputElement>();
|
||||||
|
|
||||||
|
private _typePopoverRef = createRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
static override styles = css`
|
||||||
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
--shadow: 0 0.5rem 0.5rem #3333;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.main {
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-weight: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.th {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
border: dashed 1px #ccc;
|
||||||
|
border-left: none;
|
||||||
|
border-top: none;
|
||||||
|
font-family: "Funnel Sans";
|
||||||
|
background: #0001;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input#name-input {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#type-config-button {
|
||||||
|
anchor-name: --type-config-button;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-popover:popover-open {
|
||||||
|
box-sizing: border-box;
|
||||||
|
inset: unset;
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 1rem;
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
width: 20rem;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
filter: drop-shadow(var(--shadow));
|
||||||
|
}
|
||||||
|
|
||||||
|
#type-popover {
|
||||||
|
position-anchor: --type-config-button;
|
||||||
|
position-area: bottom;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
protected override updated() {
|
||||||
|
if (this._active && this._labelInputRef.value) {
|
||||||
|
this._labelInputRef.value.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _activate() {
|
||||||
|
this._active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleLabelChange(ev: InputEvent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private _showTypePopover() {
|
||||||
|
this._typePopoverRef.value?.showPopover();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override render() {
|
||||||
|
if (this._active) {
|
||||||
|
return html`
|
||||||
|
<div class="th">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
${ref(
|
||||||
|
this._labelInputRef,
|
||||||
|
)}
|
||||||
|
id="label-input"
|
||||||
|
name="name-input"
|
||||||
|
@change="${this._handleLabelChange}"
|
||||||
|
>
|
||||||
|
<button type="button" id="type-config-button" @click="${this
|
||||||
|
._showTypePopover}">
|
||||||
|
abc
|
||||||
|
</button>
|
||||||
|
<button type="submit">Create</button>
|
||||||
|
</div>
|
||||||
|
<div ${ref(
|
||||||
|
this._typePopoverRef,
|
||||||
|
)} id="type-popover" class="config-popover" popover="auto">
|
||||||
|
<input type="text" ${ref(this._nameInputRef)} name="name">
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<button type="button" class="main" @click="${this._activate}">+</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
import { css, html, LitElement } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators.js";
|
|
||||||
import { createRef, type Ref, ref } from "lit/directives/ref.js";
|
|
||||||
|
|
||||||
import "./add-selection-modal-contents.tsx";
|
|
||||||
|
|
||||||
@customElement("add-selection-button")
|
|
||||||
export class AddSelectionButton extends LitElement {
|
|
||||||
@property({ attribute: true })
|
|
||||||
columns = "";
|
|
||||||
|
|
||||||
private _dialogRef: Ref<HTMLDialogElement> = createRef();
|
|
||||||
|
|
||||||
static override styles = css`
|
|
||||||
button.th {
|
|
||||||
appearance: none;
|
|
||||||
border: none;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
font-weight: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
font-family: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog {
|
|
||||||
border: solid 1px #ccc;
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
box-shadow: 0 0.5rem 0.5rem #3333;
|
|
||||||
font-family:
|
|
||||||
"Averia Serif Libre",
|
|
||||||
"Open Sans",
|
|
||||||
"Helvetica Neue",
|
|
||||||
Arial,
|
|
||||||
sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog::backdrop {
|
|
||||||
background: #0001;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
showModal() {
|
|
||||||
this._dialogRef.value?.showModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override render() {
|
|
||||||
return html`
|
|
||||||
<button type="button" class="th" @click="${this.showModal}">+</button>
|
|
||||||
<dialog ${ref(this._dialogRef)} closedby="any">
|
|
||||||
<add-selection-modal-content
|
|
||||||
columns="${this.columns}"
|
|
||||||
></add-selection-modal-content>
|
|
||||||
</dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1
components/src/entrypoints/viewer-components.ts
Normal file
1
components/src/entrypoints/viewer-components.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { AddSelectionButton } from "../add-selection-button.ts";
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export { AddSelectionButton } from "../add-selection-button.tsx";
|
|
||||||
4
glm/.gitignore
vendored
Normal file
4
glm/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.beam
|
||||||
|
*.ez
|
||||||
|
/build
|
||||||
|
erl_crash.dump
|
||||||
24
glm/README.md
Normal file
24
glm/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# glm
|
||||||
|
|
||||||
|
[](https://hex.pm/packages/glm)
|
||||||
|
[](https://hexdocs.pm/glm/)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gleam add glm@1
|
||||||
|
```
|
||||||
|
```gleam
|
||||||
|
import glm
|
||||||
|
|
||||||
|
pub fn main() -> Nil {
|
||||||
|
// TODO: An example of the project in use
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Further documentation can be found at <https://hexdocs.pm/glm>.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
gleam run # Run the project
|
||||||
|
gleam test # Run the tests
|
||||||
|
```
|
||||||
24
glm/gleam.toml
Normal file
24
glm/gleam.toml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
name = "glm"
|
||||||
|
version = "1.0.0"
|
||||||
|
target = "javascript"
|
||||||
|
|
||||||
|
# Fill out these fields if you intend to generate HTML documentation or publish
|
||||||
|
# your project to the Hex package manager.
|
||||||
|
#
|
||||||
|
# description = ""
|
||||||
|
# licences = ["Apache-2.0"]
|
||||||
|
# repository = { type = "github", user = "", repo = "" }
|
||||||
|
# links = [{ title = "Website", href = "" }]
|
||||||
|
#
|
||||||
|
# For a full reference of all the available options, you can have a look at
|
||||||
|
# https://gleam.run/writing-gleam/gleam-toml/.
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
|
||||||
|
lustre = ">= 5.2.1 and < 6.0.0"
|
||||||
|
gleam_json = ">= 3.0.2 and < 4.0.0"
|
||||||
|
gleam_regexp = ">= 1.1.1 and < 2.0.0"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
gleeunit = ">= 1.0.0 and < 2.0.0"
|
||||||
|
lustre_dev_tools = ">= 1.9.0 and < 2.0.0"
|
||||||
51
glm/manifest.toml
Normal file
51
glm/manifest.toml
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# This file was generated by Gleam
|
||||||
|
# You typically do not need to edit this file
|
||||||
|
|
||||||
|
packages = [
|
||||||
|
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
|
||||||
|
{ name = "directories", version = "1.2.0", build_tools = ["gleam"], requirements = ["envoy", "gleam_stdlib", "platform", "simplifile"], otp_app = "directories", source = "hex", outer_checksum = "D13090CFCDF6759B87217E8DDD73A75903A700148A82C1D33799F333E249BF9E" },
|
||||||
|
{ name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" },
|
||||||
|
{ name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
|
||||||
|
{ name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
|
||||||
|
{ name = "fs", version = "11.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "DD00A61D89EAC01D16D3FC51D5B0EB5F0722EF8E3C1A3A547CD086957F3260A9" },
|
||||||
|
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
|
||||||
|
{ name = "gleam_community_colour", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "E34DD2C896AC3792151EDA939DA435FF3B69922F33415ED3C4406C932FBE9634" },
|
||||||
|
{ name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
|
||||||
|
{ name = "gleam_deque", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_deque", source = "hex", outer_checksum = "64D77068931338CF0D0CB5D37522C3E3CCA7CB7D6C5BACB41648B519CC0133C7" },
|
||||||
|
{ name = "gleam_erlang", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "F91CE62A2D011FA13341F3723DB7DB118541AAA5FE7311BD2716D018F01EF9E3" },
|
||||||
|
{ name = "gleam_http", version = "4.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "DB25DFC8530B64B77105405B80686541A0D96F7E2D83D807D6B2155FB9A8B1B8" },
|
||||||
|
{ name = "gleam_httpc", version = "4.1.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "C670EBD46FC1472AD5F1F74F1D3938D1D0AC1C7531895ED1D4DDCB6F07279F43" },
|
||||||
|
{ name = "gleam_json", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "874FA3C3BB6E22DD2BB111966BD40B3759E9094E05257899A7C08F5DE77EC049" },
|
||||||
|
{ name = "gleam_otp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "7020E652D18F9ABAC9C877270B14160519FA0856EE80126231C505D719AD68DA" },
|
||||||
|
{ name = "gleam_package_interface", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "8F2D19DE9876D9401BB0626260958A6B1580BB233489C32831FE74CE0ACAE8B4" },
|
||||||
|
{ name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
|
||||||
|
{ name = "gleam_stdlib", version = "0.62.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "DC8872BC0B8550F6E22F0F698CFE7F1E4BDA7312FDEB40D6C3F44C5B706C8310" },
|
||||||
|
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
|
||||||
|
{ name = "gleeunit", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "63022D81C12C17B7F1A60E029964E830A4CBD846BBC6740004FC1F1031AE0326" },
|
||||||
|
{ name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" },
|
||||||
|
{ name = "glisten", version = "8.0.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib", "logging", "telemetry"], otp_app = "glisten", source = "hex", outer_checksum = "534BB27C71FB9E506345A767C0D76B17A9E9199934340C975DC003C710E3692D" },
|
||||||
|
{ name = "gramps", version = "3.0.3", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_erlang", "gleam_http", "gleam_stdlib"], otp_app = "gramps", source = "hex", outer_checksum = "75F0F20C867A6217CBB632A7E563568D6A6366B850815041E8E0B4F179681E53" },
|
||||||
|
{ name = "houdini", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "houdini", source = "hex", outer_checksum = "5BA517E5179F132F0471CB314F27FE210A10407387DA1EA4F6FD084F74469FC2" },
|
||||||
|
{ name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" },
|
||||||
|
{ name = "logging", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "1098FBF10B54B44C2C7FDF0B01C1253CAFACDACABEFB4B0D027803246753E06D" },
|
||||||
|
{ name = "lustre", version = "5.2.1", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "DCD121F8E6B7E179B27D9A8AEB6C828D8380E26DF2E16D078511EDAD1CA9F2A7" },
|
||||||
|
{ name = "lustre_dev_tools", version = "1.9.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "fs", "gleam_community_ansi", "gleam_crypto", "gleam_deque", "gleam_erlang", "gleam_http", "gleam_httpc", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_regexp", "gleam_stdlib", "glint", "glisten", "mist", "repeatedly", "simplifile", "term_size", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "2132E6B2B7E89ED87C138FFE1F2CD70D859258D67222F26B5793CDACE9B07D75" },
|
||||||
|
{ name = "marceau", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "2D1C27504BEF45005F5DFB18591F8610FB4BFA91744878210BDC464412EC44E9" },
|
||||||
|
{ name = "mist", version = "5.0.2", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "gleam_yielder", "glisten", "gramps", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "0716CE491EA13E1AA1EFEC4B427593F8EB2B953B6EBDEBE41F15BE3D06A22918" },
|
||||||
|
{ name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" },
|
||||||
|
{ name = "repeatedly", version = "2.1.2", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "93AE1938DDE0DC0F7034F32C1BF0D4E89ACEBA82198A1FE21F604E849DA5F589" },
|
||||||
|
{ name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
|
||||||
|
{ name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" },
|
||||||
|
{ name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" },
|
||||||
|
{ name = "term_size", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "term_size", source = "hex", outer_checksum = "D00BD2BC8FB3EBB7E6AE076F3F1FF2AC9D5ED1805F004D0896C784D06C6645F1" },
|
||||||
|
{ name = "tom", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0910EE688A713994515ACAF1F486A4F05752E585B9E3209D8F35A85B234C2719" },
|
||||||
|
{ name = "wisp", version = "1.8.0", build_tools = ["gleam"], requirements = ["directories", "exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "0FE9049AFFB7C8D5FC0B154EEE2704806F4D51B97F44925D69349B3F4F192957" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[requirements]
|
||||||
|
gleam_json = { version = ">= 3.0.2 and < 4.0.0" }
|
||||||
|
gleam_regexp = { version = ">= 1.1.1 and < 2.0.0" }
|
||||||
|
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
|
||||||
|
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
|
||||||
|
lustre = { version = ">= 5.2.1 and < 6.0.0" }
|
||||||
|
lustre_dev_tools = { version = ">= 1.9.0 and < 2.0.0" }
|
||||||
10
glm/src/field_adder.ffi.mjs
Normal file
10
glm/src/field_adder.ffi.mjs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Error, Ok } from "./gleam.mjs";
|
||||||
|
|
||||||
|
export function focusElement(selector, root) {
|
||||||
|
const element = root.querySelector(selector);
|
||||||
|
if (element) {
|
||||||
|
element.focus();
|
||||||
|
return new Ok(undefined);
|
||||||
|
}
|
||||||
|
return new Error(undefined);
|
||||||
|
}
|
||||||
239
glm/src/field_adder.gleam
Normal file
239
glm/src/field_adder.gleam
Normal file
|
|
@ -0,0 +1,239 @@
|
||||||
|
import gleam/dynamic.{type Dynamic}
|
||||||
|
import gleam/dynamic/decode
|
||||||
|
import gleam/json
|
||||||
|
import gleam/regexp
|
||||||
|
import gleam/result
|
||||||
|
import gleam/string
|
||||||
|
import lustre.{type App}
|
||||||
|
import lustre/attribute as attr
|
||||||
|
import lustre/component
|
||||||
|
import lustre/effect.{type Effect}
|
||||||
|
import lustre/element.{type Element}
|
||||||
|
import lustre/element/html
|
||||||
|
import lustre/event
|
||||||
|
|
||||||
|
pub const name: String = "field-adder"
|
||||||
|
|
||||||
|
pub fn component() -> App(Nil, Model, Msg) {
|
||||||
|
lustre.component(init, update, view, [
|
||||||
|
component.on_attribute_change("columns", fn(value) {
|
||||||
|
Ok(
|
||||||
|
json.parse(from: value, using: decode.list(of: decode.string))
|
||||||
|
|> result.unwrap([])
|
||||||
|
|> ParentChangedColumns,
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
component.on_attribute_change("root-path", fn(value) {
|
||||||
|
ParentChangedRootPath(value) |> Ok
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Model {
|
||||||
|
Model(
|
||||||
|
columns: List(String),
|
||||||
|
root_path: String,
|
||||||
|
expanded: Bool,
|
||||||
|
label_value: String,
|
||||||
|
name_value: String,
|
||||||
|
name_customized: Bool,
|
||||||
|
field_type: String,
|
||||||
|
submitting: Bool,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(_) -> #(Model, Effect(Msg)) {
|
||||||
|
#(
|
||||||
|
Model(
|
||||||
|
columns: [],
|
||||||
|
root_path: "",
|
||||||
|
expanded: False,
|
||||||
|
label_value: "",
|
||||||
|
name_value: "",
|
||||||
|
name_customized: False,
|
||||||
|
field_type: "text",
|
||||||
|
submitting: False,
|
||||||
|
),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Msg {
|
||||||
|
ParentChangedColumns(List(String))
|
||||||
|
ParentChangedRootPath(String)
|
||||||
|
UserClickedCancel
|
||||||
|
UserExpandedComponent
|
||||||
|
UserUpdatedName(String)
|
||||||
|
UserUpdatedLabel(String)
|
||||||
|
UserUpdatedFieldType(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) {
|
||||||
|
case msg {
|
||||||
|
ParentChangedColumns(columns) -> #(Model(..model, columns:), effect.none())
|
||||||
|
ParentChangedRootPath(root_path) -> #(
|
||||||
|
Model(..model, root_path:),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
UserClickedCancel -> #(
|
||||||
|
Model(
|
||||||
|
..model,
|
||||||
|
expanded: False,
|
||||||
|
label_value: "",
|
||||||
|
name_value: "",
|
||||||
|
name_customized: False,
|
||||||
|
field_type: "text",
|
||||||
|
),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
UserExpandedComponent -> #(
|
||||||
|
Model(..model, expanded: True),
|
||||||
|
focus_element("#label-input"),
|
||||||
|
)
|
||||||
|
UserUpdatedName(name_value) -> #(
|
||||||
|
Model(..model, name_value:, name_customized: True),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
UserUpdatedLabel(label_value) -> #(
|
||||||
|
Model(..model, label_value:, name_value: case model.name_customized {
|
||||||
|
True -> model.name_value
|
||||||
|
False -> label_value |> to_idiomatic_column_name
|
||||||
|
}),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
UserUpdatedFieldType(field_type) -> #(
|
||||||
|
Model(..model, field_type:),
|
||||||
|
effect.none(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_idiomatic_column_name(label: String) -> String {
|
||||||
|
let assert Ok(re) = regexp.from_string("[^a-z0-9]")
|
||||||
|
regexp.replace(each: re, in: label |> string.lowercase, with: "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn focus_element(selector: String) -> Effect(Msg) {
|
||||||
|
use _, shadow_root <- effect.before_paint
|
||||||
|
do_focus_element(selector:, in: shadow_root) |> result.unwrap(Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@external(javascript, "./field_adder.ffi.mjs", "focusElement")
|
||||||
|
fn do_focus_element(
|
||||||
|
selector _selector: String,
|
||||||
|
in _root: Dynamic,
|
||||||
|
) -> Result(Nil, Nil) {
|
||||||
|
Error(Nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(model: Model) -> Element(Msg) {
|
||||||
|
element.fragment([
|
||||||
|
html.link([
|
||||||
|
attr.rel("stylesheet"),
|
||||||
|
attr.href(model.root_path <> "/css_dist/field_adder/index.css"),
|
||||||
|
]),
|
||||||
|
case model.expanded {
|
||||||
|
False ->
|
||||||
|
html.button(
|
||||||
|
[
|
||||||
|
attr.type_("button"),
|
||||||
|
attr.class("expander__button"),
|
||||||
|
event.on_click(UserExpandedComponent),
|
||||||
|
],
|
||||||
|
[html.text("+")],
|
||||||
|
)
|
||||||
|
True ->
|
||||||
|
html.div([attr.class("header")], [
|
||||||
|
html.form([attr.method("post"), attr.action("create-column")], [
|
||||||
|
label_input(value: model.label_value, on_input: UserUpdatedLabel),
|
||||||
|
html.button(
|
||||||
|
[attr.type_("button"), attr.popovertarget("config-popover")],
|
||||||
|
[html.text("...")],
|
||||||
|
),
|
||||||
|
config_popover(model),
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
},
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn label_input(
|
||||||
|
value value: String,
|
||||||
|
on_input handle_input: fn(String) -> Msg,
|
||||||
|
) -> Element(Msg) {
|
||||||
|
html.input([
|
||||||
|
attr.type_("text"),
|
||||||
|
attr.id("label-input"),
|
||||||
|
attr.name("label"),
|
||||||
|
attr.class("header__input"),
|
||||||
|
attr.placeholder("My New Column"),
|
||||||
|
attr.value(value),
|
||||||
|
event.on_input(handle_input),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config_popover(model: Model) -> Element(Msg) {
|
||||||
|
html.div(
|
||||||
|
[
|
||||||
|
attr.id("config-popover"),
|
||||||
|
attr.class("config-popover__container"),
|
||||||
|
attr.popover("auto"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
html.h2([attr.class("form-section__heading")], [
|
||||||
|
html.text("Field Details"),
|
||||||
|
]),
|
||||||
|
html.label([attr.class("form-section__label"), attr.for("name-input")], [
|
||||||
|
html.text("SQL-friendly Name"),
|
||||||
|
]),
|
||||||
|
html.input([
|
||||||
|
attr.type_("text"),
|
||||||
|
attr.name("name"),
|
||||||
|
attr.class("form-section__input form-section__input--text"),
|
||||||
|
attr.id("name-input"),
|
||||||
|
attr.value(model.name_value),
|
||||||
|
event.on_input(UserUpdatedName),
|
||||||
|
]),
|
||||||
|
html.label(
|
||||||
|
[attr.for("field-type-select"), attr.class("form-section__label")],
|
||||||
|
[html.text("Data Type")],
|
||||||
|
),
|
||||||
|
html.select(
|
||||||
|
[
|
||||||
|
attr.type_("text"),
|
||||||
|
attr.name("field_type"),
|
||||||
|
attr.class("form-section__input"),
|
||||||
|
attr.id("field-type-select"),
|
||||||
|
event.on_change(UserUpdatedFieldType),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
html.option(
|
||||||
|
[attr.value("text"), attr.checked(model.field_type == "text")],
|
||||||
|
"Text",
|
||||||
|
),
|
||||||
|
html.option(
|
||||||
|
[attr.value("decimal"), attr.checked(model.field_type == "decimal")],
|
||||||
|
"Decimal",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
html.div([attr.class("form-buttons")], [
|
||||||
|
html.button(
|
||||||
|
[
|
||||||
|
attr.type_("button"),
|
||||||
|
attr.class("form-buttons__button form-buttons__button--cancel"),
|
||||||
|
event.on_click(UserClickedCancel),
|
||||||
|
],
|
||||||
|
[html.text("Cancel")],
|
||||||
|
),
|
||||||
|
html.button(
|
||||||
|
[
|
||||||
|
attr.type_("submit"),
|
||||||
|
attr.class("form-buttons__button form-buttons__button--submit"),
|
||||||
|
],
|
||||||
|
[html.text("Create")],
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
6
glm/src/glm.gleam.bak
Normal file
6
glm/src/glm.gleam.bak
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
import field_adder
|
||||||
|
|
||||||
|
pub fn main() -> Nil {
|
||||||
|
let assert Ok(_) = field_adder.register()
|
||||||
|
Nil
|
||||||
|
}
|
||||||
|
|
@ -107,6 +107,46 @@ pub fn new_router(state: AppState) -> Router<()> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.nest_service(
|
||||||
|
"/glm_dist",
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
CACHE_CONTROL,
|
||||||
|
// FIXME: restore production value
|
||||||
|
// HeaderValue::from_static("max-age=21600, stale-while-revalidate=86400"),
|
||||||
|
HeaderValue::from_static("no-cache"),
|
||||||
|
))
|
||||||
|
.service(
|
||||||
|
ServeDir::new("glm_dist").not_found_service(
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
CACHE_CONTROL,
|
||||||
|
HeaderValue::from_static("no-cache"),
|
||||||
|
))
|
||||||
|
.service(ServeFile::new("static/_404.html")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.nest_service(
|
||||||
|
"/css_dist",
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
CACHE_CONTROL,
|
||||||
|
// FIXME: restore production value
|
||||||
|
// HeaderValue::from_static("max-age=21600, stale-while-revalidate=86400"),
|
||||||
|
HeaderValue::from_static("no-cache"),
|
||||||
|
))
|
||||||
|
.service(
|
||||||
|
ServeDir::new("css_dist").not_found_service(
|
||||||
|
ServiceBuilder::new()
|
||||||
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
CACHE_CONTROL,
|
||||||
|
HeaderValue::from_static("no-cache"),
|
||||||
|
))
|
||||||
|
.service(ServeFile::new("static/_404.html")),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
.fallback_service(
|
.fallback_service(
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
.layer(SetResponseHeaderLayer::if_not_present(
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
{% include "meta_tags.html" %}
|
{% include "meta_tags.html" %}
|
||||||
<link rel="stylesheet" href="{{ settings.root_path }}/modern-normalize.min.css">
|
<link rel="stylesheet" href="{{ settings.root_path }}/modern-normalize.min.css">
|
||||||
<link rel="stylesheet" href="{{ settings.root_path }}/main.css">
|
<link rel="stylesheet" href="{{ settings.root_path }}/main.css">
|
||||||
|
<link rel="stylesheet" href="{{ settings.root_path }}/css_dist/main.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% block main %}{% endblock main %}
|
{% block main %}{% endblock main %}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<script type="module" src="{{ settings.root_path }}/js_dist/lens-controls.mjs"></script>
|
<script type="module" src="{{ settings.root_path }}/js_dist/lens-controls.mjs"></script>
|
||||||
<script type="module" src="{{ settings.root_path }}/js_dist/viewer-components.mjs"></script>
|
<script type="module" src="{{ settings.root_path }}/js_dist/viewer-components.mjs"></script>
|
||||||
<script type="module" src="{{ settings.root_path }}/js_dist/viewer-controller.mjs"></script>
|
<script type="module" src="{{ settings.root_path }}/js_dist/viewer-controller.mjs"></script>
|
||||||
|
<script type="module" src="{{ settings.root_path }}/glm_dist/field_adder.mjs"></script>
|
||||||
<link rel="stylesheet" href="{{ settings.root_path }}/viewer.css">
|
<link rel="stylesheet" href="{{ settings.root_path }}/viewer.css">
|
||||||
<table class="viewer">
|
<table class="viewer">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
@ -14,8 +15,8 @@
|
||||||
<div class="padded-cell">{{ field.label.clone().unwrap_or(field.name.clone()) }}</div>
|
<div class="padded-cell">{{ field.label.clone().unwrap_or(field.name.clone()) }}</div>
|
||||||
</th>
|
</th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<th>
|
<th class="column-adder">
|
||||||
<add-selection-button columns="{{ all_columns | json }}"></add-selection-button>
|
<field-adder root-path="{{ settings.root_path }}" columns="{{ all_columns | json }}"></field-adder>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
|
||||||
13
mise.toml
13
mise.toml
|
|
@ -1,8 +1,12 @@
|
||||||
[tools]
|
[tools]
|
||||||
deno = "latest"
|
deno = "latest"
|
||||||
|
erlang = "latest"
|
||||||
|
gleam = "latest"
|
||||||
jujutsu = "latest"
|
jujutsu = "latest"
|
||||||
|
rebar = "latest"
|
||||||
rust = { version = "1.88.0", components = "rust-analyzer,clippy" }
|
rust = { version = "1.88.0", components = "rust-analyzer,clippy" }
|
||||||
watchexec = "latest"
|
watchexec = "latest"
|
||||||
|
"github:sass/dart-sass" = "1.89.2"
|
||||||
|
|
||||||
[tasks.postgres]
|
[tasks.postgres]
|
||||||
run = "docker run --rm -it -e POSTGRES_PASSWORD=guest -v './pgdata:/var/lib/postgresql/data' -p 127.0.0.1:5432:5432 postgres:17"
|
run = "docker run --rm -it -e POSTGRES_PASSWORD=guest -v './pgdata:/var/lib/postgresql/data' -p 127.0.0.1:5432:5432 postgres:17"
|
||||||
|
|
@ -17,6 +21,15 @@ run = "deno task build"
|
||||||
dir = "./components"
|
dir = "./components"
|
||||||
sources = ["**/*.ts"]
|
sources = ["**/*.ts"]
|
||||||
|
|
||||||
|
[tasks.lustre]
|
||||||
|
run = "gleam run -m lustre/dev build component field_adder --outdir=../glm_dist"
|
||||||
|
dir = "./glm"
|
||||||
|
sources = ["**/*.gleam"]
|
||||||
|
|
||||||
|
[tasks.sass]
|
||||||
|
run = "sass sass/:css_dist/"
|
||||||
|
sources = ["sass/**/*.scss"]
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
RUST_LOG = "debug"
|
RUST_LOG = "debug"
|
||||||
RUST_BACKTRACE = "1"
|
RUST_BACKTRACE = "1"
|
||||||
|
|
|
||||||
57
sass/_forms.scss
Normal file
57
sass/_forms.scss
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
@use 'globals';
|
||||||
|
|
||||||
|
$section-gap: 1.5rem;
|
||||||
|
$label-gap: 0.5rem;
|
||||||
|
$button-gap: 0.25rem;
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
&__heading {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: $section-gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
display: block;
|
||||||
|
margin-top: $label-gap;
|
||||||
|
font-family: globals.$font-family-data;
|
||||||
|
|
||||||
|
&--text {
|
||||||
|
@include globals.rounded;
|
||||||
|
border: globals.$default-border;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-buttons {
|
||||||
|
display: flex;
|
||||||
|
margin-top: $section-gap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
margin: 0 $button-gap;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--cancel {
|
||||||
|
@include globals.button-clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--submit {
|
||||||
|
@include globals.button-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
sass/_globals.scss
Normal file
54
sass/_globals.scss
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
@use 'sass:color';
|
||||||
|
|
||||||
|
$button-primary-background: #07f;
|
||||||
|
$button-primary-color: #fff;
|
||||||
|
$default-border: solid 1px #ccc;
|
||||||
|
$font-family-default: 'Averia Serif Libre', 'Open Sans', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
$font-family-data: 'Funnel Sans', 'Open Sans', 'Helvetica Neue', Arial, sans-serif;
|
||||||
|
$popover-border: $default-border;
|
||||||
|
$popover-shadow: 0 0.5rem 0.5rem #3333;
|
||||||
|
|
||||||
|
@mixin reset-button {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button-base {
|
||||||
|
@include reset-button;
|
||||||
|
@include rounded;
|
||||||
|
font-family: $font-family-default;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
transition: background 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button-primary {
|
||||||
|
@include button-base;
|
||||||
|
background: $button-primary-background;
|
||||||
|
color: $button-primary-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: color.scale($button-primary-background, $lightness: -10%, $space: oklch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin button-clear {
|
||||||
|
@include button-base;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #0002;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin rounded-sm {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin rounded {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
16
sass/_viewer-shared.scss
Normal file
16
sass/_viewer-shared.scss
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
@use 'globals';
|
||||||
|
|
||||||
|
@mixin th {
|
||||||
|
border: globals.$default-border;
|
||||||
|
border-top: none;
|
||||||
|
font-family: 'Funnel Sans';
|
||||||
|
font-weight: bolder;
|
||||||
|
background: #0001;
|
||||||
|
height: 100%; /* css hack to make percentage based cell heights work */
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
sass/field_adder/_styles.scss
Normal file
48
sass/field_adder/_styles.scss
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
@use '../globals';
|
||||||
|
@use '../viewer-shared';
|
||||||
|
|
||||||
|
field-adder {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&::part(expander) {
|
||||||
|
@include globals.reset-button;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::part(th-lookalike) {
|
||||||
|
@include viewer-shared.th;
|
||||||
|
border-right-style: dashed;
|
||||||
|
border-bottom-style: dashed;
|
||||||
|
border-left: none;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::part(label-input) {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::part(config-popover) {
|
||||||
|
@include globals.rounded-sm;
|
||||||
|
position: fixed;
|
||||||
|
inset: unset;
|
||||||
|
margin: 0;
|
||||||
|
width: 20rem;
|
||||||
|
padding: 1rem;
|
||||||
|
font-weight: normal;
|
||||||
|
border: globals.$popover-border;
|
||||||
|
filter: drop-shadow(globals.$popover-shadow);
|
||||||
|
|
||||||
|
&:popover-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::part(form-section-header) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
sass/field_adder/index.scss
Normal file
48
sass/field_adder/index.scss
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
@use '../globals';
|
||||||
|
@use '../forms';
|
||||||
|
@use '../viewer-shared';
|
||||||
|
|
||||||
|
:host {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expander__button {
|
||||||
|
@include globals.reset-button;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
@include viewer-shared.th;
|
||||||
|
border-right-style: dashed;
|
||||||
|
border-bottom-style: dashed;
|
||||||
|
border-left: none;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-popover {
|
||||||
|
&__container {
|
||||||
|
@include globals.rounded;
|
||||||
|
font-family: globals.$font-family-default;
|
||||||
|
position: fixed;
|
||||||
|
inset: unset;
|
||||||
|
margin: 0;
|
||||||
|
width: 20rem;
|
||||||
|
padding: 1rem;
|
||||||
|
font-weight: normal;
|
||||||
|
border: globals.$popover-border;
|
||||||
|
filter: drop-shadow(globals.$popover-shadow);
|
||||||
|
|
||||||
|
&:popover-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
sass/main.scss
Normal file
1
sass/main.scss
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
|
||||||
18
static/css/field_adder.css
Normal file
18
static/css/field_adder.css
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
field-adder {
|
||||||
|
--popover-border: solid 1px #ccc;
|
||||||
|
--popover-shadow: 0 0.5rem 0.5rem #3333;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
& button.expander {
|
||||||
|
appearance: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-weight: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,18 @@ button, input[type="submit"] {
|
||||||
src: url("./averia_serif_libre/averia_serif_libre_regular.ttf");
|
src: url("./averia_serif_libre/averia_serif_libre_regular.ttf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Averia Serif Libre";
|
||||||
|
src: url("./averia_serif_libre/averia_serif_libre_bold.ttf");
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Averia Serif Libre";
|
||||||
|
src: url("./averia_serif_libre/averia_serif_libre_light.ttf");
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "Funnel Sans";
|
font-family: "Funnel Sans";
|
||||||
src: url("./funnel_sans/funnel_sans_variable.ttf");
|
src: url("./funnel_sans/funnel_sans_variable.ttf");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
table.viewer {
|
table.viewer {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
|
height: 1px; /* css hack to make percentage based cell heights work */
|
||||||
}
|
}
|
||||||
|
|
||||||
table.viewer > thead > tr > th {
|
table.viewer > thead > tr > th {
|
||||||
|
|
@ -7,10 +8,19 @@ table.viewer > thead > tr > th {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
font-family: "Funnel Sans";
|
font-family: "Funnel Sans";
|
||||||
background: #0001;
|
background: #0001;
|
||||||
|
height: 100%; /* css hack to make percentage based cell heights work */
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.column-adder {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table.viewer .padded-cell {
|
table.viewer .padded-cell {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue