diff options
Diffstat (limited to 'elm3/CharEdit')
-rw-r--r-- | elm3/CharEdit/General.elm | 260 | ||||
-rw-r--r-- | elm3/CharEdit/Main.elm | 130 | ||||
-rw-r--r-- | elm3/CharEdit/New.elm | 19 | ||||
-rw-r--r-- | elm3/CharEdit/Traits.elm | 81 | ||||
-rw-r--r-- | elm3/CharEdit/VN.elm | 186 |
5 files changed, 0 insertions, 676 deletions
diff --git a/elm3/CharEdit/General.elm b/elm3/CharEdit/General.elm deleted file mode 100644 index ee0dbd77..00000000 --- a/elm3/CharEdit/General.elm +++ /dev/null @@ -1,260 +0,0 @@ -module CharEdit.General exposing (..) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import File exposing (File) -import Lib.Html exposing (..) -import Lib.Autocomplete as A -import Lib.Util exposing (..) -import Lib.Gen as Gen -import Lib.Api as Api - - -type alias Model = - { alias : String - , aliasDuplicates : Bool - , bDay : Int - , bMonth : Int - , bloodt : String - , desc : String - , gender : String - , height : Int - , image : Int - , imgState : Api.State - , name : String - , original : String - , sBust : Int - , sHip : Int - , sWaist : Int - , weight : Maybe Int - , mainIs : Bool - , mainInstance : Bool - , mainId : Int - , mainSpoil : Int - , mainName : String - , mainSearch : A.Model Gen.ApiCharResult - } - - -init : Gen.CharEdit -> Model -init d = - { alias = d.alias - , aliasDuplicates = False - , bDay = d.b_day - , bMonth = d.b_month - , bloodt = d.bloodt - , desc = d.desc - , gender = d.gender - , height = d.height - , image = d.image - , imgState = Api.Normal - , name = d.name - , original = d.original - , sBust = d.s_bust - , sHip = d.s_hip - , sWaist = d.s_waist - , weight = d.weight - , mainIs = d.main_is - , mainInstance = isJust d.main - , mainId = Maybe.withDefault 0 d.main - , mainSpoil = d.main_spoil - , mainName = d.main_name - , mainSearch = A.init - } - - -new : Model -new = - { alias = "" - , aliasDuplicates = False - , bDay = 0 - , bMonth = 0 - , bloodt = "unknown" - , desc = "" - , gender = "unknown" - , height = 0 - , image = 0 - , imgState = Api.Normal - , name = "" - , original = "" - , sBust = 0 - , sHip = 0 - , sWaist = 0 - , weight = Nothing - , mainIs = False - , mainInstance = False - , mainId = 0 - , mainSpoil = 0 - , mainName = "" - , mainSearch = A.init - } - - -searchConfig : A.Config Msg Gen.ApiCharResult -searchConfig = { wrap = MainSearch, id = "add-main", source = A.charSource } - - -type Msg - = Name String - | Original String - | Alias String - | Desc String - | Image String - | Gender String - | Bloodt String - | BMonth String - | BDay String - | SBust String - | SWaist String - | SHip String - | Height String - | Weight String - | MainInstance Bool - | MainSpoil String - | MainSearch (A.Msg Gen.ApiCharResult) - | ImgUpload (List File) - | ImgDone Api.Response - - -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - case msg of - Name s -> ({ model | name = s }, Cmd.none) - Original s -> ({ model | original = s }, Cmd.none) - Alias s -> ({ model | alias = s, aliasDuplicates = hasDuplicates (model.name :: model.original :: splitLn s) }, Cmd.none) - Desc s -> ({ model | desc = s }, Cmd.none) - Image s -> ({ model | image = if s == "" then 0 else Maybe.withDefault model.image (String.toInt s) }, Cmd.none) - Gender s -> ({ model | gender = s }, Cmd.none) - Bloodt s -> ({ model | bloodt = s }, Cmd.none) - BMonth s -> ({ model | bMonth = if s == "" then 0 else Maybe.withDefault model.bMonth (String.toInt s) }, Cmd.none) - BDay s -> ({ model | bDay = if s == "" then 0 else Maybe.withDefault model.bDay (String.toInt s) }, Cmd.none) - SBust s -> ({ model | sBust = if s == "" then 0 else Maybe.withDefault model.sBust (String.toInt s) }, Cmd.none) - SWaist s -> ({ model | sWaist = if s == "" then 0 else Maybe.withDefault model.sWaist (String.toInt s) }, Cmd.none) - SHip s -> ({ model | sHip = if s == "" then 0 else Maybe.withDefault model.sHip (String.toInt s) }, Cmd.none) - Height s -> ({ model | height = if s == "" then 0 else Maybe.withDefault model.height (String.toInt s) }, Cmd.none) - Weight s -> ({ model | weight = String.toInt s }, Cmd.none) - MainInstance b->({ model | mainInstance = b }, Cmd.none) - MainSpoil s -> ({ model | mainSpoil = Maybe.withDefault model.mainSpoil (String.toInt s) }, Cmd.none) - MainSearch m -> - let (nm, c, res) = A.update searchConfig m model.mainSearch - in case res of - Nothing -> ({ model | mainSearch = nm }, c) - Just r -> - -- If the selected char has a main, automatically select that as our main - let chr = Maybe.withDefault {id = r.id, name = r.name, original = r.original } r.main - in ({ model | mainId = chr.id, mainName = chr.name, mainSearch = A.clear nm }, c) - - ImgUpload [i] -> ({ model | imgState = Api.Loading }, Api.postImage Api.Ch i ImgDone) - ImgUpload _ -> (model, Cmd.none) - - ImgDone (Gen.Image id _ _) -> ({ model | image = id, imgState = Api.Normal }, Cmd.none) - ImgDone r -> ({ model | image = 0, imgState = Api.Error r }, Cmd.none) - - -zeroEmpty : Int -> String -zeroEmpty i = if i == 0 then "" else String.fromInt i - - -view : Model -> Html Msg -view model = card "general" "General info" [] - - [ cardRow "Name" Nothing <| formGroups - [ [ label [for "name"] [text "Name (romaji)"] - , inputText "name" model.name Name [required True, maxlength 200] - ] - , [ label [for "original"] [text "Original"] - , inputText "original" model.original Original [maxlength 200] - , div [class "form-group__help"] [text "The character's name in the language of the visual novel, leave blank if it already is in the Latin alphabet."] - ] - , [ inputTextArea "aliases" model.alias Alias - [ rows 4, maxlength 500 - , classList [("is-invalid", model.aliasDuplicates)] - ] - , if model.aliasDuplicates - then div [class "invalid-feedback"] - [ text "There are duplicate aliases." ] - else text "" - , div [class "form-group__help"] [ text "(Un)official aliases, separated by a newline." ] - ] - ] - - , cardRow "Description" (Just "English please!") <| formGroup - [ inputTextArea "desc" model.desc Desc [rows 8] ] - - , cardRow "Image" Nothing - [ div [class "row"] - [ div [class "col-md col-md--1"] - [ div [style "max-width" "200px", style "margin-bottom" "8px"] - [ dbImg "ch" (if model.imgState == Api.Loading then -1 else model.image) [] Nothing ] - ] - , div [class "col-md col-md--2"] <| formGroups - [ [ label [for "img"] [ text "Upload new image" ] - , input [type_ "file", class "text", name "img", id "img", Api.onFileChange ImgUpload, disabled (model.imgState == Api.Loading) ] [] - , case model.imgState of - Api.Error r -> div [class "invalid-feedback"] [text <| Api.showResponse r] - _ -> text "" - , div [class "form-group__help"] - [ text "Image must be in JPEG or PNG format and at most 1MiB. Images larger than 256x300 will be resized automatically. Image must be safe for work!" ] - ] - , [ label [for "img_id"] [ text "Image ID" ] - , inputText "img_id" (String.fromInt model.image) Image [pattern "^[0-9]+$", disabled (model.imgState == Api.Loading)] - , div [class "form-group__help"] - [ text "Use a character image that is already on the server. Set to '0' to remove the current image." ] - ] - ] - ] - ] - - , cardRow "Meta" Nothing <| formGroups - [ [ label [for "sex"] [text "Sex"] - , inputSelect [id "sex", onInput Gender] model.gender Gen.genders - ] - , [ label [for "bloodt"] [text "Blood type"] - , inputSelect [id "bloodt", onInput Bloodt] model.bloodt Gen.bloodTypes - ] - -- TODO: Enforce that both or neither are set - , [ label [for "b_month"] [text "Birthday"] - , inputSelect [id "b_month", onInput BMonth, class "form-control--inline"] (String.fromInt model.bMonth) - <| ("0", "--month--") :: List.map (\i -> (String.fromInt i, String.fromInt i)) (List.range 1 12) - , inputSelect [id "b_day", onInput BDay, class "form-control--inline"] (String.fromInt model.bDay) - <| ("0", "--day--" ) :: List.map (\i -> (String.fromInt i, String.fromInt i)) (List.range 1 31) - ] - -- XXX: This looks messy - , [ label [] [ text "Measurements" ] - , p [] - [ text "Bust (cm): ", inputText "s_bust" (zeroEmpty model.sBust ) SBust [class "form-control--inline", style "width" "4em", pattern "^[0-9]{0,5}$"] - , text " Waist (cm): ", inputText "s_waist" (zeroEmpty model.sWaist) SWaist [class "form-control--inline", style "width" "4em", pattern "^[0-9]{0,5}$"] - , text " Hip (cm): ", inputText "s_hip" (zeroEmpty model.sHip ) SHip [class "form-control--inline", style "width" "4em", pattern "^[0-9]{0,5}$"] - ] - , p [] - [ text "Height (cm): ", inputText "height" (zeroEmpty model.height) Height [class "form-control--inline", style "width" "5em", pattern "^[0-9]{0,5}$"] - , text " Weight (kg): ",inputText "weight" (Maybe.withDefault "" <| Maybe.map String.fromInt model.weight) Weight [class "form-control--inline", style "width" "5em", pattern "^[0-9]{0,5}$"] - ] - ] - ] - - , cardRow "Instance" Nothing <| - if model.mainIs - then formGroup [ div [class "form-group__help"] - [ text "This character is already referenced as \"main\" from another character entry." - , text " If you want link this entry to another character, please edit that other character instead." - ] - ] - else formGroups <| - [ label [class "checkbox"] [ inputCheck "" model.mainInstance MainInstance, text " This character is an instance of another character" ] ] - :: if not model.mainInstance then [] else - [ [ if model.mainId == 0 - then div [] [ text "No character selected." ] - else div [] - [ text "Main character: " - , span [class "muted"] [ text <| "c" ++ String.fromInt model.mainId ++ ":" ] - , a [href <| "/c" ++ String.fromInt model.mainId, target "_blank"] [ text model.mainName ] - ] - ] - , if model.mainId == 0 then [] else - [ inputSelect [id "mainspoil", onInput MainSpoil, class "form-control--inline"] (String.fromInt model.mainSpoil) spoilLevels ] - , A.view searchConfig model.mainSearch [placeholder "Character name...", style "max-width" "400px"] - ] - - ] diff --git a/elm3/CharEdit/Main.elm b/elm3/CharEdit/Main.elm deleted file mode 100644 index dbb88788..00000000 --- a/elm3/CharEdit/Main.elm +++ /dev/null @@ -1,130 +0,0 @@ -module CharEdit.Main exposing (Model,Msg,main,new,update,view) - -import Html exposing (..) -import Html.Lazy exposing (..) -import Browser -import Browser.Navigation exposing (load) -import Lib.Html exposing (..) -import Lib.Gen as Gen -import Lib.Api as Api -import Lib.Editsum as Editsum -import CharEdit.General as General -import CharEdit.Traits as Traits -import CharEdit.VN as VN - - -main : Program Gen.CharEdit Model Msg -main = Browser.element - { init = \e -> (init e, Cmd.none) - , view = view - , update = update - , subscriptions = always Sub.none - } - - -type alias Model = - { state : Api.State - , editsum : Editsum.Model - , general : General.Model - , traits : Traits.Model - , vn : VN.Model - , id : Maybe Int - } - - -init : Gen.CharEdit -> Model -init d = - { state = Api.Normal - , editsum = { authmod = d.authmod, editsum = d.editsum, locked = d.locked, hidden = d.hidden } - , general = General.init d - , traits = Traits.init d.traits - , vn = VN.init d.vns d.vnrels - , id = d.id - } - - -new : List Gen.CharEditVns -> List Gen.CharEditVnrels -> Model -new vns vnrels = - { state = Api.Normal - , editsum = Editsum.new - , general = General.new - , traits = Traits.init [] - , vn = VN.init vns vnrels - , id = Nothing - } - - -encode : Model -> Gen.CharEditSend -encode model = - { editsum = model.editsum.editsum - , hidden = model.editsum.hidden - , locked = model.editsum.locked - , alias = model.general.alias - , b_day = model.general.bDay - , b_month = model.general.bMonth - , bloodt = model.general.bloodt - , desc = model.general.desc - , gender = model.general.gender - , height = model.general.height - , image = model.general.image - , name = model.general.name - , original = model.general.original - , s_bust = model.general.sBust - , s_hip = model.general.sHip - , s_waist = model.general.sWaist - , weight = model.general.weight - , main = if not model.general.mainInstance || model.general.mainId == 0 then Nothing else Just model.general.mainId - , main_spoil = model.general.mainSpoil - , traits = List.map (\e -> { tid = e.tid, spoil = e.spoil }) model.traits.traits - , vns = VN.encode model.vn - } - - -type Msg - = Editsum Editsum.Msg - | General General.Msg - | Traits Traits.Msg - | VN VN.Msg - | Submit - | Submitted Api.Response - - -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - case msg of - Editsum m -> ({ model | editsum = Editsum.update m model.editsum }, Cmd.none) - General m -> let (nm, c) = General.update m model.general in ({ model | general = nm }, Cmd.map General c) - Traits m -> let (nm, c) = Traits.update m model.traits in ({ model | traits = nm }, Cmd.map Traits c) - VN m -> let (nm, c) = VN.update m model.vn in ({ model | vn = nm }, Cmd.map VN c) - - Submit -> - let - path = - case model.id of - Just id -> "/c" ++ String.fromInt id ++ "/edit" - Nothing -> "/c/add" - body = Gen.chareditSendEncode (encode model) - in ({ model | state = Api.Loading }, Api.post path body Submitted) - - Submitted (Gen.Changed id rev) -> (model, load <| "/c" ++ String.fromInt id ++ "." ++ String.fromInt rev) - Submitted r -> ({ model | state = Api.Error r }, Cmd.none) - - -isValid : Model -> Bool -isValid model = not - ( model.general.aliasDuplicates - || (model.general.mainInstance && model.general.mainId == 0) - || model.traits.duplicates - || model.vn.duplicates - ) - - -view : Model -> Html Msg -view model = - form_ Submit (model.state == Api.Loading) - [ Html.map General <| lazy General.view model.general - , Html.map Traits <| lazy Traits.view model.traits - , Html.map VN <| lazy VN.view model.vn - , Html.map Editsum <| lazy Editsum.view model.editsum - , submitButton "Submit" model.state (isValid model) False - ] diff --git a/elm3/CharEdit/New.elm b/elm3/CharEdit/New.elm deleted file mode 100644 index 1a43341a..00000000 --- a/elm3/CharEdit/New.elm +++ /dev/null @@ -1,19 +0,0 @@ -module CharEdit.New exposing (main) - -import Browser -import Lib.Gen exposing (CharEditVnrels, CharEditVns) -import CharEdit.Main as Main - - -type alias Flags = - { vnrels : List CharEditVnrels - , vns : List CharEditVns - } - -main : Program Flags Main.Model Main.Msg -main = Browser.element - { init = \f -> (Main.new f.vns f.vnrels, Cmd.none) - , view = Main.view - , update = Main.update - , subscriptions = always Sub.none - } diff --git a/elm3/CharEdit/Traits.elm b/elm3/CharEdit/Traits.elm deleted file mode 100644 index 60399452..00000000 --- a/elm3/CharEdit/Traits.elm +++ /dev/null @@ -1,81 +0,0 @@ -module CharEdit.Traits exposing (Model, Msg, init, update, view) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import Lib.Html exposing (..) -import Lib.Autocomplete as A -import Lib.Gen as Gen -import Lib.Util exposing (..) - - -type alias Model = - { traits : List Gen.CharEditTraits - , search : A.Model Gen.ApiTraitResult - , duplicates : Bool - } - - -init : List Gen.CharEditTraits -> Model -init l = - { traits = l - , search = A.init - , duplicates = False - } - - -type Msg - = Del Int - | SetSpoil Int String - | Search (A.Msg Gen.ApiTraitResult) - - -searchConfig : A.Config Msg Gen.ApiTraitResult -searchConfig = { wrap = Search, id = "add-trait", source = A.traitSource } - - -validate : Model -> Model -validate model = { model | duplicates = hasDuplicates <| List.map .tid model.traits } - - -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - case msg of - Del i -> (validate { model | traits = delidx i model.traits }, Cmd.none) - SetSpoil i s -> (validate { model | traits = modidx i (\e -> { e | spoil = Maybe.withDefault e.spoil (String.toInt s) }) model.traits } - , Cmd.none ) - - Search m -> - let (nm, c, res) = A.update searchConfig m model.search - in case res of - Nothing -> ({ model | search = nm }, c) - Just r -> - let nrow = { tid = r.id, name = r.name, group = Maybe.withDefault "" r.group, spoil = 0 } - in (validate { model | search = A.clear nm, traits = model.traits ++ [nrow] }, c) - - - -view : Model -> Html Msg -view model = - let - entry n e = editListRow "" - [ editListField 2 "col-form-label single-line" - [ span [ class "muted" ] [ text <| e.group ++ " / " ] - , a [href <| "/i" ++ String.fromInt e.tid, title e.name, target "_blank" ] [ text e.name ] ] - , editListField 1 "" - [ inputSelect [onInput (SetSpoil n)] (String.fromInt e.spoil) spoilLevels ] - , editListField 0 "" [ removeButton (Del n) ] - ] - - in card "traits" "Traits" [] - <| editList (List.indexedMap entry model.traits) - ++ formGroups ( - (if model.duplicates - then [ [ div [ class "invalid-feedback" ] - [ text "There are duplicate traits." ] ] ] - else [] - ) ++ - [ label [for "add-trait"] [text "Add trait"] - :: A.view searchConfig model.search [placeholder "Trait", style "max-width" "400px"] - ] - ) diff --git a/elm3/CharEdit/VN.elm b/elm3/CharEdit/VN.elm deleted file mode 100644 index 57a50c88..00000000 --- a/elm3/CharEdit/VN.elm +++ /dev/null @@ -1,186 +0,0 @@ -module CharEdit.VN exposing (Model, Msg, init, encode, update, view) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import Json.Encode as JE -import Dict exposing (Dict) -import Lib.Html exposing (..) -import Lib.Autocomplete as A -import Lib.Gen as Gen -import Lib.Util exposing (..) -import Lib.Api as Api - - -type alias VNRel = - { id : Int - , title : String - , role : String - , spoil : Int - , relsel : Bool - , rel : Dict Int { role : String, spoil : Int } - } - -type alias Model = - { vn : List VNRel - , releases : Dict Int (List Gen.CharEditVnrelsReleases) -- Mapping from VN id -> list of releases - , search : A.Model Gen.ApiVNResult - , duplicates : Bool - } - - -init : List Gen.CharEditVns -> List Gen.CharEditVnrels -> Model -init vns rels = - -- Turn the array from the server into a more usable data structure. This assumes that the array is ordered by VN id. - let - merge o n = case n.rid of - Nothing -> { o | role = n.role, spoil = n.spoil } - Just i -> { o | relsel = True, rel = Dict.insert i { role = n.role, spoil = n.spoil } o.rel } - - new n = case n.rid of - Nothing -> { id = n.vid, title = n.title, relsel = False, role = n.role, spoil = n.spoil, rel = Dict.empty } - Just i -> { id = n.vid, title = n.title, relsel = True, role = "", spoil = 0, rel = Dict.fromList [(i, { role = n.role, spoil = n.spoil })] } - - step n l = - case l of - [] -> [ new n ] - i::xs -> - if i.id == n.vid - then merge i n :: xs - else new n :: l - in - { vn = List.foldr step [] vns - , releases = Dict.fromList <| List.map (\n -> (n.id, n.releases)) rels - , search = A.init - , duplicates = False - } - - --- XXX: The model and the UI allow an invalid state: VN is present, but --- role="". This isn't too obvious to trigger, I hope, so in this case we'll --- just be lazy and not send the VN to the server. -encode : Model -> List Gen.CharEditSendVns -encode model = - let - vn e = - (if e.role == "" then [] else [{ vid = e.id, rid = Nothing, role = e.role, spoil = e.spoil }]) - ++ - (if e.relsel then Dict.foldl (\id r l -> { vid = e.id, rid = Just id, role = r.role, spoil = r.spoil } :: l) [] e.rel else []) - in List.concat <| List.map vn model.vn - - - -type Msg - = Del Int - | SetSel Int Bool - | SetRole Int String - | SetSpoil Int String - | SetRRole Int Int String - | SetRSpoil Int Int String - | Search (A.Msg Gen.ApiVNResult) - | ReleaseInfo Int Api.Response - - -searchConfig : A.Config Msg Gen.ApiVNResult -searchConfig = { wrap = Search, id = "add-vn", source = A.vnSource } - - -validate : Model -> Model -validate model = { model | duplicates = hasDuplicates <| List.map .id model.vn } - - -update : Msg -> Model -> (Model, Cmd Msg) -update msg model = - let - rrole s o_ = if s == "" then Nothing - else Just <| case o_ of - Nothing -> { role = s, spoil = 0 } - Just o -> { o | role = s } - rspoil s = Maybe.map (\o -> { o | spoil = Maybe.withDefault o.spoil (String.toInt s) }) - in case msg of - Del i -> (validate { model | vn = delidx i model.vn }, Cmd.none) - SetSel i b -> ({ model | vn = modidx i (\e -> { e | relsel = b }) model.vn }, Cmd.none) - SetRole i s -> ({ model | vn = modidx i (\e -> { e | role = s }) model.vn }, Cmd.none) - SetSpoil i s -> ({ model | vn = modidx i (\e -> { e | spoil = Maybe.withDefault e.spoil (String.toInt s) }) model.vn }, Cmd.none) - SetRRole i id s -> ({ model | vn = modidx i (\e -> { e | rel = Dict.update id (rrole s) e.rel }) model.vn }, Cmd.none) - SetRSpoil i id s -> ({ model | vn = modidx i (\e -> { e | rel = Dict.update id (rspoil s) e.rel }) model.vn }, Cmd.none) - - Search m -> - let (nm, c, res) = A.update searchConfig m model.search - in case res of - Nothing -> ({ model | search = nm }, c) - Just r -> - let - nrow = { id = r.id, title = r.title, relsel = False, role = "primary", spoil = 0, rel = Dict.empty } - nc = case Dict.get r.id model.releases of - Nothing -> Api.post "/js/release.json" (JE.object [("vid", JE.int r.id)]) (ReleaseInfo r.id) - Just _ -> Cmd.none - in (validate { model | search = A.clear nm, vn = model.vn ++ [nrow] }, Cmd.batch [c, nc]) - - ReleaseInfo vid (Gen.ReleaseResult r) -> ({ model | releases = Dict.insert vid r model.releases}, Cmd.none) - ReleaseInfo _ _ -> (model, Cmd.none) - - - -view : Model -> Html Msg -view model = - let - vn n e = editList <| - editListRow "" - [ editListField 3 "col-form-label single-line" - [ span [ class "muted" ] [ text <| "v" ++ String.fromInt e.id ++ ":" ] - , a [ href <| "/v" ++ String.fromInt e.id, target "_blank" ] [ text e.title ] - ] - , editListField 0 "" [ removeButton (Del n) ] - ] - :: case Dict.get e.id model.releases of - Nothing -> [ div [ class "spinner spinner--md" ] [] ] - Just l -> default n e :: if e.relsel then List.map (rel n e.rel) l else [] - - default n e = - editListRow "" - [ editListField 2 "ml-3" - [ label [class "checkbox"] [ inputCheck "" e.relsel (SetSel n), text " Per release" ] ] - , editListField 1 "col-form-label single-line text-right" [ text <| if e.relsel then "Default:" else "All releases:" ] - , editListField 1 "" - [ inputSelect [onInput (SetRole n)] e.role <| - (if e.relsel then [("", "Not involved")] else []) - ++ Gen.charRoles - ] - , editListField 1 "" - [ if e.role == "" - then text "" - else inputSelect [onInput (SetSpoil n)] (String.fromInt e.spoil) spoilLevels - ] - ] - - rel n rels e = - let - sel = Maybe.withDefault { role = "", spoil = 0 } <| Dict.get e.id rels - in editListRow "" - [ editListField 3 "col-form-label single-line ml-3" <| - span [ class "muted" ] [ text <| "r" ++ String.fromInt e.id ++ ": " ] - :: List.map iconLanguage e.lang - ++ - [ a [href <| "/r" ++ String.fromInt e.id, title e.title, target "_blank" ] [ text e.title ] ] - , editListField 1 "" - [ inputSelect [onInput (SetRRole n e.id)] sel.role (("", "-default-") :: Gen.charRoles) ] - , editListField 1 "" - [ if sel.role == "" - then text "" - else inputSelect [onInput (SetRSpoil n e.id)] (String.fromInt sel.spoil) spoilLevels - ] - ] - - in card "vns" "Visual Novels" [] <| - List.concat (List.indexedMap vn model.vn) - ++ formGroups ( - (if model.duplicates - then [ [ div [ class "invalid-feedback" ] - [ text "There are duplicate visual novels." ] ] ] - else [] - ) ++ - [ label [for "add-vn"] [text "Add visual novel"] - :: A.view searchConfig model.search [placeholder "VIsual novel", style "max-width" "400px"] - ] - ) |