Changes
16 changed files (+289/-183)
-
-
@@ -9,6 +9,5 @@:8080 { encode root * zig-out try_files {path} /index.html file_server }
-
-
-
@@ -11,6 +11,37 @@const CustomElements = @import("./build/CustomElements.zig"); const Elm = @import("./build/Elm.zig"); const BuildEditorParameters = struct { main: std.Build.LazyPath, files: []const std.Build.LazyPath, optimize: std.builtin.OptimizeMode, }; fn buildEditor(b: *std.Build, params: BuildEditorParameters) Elm { const compile = Elm.init(b, .{ .optimize = params.optimize, }); compile.addMainElmSourceFile(params.main); compile.addElmSourceFile(b.path("src/Html/LivingStandard.elm")); compile.addElmSourceFile(b.path("src/Length.elm")); compile.addElmSourceFile(b.path("src/Preferences.elm")); compile.addElmSourceFile(b.path("src/Preferences/App.elm")); compile.addElmSourceFile(b.path("src/Template/Layout.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Container.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Coordinate.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Item.elm")); compile.addElmSourceFile(b.path("src/Svg/Path.elm")); compile.addElmSourceFile(b.path("src/Url/SearchParams.elm")); for (params.files) |file| { compile.addElmSourceFile(file); } return compile; } pub fn build(b: *std.Build) !void { const optimize = b.standardOptimizeOption(.{}); const custom_elements_compiler = b.option(
-
@@ -19,36 +50,6 @@ "custom-elements-compiler","Path to custom elements compiler binary", ) orelse "custom_elements_compiler"; const elm_main = elm_main: { const compile = Elm.init(b, .{ .optimize = optimize, }); compile.addMainElmSourceFile(b.path("src/Main.elm")); compile.addElmSourceFile(b.path("src/Html/LivingStandard.elm")); compile.addElmSourceFile(b.path("src/Length.elm")); compile.addElmSourceFile(b.path("src/Parameters.elm")); compile.addElmSourceFile(b.path("src/Parameters/App.elm")); compile.addElmSourceFile(b.path("src/Parameters/Constraints.elm")); 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")); compile.addElmSourceFile(b.path("src/Template/Layout.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Container.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Coordinate.elm")); compile.addElmSourceFile(b.path("src/Template/Layout/Item.elm")); compile.addElmSourceFile(b.path("src/Svg/Path.elm")); compile.addElmSourceFile(b.path("src/Url/SearchParams.elm")); break :elm_main compile; }; const elements_js = elements_js: { const compile = CustomElements.init(b, .{ .entrypoint = b.path("src/elements/main.js"),
-
@@ -58,25 +59,45 @@break :elements_js compile.output_js; }; const index_html = index_html: { const html = b.path("src/index.html"); const pws01 = pws01: { const dir = b.addWriteFiles(); break :index_html html; const app = buildEditor(b, .{ .optimize = optimize, .main = b.path("src/Models/PWS01/Main.elm"), .files = &.{ b.path("src/Models/PWS01/Template.elm"), b.path("src/Models/PWS01/Template/Cuts.elm"), b.path("src/Models/PWS01/Template/InfoArea.elm"), b.path("src/Models/PWS01/QueryHealer.elm"), b.path("src/Models/PWS01/Parameters.elm"), b.path("src/Models/PWS01/Parameters/App.elm"), b.path("src/Models/PWS01/Parameters/Constraints.elm"), b.path("src/Models/PWS01/Parameters/Key.elm"), b.path("src/Models/PWS01/Parameters/Parser.elm"), }, }); _ = dir.addCopyFile(b.path("src/pws01/index.html"), "index.html"); _ = dir.addCopyFile(app.output_js, "main.js"); _ = dir.addCopyFile(app.generateThirdPartyLicenseText(), "licenses/third-party.txt"); break :pws01 dir; }; const dist = dist: { const dir = b.addWriteFiles(); _ = dir.addCopyFile(index_html, "index.html"); _ = dir.addCopyFile(elm_main.output_js, "main.js"); _ = dir.addCopyFile(b.path("src/index.html"), "index.html"); _ = dir.addCopyFile(elements_js, "elements.js"); _ = dir.addCopyDirectory(b.path("vendor/barlow"), "vendor/barlow", .{}); _ = dir.addCopyDirectory(b.path("vendor/Inter"), "vendor/Inter", .{}); _ = dir.addCopyFile(elm_main.generateThirdPartyLicenseText(), "licenses/third-party.txt"); _ = dir.addCopyFile(b.path("LICENSES/MPL-2.0.txt"), "licenses/MPL-2.0.txt"); _ = dir.addCopyFile(b.path("LICENSES/OFL-1.1-no-RFN.txt"), "licenses/OFL-1.1-no-RFN.txt"); _ = dir.addCopyDirectory(pws01.getDirectory(), "pws01", .{}); break :dist dir; };
-
-
-
@@ -7,7 +7,7 @@ ---- SPDX-License-Identifier: MPL-2.0 module Main exposing (main) module Models.PWS01.Main exposing (main) import Browser import Browser.Navigation exposing (Key)
-
@@ -15,14 +15,14 @@ import Html exposing (a, hr, node, p, span, text)import Html.Attributes exposing (attribute, href) import Html.LivingStandard exposing (..) import Json.Decode import Parameters import Parameters.App import Parameters.Parser import Models.PWS01.Parameters as Parameters import Models.PWS01.Parameters.App as ParametersApp import Models.PWS01.Parameters.Parser as Parser import Models.PWS01.QueryHealer as QueryHealer import Models.PWS01.Template exposing (template) 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
-
@@ -55,20 +55,20 @@type alias Model = { url : Url , key : Key , parameters : Result QueryHealer.Model Parameters.App.Model , parameters : Result QueryHealer.Model ParametersApp.Model , preferences : Preferences.App.Model } parseParameters : Url -> Key -> Preferences.Preferences -> ( Result QueryHealer.Model Parameters.App.Model, Cmd Msg ) parseParameters : Url -> Key -> Preferences.Preferences -> ( Result QueryHealer.Model ParametersApp.Model, Cmd Msg ) parseParameters url key preferences = case Maybe.map Url.SearchParams.parse url.query of Just dict -> case Parameters.Parser.parse dict of case Parser.parse dict of Ok params -> let ( model, cmd ) = Parameters.App.init url key preferences params ParametersApp.init url key preferences params in ( Ok model, Cmd.map ParametersMsg cmd )
-
@@ -78,7 +78,7 @@Nothing -> let ( model, cmd ) = Parameters.App.init url key preferences Parameters.default ParametersApp.init url key preferences Parameters.default in ( Ok model, Cmd.map ParametersMsg cmd )
-
@@ -107,7 +107,7 @@type Msg = NoOp | ParametersMsg Parameters.App.Msg | ParametersMsg ParametersApp.Msg | PreferencesMsg Preferences.App.Msg | QueryHealerMsg QueryHealer.Msg | UrlRequested Browser.UrlRequest
-
@@ -123,7 +123,7 @@ParametersMsg subMsg -> case model.parameters of Ok subModel -> Parameters.App.update subMsg subModel ParametersApp.update subMsg subModel |> Tuple.mapFirst (\p -> { model | parameters = Ok p }) |> Tuple.mapSecond (Cmd.map ParametersMsg)
-
@@ -197,7 +197,7 @@DoNotHighlight -> Nothing in { title = "" { title = "Configurator | CLT-PWS01" , body = [ node "x-app-layout" []
-
@@ -262,7 +262,7 @@ ]] ] :: hr [] [] :: (Parameters.App.view parameters |> List.map (Html.map ParametersMsg)) :: (ParametersApp.view parameters |> List.map (Html.map ParametersMsg)) ++ hr [] [] :: (Preferences.App.panelItems model.preferences |> List.map (Html.map PreferencesMsg)) ++ [ hr [] []
-
@@ -294,7 +294,7 @@ [][ span [ slot "title" ] [ text "Third-party Softwares" ] , p [ slot "description" ] [ text "See " , a [ href "/licenses/third-party.txt" ] [ text "third-party.txt" ] , a [ href "licenses/third-party.txt" ] [ text "third-party.txt" ] , text " for list of third-party softwares and its license text." ] ]
-
@@ -307,7 +307,7 @@ ]} Err queryHealer -> { title = "Parameters Error | WWSTB" { title = "Parameters Error | CLT-PWS01" , body = [ QueryHealer.view queryHealer |> Html.map QueryHealerMsg ] }
-
-
-
@@ -7,11 +7,12 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters exposing (..) module Models.PWS01.Parameters exposing (..) import Dict exposing (Dict) import Length exposing (Length, mm, toMM) import Parameters.Key as Key exposing (Key(..)) import Models.PWS01.Parameters.Key as Key exposing (Key(..)) import Preferences exposing (DictKeyMode(..)) type TipStyle
-
@@ -253,11 +254,6 @@type alias ParametersDict = Dict String String type DictKeyMode = Regular | Compact toDict : DictKeyMode -> Parameters -> ParametersDict
-
-
-
@@ -7,7 +7,7 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters.App exposing (Model, Msg, init, update, view) module Models.PWS01.Parameters.App exposing (Model, Msg, init, update, view) import Browser.Navigation import Dict
-
@@ -17,12 +17,24 @@ import Html.Attributes exposing (..)import Html.Events exposing (onBlur, onFocus, onInput) import Html.LivingStandard exposing (..) import Length exposing (Length, mm, toMM) import Parameters exposing (ColorSchema(..), LoopStyle(..), Parameters, ParametersDict, colorSchemaToString, getKey, hasKey, loopStyleToString, profileKind, tipStyleToString) import Parameters.Constraints exposing (NumberConstraints, constraints) import Parameters.Key as Key exposing (Key(..)) import Parameters.Parser exposing (..) import Models.PWS01.Parameters as Parameters exposing ( ColorSchema(..) , LoopStyle(..) , Parameters , ParametersDict , colorSchemaToString , getKey , hasKey , loopStyleToString , profileKind , tipStyleToString ) import Models.PWS01.Parameters.Constraints exposing (NumberConstraints, constraints) import Models.PWS01.Parameters.Key as Key exposing (Key(..)) import Models.PWS01.Parameters.Parser exposing (..) import Platform.Cmd as Cmd import Preferences exposing (Preferences) import Preferences exposing (DictKeyMode(..), Preferences) import Process import Task import Time
-
@@ -58,8 +70,8 @@ init baseUrl key preferences params =let fields = Dict.union (Parameters.toDict Parameters.Regular params) (Parameters.fallbackValues Parameters.Regular) (Parameters.toDict Regular params) (Parameters.fallbackValues Regular) in ( { fields = fields , errors =
-
-
-
@@ -7,10 +7,10 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters.Constraints exposing (..) module Models.PWS01.Parameters.Constraints exposing (..) import Length exposing (Length, mm) import Parameters import Models.PWS01.Parameters exposing (Parameters) type alias NumberConstraints a =
-
-
-
@@ -7,7 +7,7 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters.Key exposing (Key(..), toCompactID, toLabel, toString) module Models.PWS01.Parameters.Key exposing (Key(..), toCompactID, toLabel, toString) type Key
-
-
-
@@ -7,13 +7,13 @@ ---- SPDX-License-Identifier: MPL-2.0 module Parameters.Parser exposing (Error(..), Errors, parse) module Models.PWS01.Parameters.Parser exposing (Error(..), Errors, parse) 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) import Parameters.Key as Key exposing (Key(..)) import Models.PWS01.Parameters exposing (..) import Models.PWS01.Parameters.Constraints as Constraints exposing (constraints) import Models.PWS01.Parameters.Key as Key exposing (Key(..)) type Error
-
@@ -203,7 +203,7 @@ Nothing ->Ok Nothing parseFixedLoop : ParametersDict -> Result Errors (Maybe Parameters.FixedLoop) parseFixedLoop : ParametersDict -> Result Errors (Maybe FixedLoop) parseFixedLoop fields = if hasKey HasFixedLoop fields then case
-
@@ -214,7 +214,7 @@ of( Ok width, Ok length ) -> let base = Parameters.defaultFixedLoop defaultFixedLoop in Ok (Just { base | width = width, length = length })
-
@@ -230,7 +230,7 @@ elseOk Nothing parseFreeLoop : ParametersDict -> Result Errors (Maybe Parameters.FreeLoop) parseFreeLoop : ParametersDict -> Result Errors (Maybe FreeLoop) parseFreeLoop fields = if hasKey HasFreeLoop fields then case
-
@@ -255,7 +255,7 @@ elseOk Nothing parseLoops : ParametersDict -> Result Errors Parameters.Loops parseLoops : ParametersDict -> Result Errors Loops parseLoops fields = case ( ( parseFixedLoop fields, parseFreeLoop fields )
-
@@ -276,7 +276,7 @@ |> Dict.Any.fromList Key.toString|> Err parseShortPiece : ParametersDict -> Result Errors Parameters.ShortPiece parseShortPiece : ParametersDict -> Result Errors ShortPiece parseShortPiece fields = case ( parseLoops fields
-
@@ -286,7 +286,7 @@ of( Ok loops, Ok length ) -> let base = Parameters.default.shortPiece default.shortPiece in Ok { base | loops = loops, length = length }
-
@@ -300,7 +300,7 @@ |> Dict.Any.fromList Key.toString|> Err parseBuckleHole : ParametersDict -> Result Errors Parameters.BuckleHole parseBuckleHole : ParametersDict -> Result Errors BuckleHole parseBuckleHole fields = case ( ( parseField BuckleHoleAdjustments (parseInt constraints.longPiece.buckleHole.adjustments) fields
-
@@ -325,17 +325,17 @@ ]) parseTipStyle : ParametersDict -> Result Errors Parameters.TipStyle parseTipStyle : ParametersDict -> Result Errors TipStyle parseTipStyle fields = case getKey TipStyle fields of Just text -> if text == "r" || text == "round" then Ok Parameters.Round Ok Round else if text == "p" || text == "pointed" then case parseField TipSharpness (parseInt constraints.longPiece.tipSharpness) fields of Ok sharpness -> Ok (Parameters.Pointed sharpness) Ok (Pointed sharpness) Err err -> mkErrors [ ( TipSharpness, Just err ) ]
-
@@ -350,7 +350,7 @@ mkErrors [ ( TipStyle, Just MissingValue ) ]|> Err parseLongPiece : ParametersDict -> Result Errors Parameters.LongPiece parseLongPiece : ParametersDict -> Result Errors LongPiece parseLongPiece fields = case ( ( parseBuckleHole fields
-
@@ -373,7 +373,7 @@ |> Dict.Any.fromList Key.toString|> Err parseRendering : ParametersDict -> Result Errors Parameters.Rendering parseRendering : ParametersDict -> Result Errors Rendering parseRendering fields = case ( ( parseField CanvasMargin (parseLength constraints.rendering.margin) fields
-
@@ -386,7 +386,7 @@ of( ( Ok margin, Ok lineWidth, Ok colorSchema ), qrCode ) -> let base = Parameters.default.rendering default.rendering in Ok { base
-
@@ -406,17 +406,17 @@ ]) parseProfile : ParametersDict -> Result Errors Parameters.Profile parseProfile : ParametersDict -> Result Errors Profile parseProfile fields = case getKey Profile fields of Just text -> if text == "s" || text == "straight" then Ok Parameters.Straight Ok Straight else if text == "t" || text == "tapered" then case parseField TaperTo (parseLength constraints.taperTo) fields of Ok taperTo -> Ok (Parameters.Tapered taperTo) Ok (Tapered taperTo) Err err -> Err (mkErrors [ ( TaperTo, Just err ) ])
-
-
-
@@ -7,11 +7,18 @@ ---- SPDX-License-Identifier: MPL-2.0 module Preferences exposing (FieldHighlight(..), Preferences, PreviewTheme(..), decoder, defaultPreferences, encode) module Preferences exposing ( DictKeyMode(..) , FieldHighlight(..) , Preferences , PreviewTheme(..) , decoder , defaultPreferences , encode ) import Json.Decode as Decode import Json.Encode as Encode import Parameters exposing (DictKeyMode(..)) type PreviewTheme
-
@@ -80,6 +87,11 @@DoNotHighlight -> "do_not_highlight" ) type DictKeyMode = Regular | Compact dictKeyModeDecoder : Decode.Decoder DictKeyMode
-
-
-
@@ -15,8 +15,7 @@ import Html.Eventsimport Html.LivingStandard exposing (..) import Json.Decode as Decode import Json.Encode as Encode import Parameters exposing (DictKeyMode(..)) import Preferences exposing (FieldHighlight(..), Preferences, PreviewTheme(..)) import Preferences exposing (DictKeyMode(..), FieldHighlight(..), Preferences, PreviewTheme(..))
-
-
-
@@ -7,17 +7,17 @@ ---- SPDX-License-Identifier: MPL-2.0 module QueryHealer exposing (Model, Msg, init, update, view) module Models.PWS01.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 Preferences exposing (Preferences) import Models.PWS01.Parameters as Parameters import Models.PWS01.Parameters.Key as Key exposing (Key) import Models.PWS01.Parameters.Parser as Parser exposing (Error(..)) import Preferences exposing (DictKeyMode(..), Preferences) import Url exposing (Url) import Url.SearchParams as SearchParams
-
@@ -27,14 +27,14 @@ -- MODELtype alias Model = { errors : Parameters.Parser.Errors { errors : Parser.Errors , searchParams : Dict String String , url : Url , preferences : Preferences } init : Url -> Preferences -> Parameters.Parser.Errors -> Model init : Url -> Preferences -> Parser.Errors -> Model init url preferences errors = { errors = errors , searchParams =
-
@@ -65,7 +65,7 @@-- VIEW defaults : Parameters.DictKeyMode -> Dict String String defaults : DictKeyMode -> Dict String String defaults mode = Dict.union (Parameters.toDict mode Parameters.default)
-
-
-
@@ -7,17 +7,17 @@ ---- SPDX-License-Identifier: MPL-2.0 module Template exposing (template) module Models.PWS01.Template exposing (template) import Length exposing (toMM) import Parameters exposing (LoopStyle(..), Parameters, canvasSizeDimension) import Parameters.Key exposing (Key) import Models.PWS01.Parameters exposing (LoopStyle(..), Parameters, canvasSizeDimension) import Models.PWS01.Parameters.Key exposing (Key) import Models.PWS01.Template.Cuts exposing (cuts) import Models.PWS01.Template.InfoArea exposing (infoArea) import String import Svg exposing (..) import Svg.Attributes exposing (..) import Svg.Path exposing (LargeArcFlag(..), PathCommand(..), PointMode(..), SweepFlag(..)) import Template.Cuts exposing (cuts) import Template.InfoArea exposing (infoArea) import Template.Layout as Layout import Template.Layout.Container as Container import Template.Layout.Coordinate exposing (Request(..))
-
-
-
@@ -7,11 +7,11 @@ ---- SPDX-License-Identifier: MPL-2.0 module Template.Cuts exposing (cuts) module Models.PWS01.Template.Cuts exposing (cuts) import Length exposing (Length, toMM) import Parameters exposing (LoopStyle(..), Parameters, Profile(..), TipStyle(..)) import Parameters.Key exposing (Key(..)) import Models.PWS01.Parameters exposing (LoopStyle(..), Parameters, Profile(..), TipStyle(..)) import Models.PWS01.Parameters.Key exposing (Key(..)) import Svg exposing (..) import Svg.Attributes exposing (..) import Svg.Path as Path exposing (..)
-
-
-
@@ -7,12 +7,12 @@ ---- SPDX-License-Identifier: MPL-2.0 module Template.InfoArea exposing (infoArea) module Models.PWS01.Template.InfoArea exposing (infoArea) import Html.Attributes exposing (attribute) import Length exposing (toMM) import Parameters exposing (Parameters, Profile(..)) import Parameters.Key as Key exposing (Key(..)) import Models.PWS01.Parameters exposing (..) import Models.PWS01.Parameters.Key as Key exposing (Key(..)) import QRCode import Svg exposing (..) import Svg.Attributes as Attrs exposing (..)
-
@@ -42,7 +42,21 @@ |> Container.build[ columns |> gapped 5 |> Container.build [ scaleChcker [ Item { width = AtLeast 20, height = Exactly 5 } (\p size -> text_ [ x (String.fromFloat p.x) , y (String.fromFloat (p.y + size.height / 2)) , fontSize "4" , fontWeight "700" , textAnchor "left" , dominantBaseline "middle" , fill "currentColor" ] [ text "CLT-PWS01" ] ) , scaleChcker , legends params |> noGrow ] |> noGrow
-
@@ -229,14 +243,14 @@ , value = lengthValue to} ] , case params.longPiece.tip of Parameters.Round -> Round -> [ parameter { key = TipStyle , value = value "Round" } ] Parameters.Pointed sharpness -> Pointed sharpness -> [ parameter { key = TipStyle , value = value "Pointed"
-
@@ -272,10 +286,10 @@ { key = LoopStyle, value = value (case params.shortPiece.loops.style of Parameters.Simple -> Simple -> "Simple" Parameters.Folded -> Folded -> "Folded" ) }
-
-
-
@@ -13,54 +13,11 @@ <head><meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="color-scheme" content="light dark" /> <title>Watch Strap Template Builder</title> <script src="/main.js"></script> <script type="module"> const PREFERENCES_KEY = "wwstb.preferences"; function loadPreferences() { try { const loaded = localStorage.getItem(PREFERENCES_KEY); if (!loaded) { return {}; } return JSON.parse(loaded); } catch (err) { console.warn("Failed to load stored preferences, falling back to defaults.", err); return {}; } } import("./elements.js").then(() => { const app = Elm.Main.init({ flags: { preferences: loadPreferences(), } }); app.ports.writePreferences.subscribe(preferences => { localStorage.setItem(PREFERENCES_KEY, JSON.stringify(preferences)); }); }); </script> <title>Configurable Leathercraft Templates | CLT</title> <meta name="description" content="My leathercraft templates and configurator application" /> <style> :where(*, *::before, *::after) { box-sizing: border-box; margin: 0; } :root { --_highlight-color: oklch(50% 0.4 0deg); } @font-face { font-family: "Barlow"; font-weight: normal; src: url("vendor/barlow/fonts/woff2/Barlow-Regular.woff2") format("woff2"), url("vendor/barlow/fonts/otf/Barlow-Regular.otf") format("opentype"), url("vendor/barlow/fonts/ttf/Barlow-Regular.ttf") format("truetype"); } @font-face {
-
@@ -69,27 +26,28 @@ font-weight: 100 900;src: local("InterVariable"), local("Inter"), url("vendor/Inter/web/InterVariable.woff2") format("woff2"), url("vendor/Inter/InterVariable.ttf") format("ttf"); } @media print { :root, body { margin: 0; padding: 0; } @page { size: A4; margin: 0; } url("/vendor/Inter/web/InterVariable.woff2") format("woff2"), url("/vendor/Inter/InterVariable.ttf") format("ttf"); } @media not print { x-preview > svg .highlight-stroke { stroke: var(--_highlight-color); } body { font-family: "Inter", sans-serif; } </style> </head> <body> <h1>Configurable Leathercraft Templates</h1> <p>This website hosts my configurable leathercraft templates.</p> <hr/> <h2>CLT-PWS01: Basic wristwatch strap</h2> <p>CLT-PWS01 is a classic tow-piece strap for wristwatches.</p> <ul> <li> <a href="./pws01/">Configurator</a> </li> <li>License: CC-BY-4.0</li> </ul> </body> </html>
-
-
src/pws01/index.html (new)
-
@@ -0,0 +1,95 @@<!DOCTYPE html> <!-- 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 --> <html lang="en-US"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="color-scheme" content="light dark" /> <title>Template Editor | CTB-PWS01</title> <script src="./main.js"></script> <script type="module"> const PREFERENCES_KEY = "ctb.preferences"; function loadPreferences() { try { const loaded = localStorage.getItem(PREFERENCES_KEY); if (!loaded) { return {}; } return JSON.parse(loaded); } catch (err) { console.warn("Failed to load stored preferences, falling back to defaults.", err); return {}; } } import("/elements.js").then(() => { const app = Elm.Models.PWS01.Main.init({ flags: { preferences: loadPreferences(), } }); app.ports.writePreferences.subscribe(preferences => { localStorage.setItem(PREFERENCES_KEY, JSON.stringify(preferences)); }); }); </script> <style> :where(*, *::before, *::after) { box-sizing: border-box; margin: 0; } :root { --_highlight-color: oklch(50% 0.4 0deg); } @font-face { font-family: "Barlow"; font-weight: normal; src: url("/vendor/barlow/fonts/woff2/Barlow-Regular.woff2") format("woff2"), url("/vendor/barlow/fonts/otf/Barlow-Regular.otf") format("opentype"), url("/vendor/barlow/fonts/ttf/Barlow-Regular.ttf") format("truetype"); } @font-face { font-family: "Inter"; font-weight: 100 900; src: local("InterVariable"), local("Inter"), url("/vendor/Inter/web/InterVariable.woff2") format("woff2"), url("/vendor/Inter/InterVariable.ttf") format("ttf"); } @media print { :root, body { margin: 0; padding: 0; } @page { size: A4; margin: 0; } } @media not print { x-preview > svg .highlight-stroke { stroke: var(--_highlight-color); } } </style> </head> </html>
-