-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-- 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
port module Preferences.App exposing (Model, Msg, init, panelItems, update)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events
import Html.LivingStandard exposing (..)
import Json.Decode as Decode
import Json.Encode as Encode
import Preferences exposing (FieldHighlight(..), Preferences, PreviewTheme(..))
-- PORTS
port writePreferences : Encode.Value -> Cmd msg
-- MODEL
type alias Model =
{ preferences : Preferences
}
init : Decode.Value -> Model
init saved =
case Decode.decodeValue Preferences.decoder saved of
Ok preferences ->
{ preferences = preferences }
Err _ ->
-- As `Preferences.decoder` never fails, this is unreachable.
{ preferences = Preferences.defaultPreferences }
-- UPDATE
type Msg
= NoOp
| SetPreviewTheme PreviewTheme
| SetFieldHighlight FieldHighlight
| WritePreferences
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
let
{ preferences } =
model
in
case msg of
NoOp ->
( model, Cmd.none )
SetPreviewTheme theme ->
update WritePreferences { model | preferences = { preferences | previewTheme = theme } }
SetFieldHighlight highlight ->
update WritePreferences { model | preferences = { preferences | fieldHighlight = highlight } }
WritePreferences ->
( model, writePreferences (Preferences.encode model.preferences) )
-- VIEW
previewThemeId : String
previewThemeId =
"preview-theme"
fieldHighlightId : String
fieldHighlightId =
"field-highlight"
descriptionId : String -> String
descriptionId prefix =
prefix ++ "_description"
type alias RadioBoxProps msg =
{ label : List (Html msg)
, description : List (Html msg)
, name : String
, value : String
, checked : Bool
, onCheck : msg
}
radioBox : RadioBoxProps msg -> List (Html.Attribute msg) -> Html msg
radioBox { label, description, name, value, checked, onCheck } attrs =
let
id =
name ++ "_" ++ value
in
node "x-radio-box"
[ if checked then
attribute "checked" ""
else
class ""
]
[ Html.label [ for id, slot "label" ] label
, Html.p [ Html.Attributes.id (descriptionId id), slot "description" ] description
, input
(type_ "radio"
:: Html.Attributes.id id
:: Html.Attributes.name name
:: Html.Attributes.value value
:: Html.Attributes.checked checked
:: Html.Events.onCheck (\_ -> onCheck)
:: attrs
)
[]
]
panelItems : Model -> List (Html Msg)
panelItems model =
[ node "x-field-group"
[]
[ span [ slot "title" ] [ text "Preferences" ]
, span [ slot "description" ] [ text "These parameters are saved to this browser, and will not be shared." ]
, node "x-field"
[]
[ span [ slot "title" ] [ text "Preview Color Theme" ]
, p
[ slot "description"
, id (descriptionId previewThemeId)
]
[ text "This does not affect print output." ]
, radioBox
{ label = [ text "Use system theme" ]
, description =
[ text "Toggle light and dark mode automatically based on your system's dark mode setting." ]
, name = previewThemeId
, value = "system"
, checked = model.preferences.previewTheme == SystemTheme
, onCheck = SetPreviewTheme SystemTheme
}
[]
, radioBox
{ label = [ text "Use print theme" ]
, description = [ text "Preview in printed color. Output image will be exactly same to the preview." ]
, name = previewThemeId
, value = "print"
, checked = model.preferences.previewTheme == PrintTheme
, onCheck = SetPreviewTheme PrintTheme
}
[]
]
, node "x-field"
[]
[ span [ slot "title" ] [ text "Field Highlight" ]
, p
[ slot "description"
, id (descriptionId fieldHighlightId)
]
[ text "This does not affect print output." ]
, radioBox
{ label = [ text "Enabled" ]
, description =
[ text "Highlight lines on preview relevant to the focused field." ]
, name = fieldHighlightId
, value = "highlight-on-preview"
, checked = model.preferences.fieldHighlight == HighlightOnPreview
, onCheck = SetFieldHighlight HighlightOnPreview
}
[]
, radioBox
{ label = [ text "Disabled" ]
, description = [ text "Do not highlight on field focus." ]
, name = fieldHighlightId
, value = "do-not-highlight"
, checked = model.preferences.fieldHighlight == DoNotHighlight
, onCheck = SetFieldHighlight DoNotHighlight
}
[]
]
]
]