diff --git a/Cargo.lock b/Cargo.lock index e7589f3..9b3f536 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1603,6 +1603,7 @@ checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" dependencies = [ "equivalent", "hashbrown", + "serde", ] [[package]] @@ -1667,6 +1668,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -2379,6 +2389,27 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -2587,7 +2618,7 @@ dependencies = [ "built", "cfg-if", "interpolate_name", - "itertools", + "itertools 0.12.1", "libc", "libfuzzer-sys", "log", @@ -3028,6 +3059,51 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_valid" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b615bed66931a7a9809b273937adc8a402d038b1e509d027fcaf62f084d33d1" +dependencies = [ + "indexmap", + "itertools 0.13.0", + "num-traits", + "once_cell", + "paste", + "regex", + "serde", + "serde_json", + "serde_valid_derive", + "serde_valid_literal", + "thiserror 1.0.69", + "unicode-segmentation", +] + +[[package]] +name = "serde_valid_derive" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa1a5a21ea5aab06d2e6a6b59837d450fb2be9695be97735a711edfbe79ea07" +dependencies = [ + "itertools 0.13.0", + "paste", + "proc-macro-error2", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.104", +] + +[[package]] +name = "serde_valid_literal" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd07331596ea967dccf9a35bde71ecd757490e09827b938a5c6226c648e3a25e" +dependencies = [ + "paste", + "regex", +] + [[package]] name = "sha1" version = "0.10.6" @@ -3214,6 +3290,12 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -3423,6 +3505,7 @@ dependencies = [ "reqwest", "serde", "serde_json", + "serde_valid", "tetratto-l10n 12.0.0", "tetratto-shared 12.0.6", "tokio", @@ -4027,6 +4110,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + [[package]] name = "unicode-width" version = "0.2.1" diff --git a/crates/app/src/langs/en-US.toml b/crates/app/src/langs/en-US.toml index 77e351e..01943c0 100644 --- a/crates/app/src/langs/en-US.toml +++ b/crates/app/src/langs/en-US.toml @@ -175,6 +175,7 @@ version = "1.0.0" "settings:tab.general" = "General" "settings:tab.account" = "Account" "settings:tab.profile" = "Profile" +"settings:tab.experience" = "Experience" "settings:tab.theme" = "Theme" "settings:tab.sessions" = "Sessions" "settings:tab.grants" = "Grants" diff --git a/crates/app/src/public/css/root.css b/crates/app/src/public/css/root.css index c38372d..5c82cbf 100644 --- a/crates/app/src/public/css/root.css +++ b/crates/app/src/public/css/root.css @@ -199,6 +199,34 @@ body:not(.use_system_font) { & input, & textarea { font-variation-settings: "wght" 325; + + & h1 { + font-variation-settings: "wght" 600; + } + + & h2 { + font-variation-settings: "wght" 550; + } + + & h3 { + font-variation-settings: "wght" 500; + } + + & h4 { + font-variation-settings: "wght" 450; + } + + & h5 { + font-variation-settings: "wght" 400; + } + + & h6 { + font-variation-settings: "wght" 350; + } + + & b { + font-variation-settings: "wght" 500; + } } } diff --git a/crates/app/src/public/css/style.css b/crates/app/src/public/css/style.css index bec7d76..12f83b1 100644 --- a/crates/app/src/public/css/style.css +++ b/crates/app/src/public/css/style.css @@ -1256,6 +1256,11 @@ details summary::-webkit-details-marker { display: none; } +details summary.button { + height: max-content; + justify-content: start; +} + details[open] > summary { position: relative; color: var(--color-text-lowered) !important; @@ -1288,7 +1293,7 @@ details.accordion { details.accordion summary { background: var(--color-lowered); border-radius: var(--radius); - padding: var(--pad-3) var(--pad-4); + padding: var(--pad-3) var(--pad-4) !important; margin: 0; width: 100%; user-select: none; diff --git a/crates/app/src/public/html/communities/settings.lisp b/crates/app/src/public/html/communities/settings.lisp index f95a900..a51c69f 100644 --- a/crates/app/src/public/html/communities/settings.lisp +++ b/crates/app/src/public/html/communities/settings.lisp @@ -147,7 +147,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))))) + (str (text "general:action.save"))))))) (div ("class" "card_nest") ("ui_ident" "danger_zone") @@ -170,7 +170,7 @@ ("onclick" "save_context()") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))) + (str (text "general:action.save")))) (a ("href" "/community/{{ community.title }}") ("class" "button secondary") @@ -273,7 +273,7 @@ ("onclick" "update_user_role(document.getElementById('uid').value, document.getElementById('role').value)") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "card flex flex_col gap_2") ("id" "permission_builder")))) diff --git a/crates/app/src/public/html/developer/app.lisp b/crates/app/src/public/html/developer/app.lisp index 4d4d9c8..1b4060e 100644 --- a/crates/app/src/public/html/developer/app.lisp +++ b/crates/app/src/public/html/developer/app.lisp @@ -95,7 +95,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))) + (str (text "general:action.save")))))) (div ("class" "card_nest") (div @@ -120,7 +120,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))) + (str (text "general:action.save")))))) (div ("class" "card_nest") (div @@ -145,7 +145,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))) + (str (text "general:action.save")))))) (div ("class" "card_nest") (div @@ -185,7 +185,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))) + (str (text "general:action.save")))))) (div ("class" "card_nest") (div diff --git a/crates/app/src/public/html/journals/app.lisp b/crates/app/src/public/html/journals/app.lisp index 337d39c..8f52ed0 100644 --- a/crates/app/src/public/html/journals/app.lisp +++ b/crates/app/src/public/html/journals/app.lisp @@ -255,7 +255,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))))) + (str (text "general:action.save")))))))) ; users should also be able to manage the journal's sub directories here (details diff --git a/crates/app/src/public/html/macros.lisp b/crates/app/src/public/html/macros.lisp index f71deeb..e989794 100644 --- a/crates/app/src/public/html/macros.lisp +++ b/crates/app/src/public/html/macros.lisp @@ -354,7 +354,7 @@ (str (text "forge:tab.tickets")))) (text "{%- endmacro %}") -(text "{% macro profile_settings_nav_options() -%}") +(text "{% macro user_settings_nav_options() -%}") (a ("data-tab-button" "account") ("class" "active") @@ -368,6 +368,12 @@ (text "{{ icon \"user-round\" }}") (span (text "{{ text \"settings:tab.profile\" }}"))) +(a + ("data-tab-button" "experience") + ("href" "#/experience") + (text "{{ icon \"settings-2\" }}") + (span + (text "{{ text \"settings:tab.experience\" }}"))) (a ("data-tab-button" "theme") ("href" "#/theme") @@ -393,4 +399,10 @@ (text "{{ icon \"book-user\" }}") (span (text "{{ text \"settings:tab.close_friends\" }}"))) +(a + ("data-tab-button" "presets") + ("href" "#/presets") + (icon (text "cooking-pot")) + (span + (str (text "settings:tab.presets")))) (text "{%- endmacro %}") diff --git a/crates/app/src/public/html/mod/profile.lisp b/crates/app/src/public/html/mod/profile.lisp index 843f40c..af048e5 100644 --- a/crates/app/src/public/html/mod/profile.lisp +++ b/crates/app/src/public/html/mod/profile.lisp @@ -358,7 +358,7 @@ ("onclick" "update_user_role(Number.parseInt(document.getElementById('role').value))") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "card lowered flex flex_col gap_2") ("id" "permission_builder"))) @@ -376,7 +376,7 @@ ("onclick" "update_user_secondary_role(Number.parseInt(document.getElementById('secondary_role').value))") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "card lowered flex flex_col gap_2") ("id" "secondary_permission_builder"))) diff --git a/crates/app/src/public/html/post/post.lisp b/crates/app/src/public/html/post/post.lisp index ad6fcb0..61214cf 100644 --- a/crates/app/src/public/html/post/post.lisp +++ b/crates/app/src/public/html/post/post.lisp @@ -148,7 +148,7 @@ ("onclick" "save_context()") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))) + (str (text "general:action.save")))) (script (text "setTimeout(async () => { const ui = await ns(\"ui\"); @@ -286,7 +286,7 @@ ("class" "flex gap_2") (text "{{ components::emoji_picker(element_id=\"new_content\", render_dialog=false) }}") (button - (text "{{ text \"general:action.save\" }}"))))) + (str (text "general:action.save")))))) (script (text "async function edit_post_from_form(e) { e.preventDefault(); diff --git a/crates/app/src/public/html/profile/base.lisp b/crates/app/src/public/html/profile/base.lisp index 72d9ebf..fdc6c1c 100644 --- a/crates/app/src/public/html/profile/base.lisp +++ b/crates/app/src/public/html/profile/base.lisp @@ -115,7 +115,7 @@ ("class" "fade") (text "{{ profile.username }}")))) (div - ("class" "card flex flex_col items_center gap_2") + ("class" "card flex flex_col items_center small gap_2") ("id" "social") (text "{% if profile.settings.status -%}") (p @@ -159,7 +159,20 @@ (div ("id" "bio") ("class" "card small no_p_margin") - (text "{{ profile.settings.biography|markdown|safe }}")) + (text "{{ profile.settings.biography|markdown|safe }}") + + (text "{% if profile.settings.location|length > 0 -%}") + (span ("class" "flex items_center gap_2") (icon (text "map-pin")) (text "{{ profile.settings.location }}")) + (text "{%- endif %}") + + (text "{% for link in profile.settings.links -%}") + (span + ("class" "flex items_center gap_2") + (icon (text "link")) + (a + ("href" "{{ link[1] }}") + (text "{{ link[0] }}"))) + (text "{%- endfor %}")) (div ("class" "card flex flex_col gap_2") (text "{% if user -%}") diff --git a/crates/app/src/public/html/profile/settings.lisp b/crates/app/src/public/html/profile/settings.lisp index 0a69f2b..7a91e0d 100644 --- a/crates/app/src/public/html/profile/settings.lisp +++ b/crates/app/src/public/html/profile/settings.lisp @@ -7,7 +7,7 @@ ; nav desktop (menu ("class" "desktop col") - (text "{{ macros::profile_settings_nav_options() }}")) + (text "{{ macros::user_settings_nav_options() }}")) ; content (main @@ -35,7 +35,7 @@ (span ("class" "current_tab_text") (text "account"))) (div ("class" "inner left") - (text "{{ macros::profile_settings_nav_options() }}")))) + (text "{{ macros::user_settings_nav_options() }}")))) ; ... (div @@ -43,81 +43,70 @@ ("data-tab" "presets") (div ("class" "card lowered flex flex_col gap_2") - (a - ("href" "#/account") - ("class" "button secondary") - (icon (text "arrow-left")) - (span - (str (text "general:action.back")))) - (div - ("class" "card_nest") + (p (text "Not sure where to start? Try some settings presets!")) + (details + ("class" "w_full accordion") + (summary + ("class" "button raised") + (icon (text "rss")) + (text "Microblogging")) + (div - ("class" "card flex items_center gap_2 small") - (icon (text "cooking-pot")) - (span - (str (text "settings:tab.presets")))) + ("class" "inner flex flex_col gap_2") + (p ("class" "fade") (text "Focus on yourself and your communities.")) + (ul ("id" "preset_microblogging_ul")) + (button + ("onclick" "apply_preset(PRESET_MICROBLOGGING)") + (icon (text "settings")) + (str (text "general:action.apply"))))) + + (details + ("class" "w_full accordion") + (summary + ("class" "button raised") + (icon (text "message-circle-heart")) + (text "Q&A")) + (div - ("class" "card flex flex_col gap_2 secondary") - (p (text "Not sure where to start? Try some settings presets!")) - (details - ("class" "w_full accordion") - (summary - (icon (text "rss")) - (text "Microblogging")) + ("class" "inner flex flex_col gap_2") + (p ("class" "fade") (text "Just like Neospring!")) + (ul ("id" "preset_questions_ul")) + (button + ("onclick" "apply_preset(PRESET_QUESTIONS)") + (icon (text "settings")) + (str (text "general:action.apply"))))) - (div - ("class" "inner flex flex_col gap_2") - (p ("class" "fade") (text "Focus on yourself and your communities.")) - (ul ("id" "preset_microblogging_ul")) - (button - ("onclick" "apply_preset(PRESET_MICROBLOGGING)") - (icon (text "settings")) - (str (text "general:action.apply"))))) + (details + ("class" "w_full accordion") + (summary + ("class" "button raised") + (icon (text "key")) + (text "Private")) - (details - ("class" "w_full accordion") - (summary - (icon (text "message-circle-heart")) - (text "Q&A")) + (div + ("class" "inner flex flex_col gap_2") + (p ("class" "fade") (text "This preset allows you to keep your profile and posts hidden to people you aren't following.")) + (ul ("id" "preset_private_ul")) + (button + ("onclick" "apply_preset(PRESET_PRIVATE)") + (icon (text "settings")) + (str (text "general:action.apply"))))) - (div - ("class" "inner flex flex_col gap_2") - (p ("class" "fade") (text "Just like Neospring!")) - (ul ("id" "preset_questions_ul")) - (button - ("onclick" "apply_preset(PRESET_QUESTIONS)") - (icon (text "settings")) - (str (text "general:action.apply"))))) + (details + ("class" "w_full accordion") + (summary + ("class" "button raised") + (icon (text "eye-closed")) + (text "NSFW")) - (details - ("class" "w_full accordion") - (summary - (icon (text "key")) - (text "Private")) - - (div - ("class" "inner flex flex_col gap_2") - (p ("class" "fade") (text "This preset allows you to keep your profile and posts hidden to people you aren't following.")) - (ul ("id" "preset_private_ul")) - (button - ("onclick" "apply_preset(PRESET_PRIVATE)") - (icon (text "settings")) - (str (text "general:action.apply"))))) - - (details - ("class" "w_full accordion") - (summary - (icon (text "eye-closed")) - (text "NSFW")) - - (div - ("class" "inner flex flex_col gap_2") - (p ("class" "fade") (text "NSFW content is allowed if it is hidden from main timelines. This preset will help you do that quickly.")) - (ul ("id" "preset_nsfw_ul")) - (button - ("onclick" "apply_preset(PRESET_NSFW)") - (icon (text "settings")) - (str (text "general:action.apply"))))))))) + (div + ("class" "inner flex flex_col gap_2") + (p ("class" "fade") (text "NSFW content is allowed if it is hidden from main timelines. This preset will help you do that quickly.")) + (ul ("id" "preset_nsfw_ul")) + (button + ("onclick" "apply_preset(PRESET_NSFW)") + (icon (text "settings")) + (str (text "general:action.apply"))))))) (div ("class" "w_full flex flex_col gap_2") @@ -180,61 +169,6 @@ (span (text "{{ text \"settings:tab.billing\" }}")))) (text "{%- endif %}") - - (div - ("class" "card_nest") - ("ui_ident" "home_timeline") - (div - ("class" "card small") - (b - (text "Home timeline"))) - (div - ("class" "card") - (select - ("onchange" "window.SETTING_SET_FUNCTIONS[0]('default_timeline', event.target.selectedOptions[0].value.startsWith('{') ? JSON.parse(event.target.selectedOptions[0].value) : event.target.selectedOptions[0].value)") - (option - ("value" "MyCommunities") - ("selected" "{% if home == '/' -%}true{% else %}false{%- endif %}") - (text "My communities")) - (option - ("value" "MyCommunitiesQuestions") - ("selected" "{% if home == '/questions' -%}true{% else %}false{%- endif %}") - (text "My communities (questions)")) - (option - ("value" "PopularPosts") - ("selected" "{% if home == '/popular' -%}true{% else %}false{%- endif %}") - (text "Popular")) - (option - ("value" "PopularQuestions") - ("selected" "{% if home == '/popular/questions' -%}true{% else %}false{%- endif %}") - (text "Popular (questions)")) - (option - ("value" "FollowingPosts") - ("selected" "{% if home == '/following' -%}true{% else %}false{%- endif %}") - (text "Following")) - (option - ("value" "FollowingQuestions") - ("selected" "{% if home == '/following/questions' -%}true{% else %}false{%- endif %}") - (text "Following (questions)")) - (option - ("value" "AllPosts") - ("selected" "{% if home == '/all' -%}true{% else %}false{%- endif %}") - (text "All")) - (option - ("value" "AllQuestions") - ("selected" "{% if home == '/all/questions' -%}true{% else %}false{%- endif %}") - (text "All (questions)")) - (text "{% for stack in stacks %}") - (text "") - (text "{% endfor %}")) - (span - ("class" "fade") - (text "This represents the timeline the home button takes you to.")))) (div ("class" "card_nest desktop") ("ui_ident" "notifications") @@ -282,7 +216,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))))) + (str (text "general:action.save"))))))) (div ("class" "card_nest") ("ui_ident" "delete_account") @@ -337,7 +271,7 @@ ("id" "save_button") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "w_full flex flex_col gap_2 hidden") ("data-tab" "account/security") @@ -444,7 +378,7 @@ (button (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}"))))))))) + (str (text "general:action.save")))))))))) (div ("class" "w_full flex flex_col gap_2 hidden") ("data-tab" "account/following") @@ -991,13 +925,13 @@ (span ("class" "fade") (text "Use an image of 1100x350px for the best results.")))) + (div ("class" "card_nest") ("ui_ident" "default_profile_page") (div ("class" "card small") - (b - (text "Default profile tab"))) + (b (text "Default profile tab"))) (div ("class" "card") (select @@ -1013,10 +947,36 @@ (span ("class" "fade") (text "This represents the timeline that is shown on your profile by default.")))) + + (div + ("class" "card_nest") + ("ui_ident" "user_links") + (div + ("class" "card small") + (b (text "My links"))) + (div + ("class" "card flex flex_col gap_2") + (button + ("onclick" "add_link()") + (icon (text "plus")) + (text "Add link")) + + (ul ("id" "user_links"))))) + (button + ("onclick" "save_settings()") + ("id" "save_button") + (icon (text "check")) + (span + (str (text "general:action.save"))))) + (div + ("class" "w_full hidden flex flex_col gap_2") + ("data-tab" "experience") + (div + ("class" "card lowered flex flex_col gap_2") + ("id" "experience_settings") (div ("class" "flex flex_col gap_2") ("ui_ident" "show_presets") - (hr ("class" "margin")) (div ("class" "card_nest") (div @@ -1028,13 +988,67 @@ (p (text "Quickly set up your account with ") (a ("href" "/settings#/presets") (text "settings presets")) - (text "!")))))) + (text "!"))))) + (div + ("class" "card_nest") + ("ui_ident" "home_timeline") + (div + ("class" "card small") + (b + (text "Home timeline"))) + (div + ("class" "card") + (select + ("onchange" "window.SETTING_SET_FUNCTIONS[0]('default_timeline', event.target.selectedOptions[0].value.startsWith('{') ? JSON.parse(event.target.selectedOptions[0].value) : event.target.selectedOptions[0].value)") + (option + ("value" "MyCommunities") + ("selected" "{% if home == '/' -%}true{% else %}false{%- endif %}") + (text "My communities")) + (option + ("value" "MyCommunitiesQuestions") + ("selected" "{% if home == '/questions' -%}true{% else %}false{%- endif %}") + (text "My communities (questions)")) + (option + ("value" "PopularPosts") + ("selected" "{% if home == '/popular' -%}true{% else %}false{%- endif %}") + (text "Popular")) + (option + ("value" "PopularQuestions") + ("selected" "{% if home == '/popular/questions' -%}true{% else %}false{%- endif %}") + (text "Popular (questions)")) + (option + ("value" "FollowingPosts") + ("selected" "{% if home == '/following' -%}true{% else %}false{%- endif %}") + (text "Following")) + (option + ("value" "FollowingQuestions") + ("selected" "{% if home == '/following/questions' -%}true{% else %}false{%- endif %}") + (text "Following (questions)")) + (option + ("value" "AllPosts") + ("selected" "{% if home == '/all' -%}true{% else %}false{%- endif %}") + (text "All")) + (option + ("value" "AllQuestions") + ("selected" "{% if home == '/all/questions' -%}true{% else %}false{%- endif %}") + (text "All (questions)")) + (text "{% for stack in stacks %}") + (text "") + (text "{% endfor %}")) + (span + ("class" "fade") + (text "This represents the timeline the home button takes you to."))))) (button ("onclick" "save_settings()") ("id" "save_button") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "card w_full lowered hidden flex flex_col gap_2") ("data-tab" "sessions") @@ -1193,7 +1207,7 @@ ("id" "save_button") (icon (text "check")) (span - (text "{{ text \"general:action.save\" }}")))) + (str (text "general:action.save"))))) (div ("class" "card w_full lowered hidden flex flex_col gap_2") ("data-tab" "grants") @@ -1595,7 +1609,7 @@ `data:image/png;base64,${qr}`; document.getElementById( \"totp_recovery_codes\", - ).innerText = recovery_codes.join(\"\n\"); + ).innerText = recovery_codes.join(\"\\n\"); document.getElementById(\"totp_stuff\").style.display = \"contents\"; @@ -1787,12 +1801,13 @@ document.getElementById(\"account_settings\"); const profile_settings = document.getElementById(\"profile_settings\"); + const experience_settings = + document.getElementById(\"experience_settings\"); const theme_settings = document.getElementById(\"theme_settings\"); ui.refresh_container(account_settings, [ \"supporter_ad\", \"account_settings_tabs\", - \"home_timeline\", \"notifications\", \"change_username\", \"delete_account\", @@ -1802,6 +1817,11 @@ \"change_avatar\", \"change_banner\", \"default_profile_page\", + \"user_links\", + ]); + ui.refresh_container(experience_settings, [ + \"supporter_ad\", + \"home_timeline\", \"show_presets\", ]); ui.refresh_container(theme_settings, [ @@ -1814,7 +1834,7 @@ ]); ui.generate_settings_ui( - account_settings, + profile_settings, [ [ [\"display_name\", \"Display name\"], @@ -1835,50 +1855,23 @@ 'This biography is only shown to users you are not following while your account is private.', }, ], + [ + [\"location\", \"Location\"], + \"{{ profile.settings.location }}\", + \"input\", + ], [[\"status\", \"Status\"], settings.status, \"textarea\"], [ [\"warning\", \"Profile warning\"], settings.warning, \"textarea\", ], - [[\"muted\", \"Muted phrases\"], settings.muted.join(\"\\n\"), \"textarea\", { - embed_html: - 'Muted phrases should all be on new lines.', - }], - [[], \"Accessibility\", \"title\"], - [ - [\"large_text\", \"Increase UI text size\"], - \"{{ profile.settings.large_text }}\", - \"checkbox\", - ], - [ - [\"use_system_font\", \"Always use system font instead\"], - \"{{ profile.settings.use_system_font }}\", - \"checkbox\", - ], - [ - [\"paged_timelines\", \"Make timelines paged instead of infinitely scrolled\"], - \"{{ profile.settings.paged_timelines }}\", - \"checkbox\", - ], - [ - [\"auto_clear_notifs\", \"Automatically clear all notifications when you open the notifications page\"], - \"{{ profile.settings.auto_clear_notifs }}\", - \"checkbox\", - ], ], settings, - { - muted: (new_muted) => { - settings.muted = new_muted - .split(\"\\n\") - .map((t) => t.trim()); - }, - }, ); ui.generate_settings_ui( - profile_settings, + experience_settings, [ [[], \"Privacy\", \"title\"], [ @@ -1988,6 +1981,10 @@ \"{{ profile.settings.hide_username_badges }}\", \"checkbox\", ], + [[\"muted\", \"Muted phrases\"], settings.muted.join(\"\\n\"), \"textarea\", { + embed_html: + 'Muted phrases should all be on new lines.', + }], [[], \"Questions\", \"title\"], [ [ @@ -2074,8 +2071,36 @@ \"{{ profile.settings.disable_achievements }}\", \"checkbox\", ], + [[], \"Accessibility\", \"title\"], + [ + [\"large_text\", \"Increase UI text size\"], + \"{{ profile.settings.large_text }}\", + \"checkbox\", + ], + [ + [\"use_system_font\", \"Always use system font instead\"], + \"{{ profile.settings.use_system_font }}\", + \"checkbox\", + ], + [ + [\"paged_timelines\", \"Make timelines paged instead of infinitely scrolled\"], + \"{{ profile.settings.paged_timelines }}\", + \"checkbox\", + ], + [ + [\"auto_clear_notifs\", \"Automatically clear all notifications when you open the notifications page\"], + \"{{ profile.settings.auto_clear_notifs }}\", + \"checkbox\", + ], ], settings, + { + muted: (new_muted) => { + settings.muted = new_muted + .split(\"\\n\") + .map((t) => t.trim()); + }, + }, ); const can_use_custom_css = @@ -2351,5 +2376,40 @@ anchor.click(); anchor.remove(); }; + + // links + function render_links() { + document.getElementById(\"user_links\").innerHTML = \"\"; + + let i = 0; + for (const link of settings.links) { + document.getElementById(\"user_links\").innerHTML += `