Changes
16 changed files (+720/-175)
-
-
@@ -35,6 +35,7 @@ compile.addElmSourceFile(b.path("src/Parameters/Key.elm"));compile.addElmSourceFile(b.path("src/Parameters/Parser.elm")); compile.addElmSourceFile(b.path("src/Preferences.elm")); compile.addElmSourceFile(b.path("src/Preferences/App.elm")); compile.addElmSourceFile(b.path("src/QueryHealer.elm")); compile.addElmSourceFile(b.path("src/Template.elm")); compile.addElmSourceFile(b.path("src/Template/Cuts.elm")); compile.addElmSourceFile(b.path("src/Template/InfoArea.elm"));
-
-
-
@@ -13,7 +13,8 @@ "elm/json": "1.1.4","elm/svg": "1.0.1", "elm/time": "1.0.0", "elm/url": "1.0.0", "pablohirafuji/elm-qrcode": "4.0.2" "pablohirafuji/elm-qrcode": "4.0.2", "turboMaCk/any-dict": "3.0.0" }, "indirect": { "avh4/elm-color": "1.0.0",
-
-
-
@@ -16,3 +16,8 @@slot : String -> Attribute msg slot name = attribute "slot" name role : String -> Attribute msg role name = attribute "role" name
-
-
-
@@ -18,8 +18,10 @@ import Json.Decodeimport Parameters import Parameters.App import Parameters.Parser import Platform.Cmd as Cmd import Preferences exposing (FieldHighlight(..)) import Preferences.App import QueryHealer import Template exposing (template) import Url exposing (Url) import Url.SearchParams
-
@@ -53,33 +55,46 @@type alias Model = { url : Url , key : Key , parameters : Parameters.App.Model , parameters : Result QueryHealer.Model Parameters.App.Model , preferences : Preferences.App.Model } parseParameters : Url -> Key -> ( Result QueryHealer.Model Parameters.App.Model, Cmd Msg ) parseParameters url key = case Maybe.map Url.SearchParams.parse url.query of Just dict -> case Parameters.Parser.parse dict of Ok params -> let ( model, cmd ) = Parameters.App.init url key params in ( Ok model, Cmd.map ParametersMsg cmd ) Err errors -> ( Err (QueryHealer.init url errors), Cmd.none ) Nothing -> let ( model, cmd ) = Parameters.App.init url key Parameters.default in ( Ok model, Cmd.map ParametersMsg cmd ) init : Flags -> Url -> Key -> ( Model, Cmd Msg ) init flags url key = let parameters = case Maybe.map Url.SearchParams.parse url.query of Just dict -> -- TODO: Handle and present errors to a user Parameters.Parser.parse dict |> Result.withDefault Parameters.default Nothing -> Parameters.default ( parametersModel, parametersCmd ) = Parameters.App.init url key parameters ( parameters, parametersCmd ) = parseParameters url key in ( { url = url , key = key , parameters = parametersModel , parameters = parameters , preferences = Preferences.App.init flags.preferences } , Cmd.map ParametersMsg parametersCmd , parametersCmd )
-
@@ -91,6 +106,7 @@ type Msg= NoOp | ParametersMsg Parameters.App.Msg | PreferencesMsg Preferences.App.Msg | QueryHealerMsg QueryHealer.Msg | UrlRequested Browser.UrlRequest | UrlChanged Url
-
@@ -102,9 +118,24 @@ NoOp ->( model, Cmd.none ) ParametersMsg subMsg -> Parameters.App.update subMsg model.parameters |> Tuple.mapFirst (\p -> { model | parameters = p }) |> Tuple.mapSecond (Cmd.map ParametersMsg) case model.parameters of Ok subModel -> Parameters.App.update subMsg subModel |> Tuple.mapFirst (\p -> { model | parameters = Ok p }) |> Tuple.mapSecond (Cmd.map ParametersMsg) Err _ -> ( model, Cmd.none ) QueryHealerMsg subMsg -> case model.parameters of Err subModel -> QueryHealer.update subMsg subModel |> Tuple.mapFirst (\p -> { model | parameters = Err p }) |> Tuple.mapSecond (Cmd.map QueryHealerMsg) Ok _ -> ( model, Cmd.none ) PreferencesMsg subMsg -> Preferences.App.update subMsg model.preferences
-
@@ -122,7 +153,16 @@ UrlRequested (Browser.External href) ->( model, Browser.Navigation.load href ) UrlChanged url -> ( { model | url = url }, Cmd.none ) case model.parameters of Ok _ -> ( { model | url = url }, Cmd.none ) Err _ -> let ( parameters, parametersCmd ) = parseParameters url model.key in ( { model | url = url, parameters = parameters }, parametersCmd )
-
@@ -131,123 +171,130 @@view : Model -> Browser.Document Msg view model = let highlighting = case model.preferences.preferences.fieldHighlight of HighlightOnPreview -> model.parameters.highlighting case model.parameters of Ok parameters -> let highlighting = case model.preferences.preferences.fieldHighlight of HighlightOnPreview -> parameters.highlighting DoNotHighlight -> Nothing in { title = "" , body = [ node "x-app-layout" [] [ node "x-preview" [ slot "preview" , attribute "print-theme" (case model.parameters.parameters.rendering.colorSchema of Parameters.BlackOnWhite -> "black-on-white" DoNotHighlight -> Nothing in { title = "" , body = [ node "x-app-layout" [] [ node "x-preview" [ slot "preview" , attribute "print-theme" (case parameters.parameters.rendering.colorSchema of Parameters.BlackOnWhite -> "black-on-white" Parameters.WhiteOnBlack -> "white-on-black" ) , attribute "preview-theme" (case model.preferences.preferences.previewTheme of Preferences.SystemTheme -> "system" Parameters.WhiteOnBlack -> "white-on-black" ) , attribute "preview-theme" (case model.preferences.preferences.previewTheme of Preferences.SystemTheme -> "system" Preferences.PrintTheme -> "print" ) ] [ template model.url model.parameters.parameters highlighting [] ] , node "x-panel" [ slot "parameters" ] [ node "x-parameters" [] (node "x-field-group" [] [ span [ slot "title" ] [ text "About" ] , node "x-field" Preferences.PrintTheme -> "print" ) ] [ template model.url parameters.parameters highlighting [] [ span [ slot "title" ] [ text "This Software" ] , p [ slot "description" ] [ text "This application lets you build a leather craft template for basic watch straps." ] ] , node "x-field" [] [ span [ slot "title" ] [ text "The Template" ] , p [ slot "description" ] [ text "The template this application outputs is for two-parts leather wrist warch strap. " , text "It assumes you use a lining leather and a clasp / buckle. " ] , p [ slot "description" ] [ text "The output is provided as-is. How to use the template is completely on your own." ] ] , node "x-field" ] , node "x-panel" [ slot "parameters" ] [ node "x-parameters" [] [ span [ slot "title" ] [ text "Author" ] , p [ slot "description" ] [ text "© Shota FUJI, licensed under the " , a [ href "/licenses/MPL-2.0.txt" ] [ text "Mozilla Public License version 2.0" ] , text "." ] ] ] :: hr [] [] :: (Parameters.App.view model.parameters |> List.map (Html.map ParametersMsg)) ++ hr [] [] :: (Preferences.App.panelItems model.preferences |> List.map (Html.map PreferencesMsg)) ++ [ hr [] [] , node "x-field-group" (node "x-field-group" [] [ span [ slot "title" ] [ text "Legal" ] [ span [ slot "title" ] [ text "About" ] , node "x-field" [] [ span [ slot "title" ] [ text "Third-party Fonts" ] , p [ slot "description" ] [ text "This application uses these fonts:" ] , Html.ul [ slot "description" ] [ Html.li [] [ a [ href "https://github.com/jpt/barlow" ] [ text "Barlow" ] , text " (Copyright 2017 The Barlow Project Authors (https://github.com/jpt/barlow), licensed under " , a [ href "/licenses/OFL-1.1-no-RFN.txt" ] [ text "SIL Open Font License, Version 1.1" ] , text ")" ] , Html.li [] [ a [ href "https://rsms.me/inter/" ] [ text "Inter UI" ] , text " (Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter), licensed under " , a [ href "/licenses/OFL-1.1-no-RFN.txt" ] [ text "SIL Open Font License, Version 1.1" ] , text ")" ] [ span [ slot "title" ] [ text "This Software" ] , p [ slot "description" ] [ text "This application lets you build a leather craft template for basic watch straps." ] ] , node "x-field" [] [ span [ slot "title" ] [ text "Third-party Softwares" ] [ span [ slot "title" ] [ text "The Template" ] , p [ slot "description" ] [ text "The template this application outputs is for two-parts leather wrist warch strap. " , text "It assumes you use a lining leather and a clasp / buckle. " ] , p [ slot "description" ] [ text "See " , a [ href "/licenses/third-party.txt" ] [ text "third-party.txt" ] , text " for list of third-party softwares and its license text." [ text "The output is provided as-is. How to use the template is completely on your own." ] ] , node "x-field" [] [ span [ slot "title" ] [ text "Author" ] , p [ slot "description" ] [ text "© Shota FUJI, licensed under the " , a [ href "/licenses/MPL-2.0.txt" ] [ text "Mozilla Public License version 2.0" ] , text "." ] ] ] ] ) :: hr [] [] :: (Parameters.App.view parameters |> List.map (Html.map ParametersMsg)) ++ hr [] [] :: (Preferences.App.panelItems model.preferences |> List.map (Html.map PreferencesMsg)) ++ [ hr [] [] , node "x-field-group" [] [ span [ slot "title" ] [ text "Legal" ] , node "x-field" [] [ span [ slot "title" ] [ text "Third-party Fonts" ] , p [ slot "description" ] [ text "This application uses these fonts:" ] , Html.ul [ slot "description" ] [ Html.li [] [ a [ href "https://github.com/jpt/barlow" ] [ text "Barlow" ] , text " (Copyright 2017 The Barlow Project Authors (https://github.com/jpt/barlow), licensed under " , a [ href "/licenses/OFL-1.1-no-RFN.txt" ] [ text "SIL Open Font License, Version 1.1" ] , text ")" ] , Html.li [] [ a [ href "https://rsms.me/inter/" ] [ text "Inter UI" ] , text " (Copyright (c) 2016 The Inter Project Authors (https://github.com/rsms/inter), licensed under " , a [ href "/licenses/OFL-1.1-no-RFN.txt" ] [ text "SIL Open Font License, Version 1.1" ] , text ")" ] ] ] , node "x-field" [] [ span [ slot "title" ] [ text "Third-party Softwares" ] , p [ slot "description" ] [ text "See " , a [ href "/licenses/third-party.txt" ] [ text "third-party.txt" ] , text " for list of third-party softwares and its license text." ] ] ] ] ) ] ] ] ] ] } } Err queryHealer -> { title = "Parameters Error | WWSTB" , body = [ QueryHealer.view queryHealer |> Html.map QueryHealerMsg ] }
-
-
-
@@ -11,6 +11,7 @@ module Parameters.App exposing (Model, Msg, init, update, view)import Browser.Navigation import Dict import Dict.Any import Html exposing (hr, input, label, node, p, span, text) import Html.Attributes exposing (..) import Html.Events exposing (onBlur, onFocus, onInput)
-
@@ -62,7 +63,7 @@ ( { fields = fields, errors = case parse fields of Ok _ -> Dict.empty Dict.Any.empty Key.toString Err errors -> errors
-
@@ -103,7 +104,7 @@ case parse fields ofOk newParams -> ( { model | fields = fields , errors = Dict.empty , errors = Dict.Any.empty Key.toString , parameters = newParams } , Task.perform UrlRewriteRequested Time.now
-
@@ -121,7 +122,7 @@ case parse fields ofOk newParams -> ( { model | fields = fields , errors = Dict.empty , errors = Dict.Any.empty Key.toString , parameters = newParams } , Task.perform UrlRewriteRequested Time.now
-
@@ -283,9 +284,6 @@NotAnInt -> [ text "Invalid integer value. This field only accepts integer value." ] NotABool -> [ text "Invalid bool value. Value must be either \"true\" or \"false\"." ] NonexistentVariant str -> [ text ("\"" ++ str ++ "\" is not a valid choice. Did you modify program's source code?") ]
-
@@ -329,7 +327,7 @@ :: value (model.fields |> getKey key |> Maybe.withDefault ""):: onInput (FieldChanged key) :: onFocus (Highlight key) :: onBlur (Unhighlight key) :: ariaInvalid (not (Dict.get (Key.toString key) model.errors == Nothing)) :: ariaInvalid (not (Dict.Any.get key model.errors == Nothing)) :: ariaDescribedBy [ errorId key, descriptionId key ] :: Html.Attributes.disabled disabled :: attrs
-
@@ -344,7 +342,7 @@ text ""] , p [ id (errorId key), slot "error" ] (Dict.get (Key.toString key) model.errors (Dict.Any.get key model.errors |> Maybe.map errorText |> Maybe.withDefault [] )
-
-
-
@@ -7,7 +7,7 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters.Key exposing (Key(..), toString) module Parameters.Key exposing (Key(..), toLabel, toString) type Key
-
@@ -115,3 +115,82 @@ "color-schema"QRCode -> "qrcode" toLabel : Key -> String toLabel key = case key of Version -> "Version" TipStyle -> "Tip style" TipSharpness -> "Tip sharpness" Profile -> "Profile" TaperTo -> "Taper to" ShoulderWidth -> "Shoulder width" PaddingOffset -> "Padding offset" BuckleHoleDistance -> "Center hole at" BuckleHoleAdjustments -> "Adjustments lv." BuckleHoleDiameter -> "Hole diameter" BuckleHoleInterval -> "Hole interval" LongPieceLength -> "Bottom length" LoopStyle -> "Loop style" HasFixedLoop -> "Fixed loop" FixedLoopWidth -> "Fixed loop width" FixedLoopLength -> "Fixed loop length" HasFreeLoop -> "Free loop" FreeLoopWidth -> "Free loop width" FreeLoopLength -> "Free loop length" FreeLoopOverlap -> "Free loop overlap" ShortPieceLength -> "Top length" CanvasMargin -> "Print margin" LineWidth -> "Line width" ColorSchema -> "Color schema" QRCode -> "QR code"
-
-
-
@@ -9,7 +9,7 @@module Parameters.Parser exposing (Error(..), Errors, parse) import Dict exposing (Dict) import Dict.Any exposing (AnyDict) import Length exposing (Length, mm, toMM) import Parameters exposing (ColorSchema(..), LoopStyle(..), Parameters, ParametersDict, getKey, hasKey) import Parameters.Constraints as Constraints exposing (constraints)
-
@@ -23,19 +23,28 @@ | AboveMax Float| NotALength | NotAnInt | NonexistentVariant String | NotABool | UnsupportedParametersVersion String type alias Errors = Dict String Error AnyDict String Key Error mkErrors : List ( Key, Maybe Error ) -> Errors mkErrors list = list |> List.filterMap (\( key, error ) -> Maybe.map (\e -> ( Key.toString key, e )) error) |> Dict.fromList |> List.filterMap (\( key, error ) -> Maybe.map (Tuple.pair key) error) |> Dict.Any.fromList Key.toString unwrapErrors : Result Errors a -> Errors unwrapErrors r = case r of Ok _ -> Dict.Any.empty Key.toString Err errs -> errs getError : Result a b -> Maybe a
-
@@ -245,13 +254,13 @@ ( ( Ok fixed, Ok free ), Ok style ) ->Ok { fixed = fixed, free = free, style = style } ( ( fixed, free ), style ) -> [ getError fixed |> Maybe.withDefault Dict.empty , getError free |> Maybe.withDefault Dict.empty [ unwrapErrors fixed , unwrapErrors free , mkErrors [ ( LoopStyle, getError style ) ] ] |> List.map Dict.toList |> List.map Dict.Any.toList |> List.concat |> Dict.fromList |> Dict.Any.fromList Key.toString |> Err
-
@@ -270,12 +279,12 @@ inOk { base | loops = loops, length = length } ( loops, length ) -> [ getError loops |> Maybe.withDefault Dict.empty [ unwrapErrors loops , mkErrors [ ( ShortPieceLength, getError length ) ] ] |> List.map Dict.toList |> List.map Dict.Any.toList |> List.concat |> Dict.fromList |> Dict.Any.fromList Key.toString |> Err
-
@@ -341,14 +350,13 @@ ( ( Ok buckleHole, Ok length ), Ok tip ) ->Ok { buckleHole = buckleHole, length = length, tip = tip } ( ( buckleHole, length ), tip ) -> [ Just (mkErrors [ ( LongPieceLength, getError length ) ]) , getError buckleHole , getError tip [ mkErrors [ ( LongPieceLength, getError length ) ] , unwrapErrors buckleHole , unwrapErrors tip ] |> List.filterMap identity |> List.map Dict.toList |> List.map Dict.Any.toList |> List.concat |> Dict.fromList |> Dict.Any.fromList Key.toString |> Err
-
@@ -434,14 +442,14 @@ [ mkErrors[ ( ShoulderWidth, getError shoulderWidth ) , ( PaddingOffset, getError paddingOffset ) ] , getError longPiece |> Maybe.withDefault Dict.empty , getError shortPiece |> Maybe.withDefault Dict.empty , getError rendering |> Maybe.withDefault Dict.empty , getError profile |> Maybe.withDefault Dict.empty , unwrapErrors longPiece , unwrapErrors shortPiece , unwrapErrors rendering , unwrapErrors profile ] |> List.map Dict.toList |> List.map Dict.Any.toList |> List.concat |> Dict.fromList |> Dict.Any.fromList Key.toString |> Err Just str ->
-
-
src/QueryHealer.elm (new)
-
@@ -0,0 +1,189 @@-- 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 module QueryHealer exposing (Model, Msg, init, update, view) import Dict exposing (Dict) import Dict.Any import Html exposing (..) import Html.Attributes exposing (..) import Html.LivingStandard exposing (..) import Parameters import Parameters.Key as Key exposing (Key) import Parameters.Parser exposing (Error(..)) import Url exposing (Url) import Url.SearchParams as SearchParams -- MODEL type alias Model = { errors : Parameters.Parser.Errors , searchParams : Dict String String , url : Url } init : Url -> Parameters.Parser.Errors -> Model init url errors = { errors = errors , searchParams = url.query |> Maybe.map SearchParams.parse |> Maybe.withDefault Dict.empty , url = url } -- UPDATE type Msg = NoOp update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of NoOp -> ( model, Cmd.none ) -- VIEW defaults : Dict String String defaults = Dict.union (Parameters.toDict Parameters.default) Parameters.fallbackValues row : Model -> Key -> Error -> Html Msg row { searchParams, url } key error = let setLinkText : String -> Html msg setLinkText value = text ("Set to \"" ++ value ++ "\". ") withDefault = case Parameters.getKey key defaults of Just value -> Dict.insert (Key.toString key) value searchParams Nothing -> searchParams defaultLink = a [ slot "action" , href (Url.toString { url | query = Just (SearchParams.build withDefault) }) ] [ setLinkText (Parameters.getKey key defaults |> Maybe.withDefault "") , text "(default value)" ] in node "x-query-healer" [ role "listitem" ] (span [ slot "key" ] [ text (Key.toLabel key) ] :: (case error of MissingValue -> [ span [ slot "description" ] [ text "Parameter is missing" ] , defaultLink ] BelowMin min -> let withMin = Dict.insert (Key.toString key) (String.fromFloat min) searchParams in [ span [ slot "description" ] [ text "Value is below the minimum." ] , defaultLink , a [ slot "action" , href (Url.toString { url | query = Just (SearchParams.build withMin) }) ] [ setLinkText (String.fromFloat min) , text "(minimum value)" ] ] AboveMax max -> let withMax = Dict.insert (Key.toString key) (String.fromFloat max) searchParams in [ span [ slot "description" ] [ text "Value exceeds the maximum." ] , defaultLink , a [ slot "action" , href (Url.toString { url | query = Just (SearchParams.build withMax) }) ] [ setLinkText (String.fromFloat max) , text "(maximum value)" ] ] NotALength -> [ span [ slot "description" ] [ text "Value is not a valid length value." ] , defaultLink ] NotAnInt -> [ span [ slot "description" ] [ text "Value is not a valid integer." ] , defaultLink ] NonexistentVariant _ -> [ span [ slot "description" ] [ text "Unrecognizable value." ] , defaultLink ] UnsupportedParametersVersion _ -> [ span [ slot "description" ] [ text "Unsupported version." ] , defaultLink , a [ slot "action" , href (Url.toString { url | query = Just (SearchParams.build (Parameters.default |> Parameters.toDict)) }) ] [ text "Use default parameters" ] ] ) ) view : Model -> Html Msg view model = let { url } = model in node "x-error-page" [] [ h1 [ slot "title" ] [ text "Invalid Parameters" ] , p [ slot "description" ] [ text "This URL is not a valid URL for WWSTB." , text " Fix erroneous parameters or start with " , a [ href (Url.toString { url | query = Just (SearchParams.build (Parameters.default |> Parameters.toDict)) }) ] [ text "default parameters" ] , text "." ] , node "x-query-healer-items" [ role "list" ] (model.errors |> Dict.Any.toList |> List.map (\( key, error ) -> row model key error) ) ]
-
-
-
@@ -12,6 +12,7 @@import Html.Attributes exposing (attribute) import Length exposing (toMM) import Parameters exposing (Parameters, Profile(..)) import Parameters.Key as Key exposing (Key(..)) import QRCode import Svg exposing (..) import Svg.Attributes as Attrs exposing (..)
-
@@ -154,7 +155,7 @@ value (String.fromFloat (toMM l) ++ "mm")type alias Parameter msg = { label : Item msg { key : Key , value : Item msg }
-
@@ -165,7 +166,7 @@ columns|> gapped 1 |> aligned Container.Center |> Container.build [ v.label, v.value ] [ label (Key.toLabel v.key), v.value ] parametersRow : List (Item msg) -> Item msg
-
@@ -193,72 +194,72 @@ |> gapped 1.2|> aligned Container.Start |> Container.build ([ [ parameter { label = label "Shoulder width" { key = ShoulderWidth , value = lengthValue params.shoulderWidth } , parameter { label = label "Padding offset" { key = PaddingOffset , value = lengthValue params.paddingOffset } , parameter { label = label "Bottom Length" { key = LongPieceLength , value = lengthValue params.longPiece.length } , parameter { label = label "Top Length" { key = ShortPieceLength , value = lengthValue params.shortPiece.length } ] , case params.profile of Straight -> [ parameter { label = label "Profile" { key = Profile , value = value "Straight" } ] Tapered to -> [ parameter { label = label "Profile" { key = Profile , value = value "Tapered" } , parameter { label = label "Taper to" { key = TaperTo , value = lengthValue to } ] , case params.longPiece.tip of Parameters.Round -> [ parameter { label = label "Tip style" { key = TipStyle , value = value "Round" } ] Parameters.Pointed sharpness -> [ parameter { label = label "Tip style" { key = TipStyle , value = value "Pointed" } , parameter { label = label "Tip sharpness" { key = TipSharpness , value = value (String.fromInt sharpness) } ] , [ parameter { label = label "Center hole at" { key = BuckleHoleDistance , value = lengthValue params.longPiece.buckleHole.distance } , parameter { label = label "Adjustments lv." { key = BuckleHoleAdjustments , value = value (String.fromInt params.longPiece.buckleHole.adjustments) } , parameter { label = label "Hole diameter" { key = BuckleHoleDiameter , value = lengthValue params.longPiece.buckleHole.diameter } , parameter { label = label "Hole interval" { key = BuckleHoleInterval , value = lengthValue params.longPiece.buckleHole.interval } ]
-
@@ -267,7 +268,7 @@ []else [ parameter { label = label "Loop style" { key = LoopStyle , value = value (case params.shortPiece.loops.style of
-
@@ -282,11 +283,11 @@ ], case params.shortPiece.loops.fixed of Just { width, length } -> [ parameter { label = label "Fixed loop width" { key = FixedLoopWidth , value = lengthValue width } , parameter { label = label "Fixed loop length" { key = FixedLoopLength , value = lengthValue length } ]
-
@@ -296,15 +297,15 @@ [], case params.shortPiece.loops.free of Just { width, length, overlap } -> [ parameter { label = label "Free loop width" { key = FreeLoopWidth , value = lengthValue width } , parameter { label = label "Free loop length" { key = FreeLoopLength , value = lengthValue length } , parameter { label = label "Free loop overlap" { key = FreeLoopOverlap , value = lengthValue overlap } ]
-
-
-
@@ -7,19 +7,25 @@ //// SPDX-License-Identifier: MPL-2.0 import { XAppLayout } from "./x-app-layout.js"; import { XErrorPage } from "./x-error-page.js"; import { XField } from "./x-field.js"; import { XFieldGroup } from "./x-field-group.js"; import { XNumberInput } from "./x-number-input.js"; import { XPanel } from "./x-panel.js"; import { XParameters } from "./x-parameters.js"; 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"; customElements.define("x-app-layout", XAppLayout); customElements.define("x-error-page", XErrorPage); customElements.define("x-field", XField); customElements.define("x-field-group", XFieldGroup); customElements.define("x-number-input", XNumberInput); customElements.define("x-panel", XPanel); customElements.define("x-parameters", XParameters); customElements.define("x-preview", XPreview); customElements.define("x-query-healer", XQueryHealer); customElements.define("x-query-healer-items", XQueryHealerItems); customElements.define("x-radio-box", XRadioBox);
-
-
-
@@ -0,0 +1,27 @@/* * 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 { position: fixed; inset: 0; padding: 1rem; display: flex; flex-direction: column; gap: 1.5rem; font-family: "Inter", sans-serif; overflow-y: auto; } .header { display: flex; flex-direction: column; gap: 0.5rem; }
-
-
-
@@ -0,0 +1,38 @@// 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-error-page.css"; export class XErrorPage extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "open", }); const style = document.createElement("style"); style.textContent = css; shadow.appendChild(style); const header = document.createElement("div"); header.classList.add("header"); shadow.appendChild(header); const title = document.createElement("slot"); title.name = "title"; header.appendChild(title); const description = document.createElement("slot"); description.name = "description"; header.appendChild(description); const body = document.createElement("slot"); shadow.appendChild(body); } }
-
-
-
@@ -0,0 +1,15 @@/* * 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; gap: 2rem; }
-
-
-
@@ -0,0 +1,26 @@// 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-query-healer-items.css"; export class XQueryHealerItems extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "open", }); const style = document.createElement("style"); style.textContent = css; shadow.appendChild(style); const slot = document.createElement("slot"); shadow.appendChild(slot); } }
-
-
-
@@ -0,0 +1,65 @@/* * 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; gap: 0.3rem; } ::slotted([slot="key"]) { font-weight: 300; font-size: 1.2rem; } ::slotted([slot="description"]) { font-size: 0.9rem; } .actions { display: flex; gap: 1rem; margin-top: 0.5rem; } ::slotted([slot="action"]) { --_bg: AccentColor; --_fg: AccentColorText; --_darker: color-mix(in oklch, var(--_bg) 90%, oklch(from var(--_bg) 10% c h) 10%); --_lighter: color-mix(in oklch, var(--_bg) 90%, oklch(from var(--_bg) 90% c h) 10%); padding: 0.2em 0.5em; border: 1px solid color-mix(in oklch, var(--_bg) 80%, CanvasText 20%); background-image: linear-gradient(to bottom, var(--_bg) 70%, var(--_darker)); border-radius: 3px; color: var(--_fg); text-decoration: none; @supports not (color: AccentColor) { --_bg: ButtonFace; --_fg: ButtonText; } } ::slotted([slot="action"]:hover) { background-image: linear-gradient(to bottom, var(--_lighter) 70%, var(--_bg)); } @supports not (color: color-mix(in oklch, black 90%, oklch(from black 10% c h) 10%)) { ::slotted([slot="action"]) { background-color: var(--_bg); border-color: ButtonBorder; color: var(--_fg); } ::slotted([slot="action"]:hover) { text-decoration: underline; } }
-
-
-
@@ -0,0 +1,39 @@// 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-query-healer.css"; export class XQueryHealer extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({ mode: "open", }); const style = document.createElement("style"); style.textContent = css; shadow.appendChild(style); const key = document.createElement("slot"); key.name = "key"; shadow.appendChild(key); const description = document.createElement("slot"); description.name = "description"; shadow.appendChild(description); const actions = document.createElement("actions"); actions.classList.add("actions"); shadow.appendChild(actions); const action = document.createElement("slot"); action.name = "action"; actions.appendChild(action); } }
-