Changes
10 changed files (+198/-24)
-
-
@@ -91,6 +91,7 @@_ = dir.addCopyFile(b.path("src/index.html"), "index.html"); _ = dir.addCopyFile(elements_js, "elements.js"); _ = dir.addCopyFile(b.path("src/logo.svg"), "logo.svg"); _ = dir.addCopyDirectory(b.path("src/icons"), ".icons", .{}); _ = dir.addCopyDirectory(b.path("vendor/barlow"), "vendor/barlow", .{}); _ = dir.addCopyDirectory(b.path("vendor/Inter"), "vendor/Inter", .{});
-
-
-
@@ -21,3 +21,13 @@role : String -> Attribute msg role name = attribute "role" name commandFor : String -> Attribute msg commandFor = attribute "commandfor" command : String -> Attribute msg command = attribute "command"
-
-
-
@@ -11,8 +11,8 @@ module Models.PWS01.Main exposing (main)import Browser import Browser.Navigation exposing (Key) import Html exposing (a, hr, node, p, span, text) import Html.Attributes exposing (attribute, href) import Html exposing (a, button, hr, img, node, p, span, text) import Html.Attributes exposing (attribute, href, src) import Html.LivingStandard exposing (..) import Json.Decode import Models.PWS01.Parameters as Parameters
-
@@ -158,7 +158,7 @@ )|> Tuple.mapSecond (Cmd.map PreferencesMsg) UrlRequested (Browser.Internal url) -> if String.endsWith ".txt" url.path then if String.endsWith ".txt" url.path || not (url.path == model.url.path) then ( model, Browser.Navigation.load (Url.toString url) ) else
-
@@ -203,6 +203,7 @@ [ node "x-app-layout"[] [ node "x-preview" [ slot "preview" , Html.Attributes.id "preview" , attribute "print-theme" (case parameters.parameters.rendering.colorSchema of Parameters.BlackOnWhite ->
-
@@ -225,6 +226,29 @@ model.urlparameters.parameters highlighting [] ] , node "x-toolbar" [ slot "toolbar" ] [ a [ href "/" ] [ img [ src "/logo.svg" , Html.Attributes.style "width" "100%" , Html.Attributes.style "height" "100%" ] [] , span [] [ text "Top page" ] ] , button [ commandFor "preview", command "--reset-viewport" ] [ img [ src "/.icons/zoom-reset.svg" , Html.Attributes.style "width" "100%" , Html.Attributes.style "height" "100%" ] [] , span [] [ text "Reset viewport" ] ] ] , node "x-panel" [ slot "parameters" ]
-
-
-
@@ -17,6 +17,7 @@ import { XPreview } from "./x-preview.js";import { XQueryHealer } from "./x-query-healer.js"; import { XQueryHealerItems } from "./x-query-healer-items.js"; import { XRadioBox } from "./x-radio-box.js"; import { XToolbar } from "./x-toolbar.js"; customElements.define("x-app-layout", XAppLayout); customElements.define("x-error-page", XErrorPage);
-
@@ -29,3 +30,4 @@ customElements.define("x-preview", XPreview);customElements.define("x-query-healer", XQueryHealer); customElements.define("x-query-healer-items", XQueryHealerItems); customElements.define("x-radio-box", XRadioBox); customElements.define("x-toolbar", XToolbar);
-
-
-
@@ -13,8 +13,8 @@ position: fixed;inset: 0; display: grid; grid-template-rows: minmax(0, 1fr) 50dvh; grid-template-columns: minmax(0, 1fr); grid-template-areas: "preview" "parameters"; grid-template-columns: 2rem minmax(0, 1fr); grid-template-areas: "toolbar preview" "parameters parameters"; font-family: "Inter", sans-serif; }
-
@@ -22,21 +22,32 @@ ::slotted([slot="preview"]) {grid-area: preview; } ::slotted([slot="parameters"]), ::slotted([slot="toolbar"]) { position: relative; box-shadow: 0 0 3px oklch(0% 0 0deg / 0.2); z-index: 100; } ::slotted([slot="parameters"]) { grid-area: parameters; position: relative; border: none; border-top: 1px solid ButtonFace; } box-shadow: 0 0 3px oklch(0% 0 0deg / 0.2); z-index: 100; ::slotted([slot="toolbar"]) { grid-area: toolbar; align-self: start; border: 1px solid ButtonFace; border-top: none; border-left: none; } @media screen and (min-width: 980px) { :host { grid-template-columns: minmax(0, 1fr) min(20rem, 30vw); grid-template-columns: 2rem minmax(0, 1fr) min(20rem, 30vw); grid-template-rows: minmax(0, 1fr); grid-template-areas: "preview parameters"; grid-template-areas: "toolbar preview parameters"; } ::slotted([slot="parameters"]) {
-
@@ -54,7 +65,7 @@ ::slotted([slot="preview"]) {display: contents; } ::slotted([slot="parameters"]) { ::slotted([slot="parameters"]), ::slotted([slot="toolbar"]) { display: none; } }
-
-
-
@@ -27,5 +27,9 @@const parameters = document.createElement("slot"); parameters.name = "parameters"; shadow.appendChild(parameters); const toolbar = document.createElement("slot"); toolbar.name = "toolbar"; shadow.appendChild(toolbar); } }
-
-
-
@@ -83,22 +83,11 @@ shadow.appendChild(this.#slot);this.#gesturePlane.classList.add("gesture-plane"); shadow.appendChild(this.#gesturePlane); const reset = document.createElement("button"); reset.textContent = "Reset Viewport"; reset.classList.add("reset"); reset.classList.add("hidden"); reset.addEventListener("click", (event) => { this.#dx = 0; this.#dy = 0; this.#scale = 1.0; this.#render(); }); shadow.appendChild(reset); } connectedCallback() { this.addEventListener("command", this.#onCommand); this.#gesturePlane.addEventListener("wheel", this.#onWheel); this.#gesturePlane.addEventListener("touchstart", this.#onTouchChange); this.#gesturePlane.addEventListener("touchend", this.#onTouchChange);
-
@@ -111,6 +100,8 @@ this.#resizeObserver.observe(this.#gesturePlane);} disconnectedCallback() { this.removeEventListener("command", this.#onCommand); this.#gesturePlane.removeEventListener("wheel", this.#onWheel); this.#gesturePlane.removeEventListener("touchstart", this.#onTouchChange); this.#gesturePlane.removeEventListener("touchend", this.#onTouchChange);
-
@@ -118,6 +109,18 @@ this.#gesturePlane.removeEventListener("touchmove", this.#onTouchMove);this.#gesturePlane.removeEventListener("touchcancel", this.#onTouchCancel); this.#resizeObserver.disconnect(); } #onCommand = (event) => { switch (event.command) { case "--reset-viewport": this.#dx = 0; this.#dy = 0; this.#scale = 1.0; this.#render(); return; } }; #onTouchChange = (event) => { switch (event.touches.length) {
-
-
-
@@ -0,0 +1,57 @@/* * Copyright 2026 Shota FUJI * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. * * SPDX-License-Identifier: MPL-2.0 */ :host { display: flex; flex-direction: column; justify-self: start; overflow: hidden; transform: translateX(-100%) translateX(2rem); transition: transform 100ms ease-in-out; } .container { display: flex; flex-direction: column; transform: translateX(100%) translateX(-1.97rem); transition: transform 100ms ease-in-out; } ::slotted(*) { display: grid; grid-template-columns: 1rem minmax(max-content, 1fr); gap: 0.5rem; padding: 0.5rem; border: none; white-space: nowrap; font: inherit; font-size: 0.9rem; background-color: Canvas; color: CanvasText; text-decoration: none; } ::slotted(:hover), ::slotted(:focus-visible) { background-color: SelectedItem; color: SelectedItemText; outline: none; } :host(:focus-within), :host(:hover) { transform: translateX(0); & > .container { transform: translateX(0); } }
-
-
-
@@ -0,0 +1,29 @@// Copyright 2026 Shota FUJI // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. // // SPDX-License-Identifier: MPL-2.0 import css from "./x-toolbar.css"; export class XToolbar extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "open", }); const style = document.createElement("style"); style.textContent = css; shadow.appendChild(style); const container = document.createElement("div"); container.classList.add("container"); shadow.appendChild(container); container.appendChild(document.createElement("slot")); } }
-
-
src/icons/zoom-reset.svg (new)
-
@@ -0,0 +1,33 @@<!-- Copyright 2026 Shota FUJI This source code and the design it expresses are licensed under the Creative Commons Attribution 4.0 International License. SPDX-License-Identifier: CC-BY-4.0 --> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 100 100"> <style> #graphics { fill: black; stroke: black; @media (prefers-color-scheme: dark) { fill: white; stroke: white; --color: white; } } </style> <mask id="mask" mask-type="luminance"> <rect fill="white" x="0" y="0" width="100" height="100" /> <path fill="none" stroke="black" stroke-width="7" d="M70,45 l10,-5 l10,5" /> <path fill="none" stroke="black" stroke-width="7" d="M0,45 l10,5 l10,-5" /> </mask> <g id="graphics" stroke-width="10"> <circle mask="url(#mask)" fill="none" stroke-width="10" cx="47" cy="45" r="35" /> <line fill="none" x1="95" y1="93" x2="70" y2="68" /> <path fill="none" stroke-width="7" d="M67,53 l15,-8 l10,14" /> <path fill="none" stroke-width="7" d="M1,32 l10,14 l15,-8" /> </g> </svg>
-