diff --git a/app/assets/javascripts/admin/addon/components/schema-theme-setting/editor.gjs b/app/assets/javascripts/admin/addon/components/schema-theme-setting/editor.gjs index c7660b23d90..bbdbf4efc14 100644 --- a/app/assets/javascripts/admin/addon/components/schema-theme-setting/editor.gjs +++ b/app/assets/javascripts/admin/addon/components/schema-theme-setting/editor.gjs @@ -5,8 +5,10 @@ import { on } from "@ember/modifier"; import { action } from "@ember/object"; import { LinkTo } from "@ember/routing"; import { service } from "@ember/service"; +import { gt } from "truth-helpers"; import DButton from "discourse/components/d-button"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import dIcon from "discourse-common/helpers/d-icon"; import i18n from "discourse-common/helpers/i18n"; import { cloneJSON } from "discourse-common/lib/object"; import I18n from "discourse-i18n"; @@ -77,7 +79,7 @@ export default class SchemaThemeSettingEditor extends Component { const subtree = new Tree(); subtree.propertyName = childObjectsProperty.name; - data[index][childObjectsProperty.name].forEach( + data[index][childObjectsProperty.name]?.forEach( (childObj, childIndex) => { subtree.nodes.push( new Node({ @@ -224,68 +226,99 @@ export default class SchemaThemeSettingEditor extends Component { } } diff --git a/app/assets/javascripts/admin/addon/templates/customize-themes-show-schema.hbs b/app/assets/javascripts/admin/addon/templates/customize-themes-show-schema.hbs index 7ae2afb44fb..d8b3e2eaaad 100644 --- a/app/assets/javascripts/admin/addon/templates/customize-themes-show-schema.hbs +++ b/app/assets/javascripts/admin/addon/templates/customize-themes-show-schema.hbs @@ -1,3 +1,12 @@ +
+

+ {{i18n + "admin.customize.theme.schema.title" + (hash name=@model.setting.setting) + }} +

+
+ { - const li = container.querySelector(".parent.node"); - const active = li.classList.contains("active"); - const children = [...container.querySelectorAll(".node.child")].map( - (child) => { - return { - text: child.textContent.trim(), - element: child, - }; - } + this.nodes = [ + ...queryAll( + ".schema-theme-setting-editor__tree .schema-theme-setting-editor__tree-node.--parent" + ), + ].map((container, index) => { + const li = container; + const active = li.classList.contains("--active"); + + const children = [ + ...queryAll( + `.schema-theme-setting-editor__tree-node.--child[data-test-parent-index="${index}"]:not(.--heading)` + ), + ].map((child) => { + return { + element: child, + textElement: child.querySelector( + ".schema-theme-setting-editor__tree-node-text" + ), + }; + }); + + const childrenHeaderElement = query( + `.schema-theme-setting-editor__tree-node.--heading[data-test-parent-index="${index}"]` ); return { - text: li.textContent.trim(), active, children, + childrenHeaderElement, element: li, + textElement: li.querySelector( + ".schema-theme-setting-editor__tree-node-text" + ), }; }); } @@ -85,6 +101,8 @@ module( const tree = new TreeFromDOM(); assert.true(tree.nodes[0].active); + assert.dom(tree.nodes[0].childrenHeaderElement).hasText("children"); + assert.strictEqual( tree.nodes[0].children.length, 2, @@ -127,12 +145,12 @@ module( const tree = new TreeFromDOM(); assert.strictEqual(tree.nodes.length, 2); - assert.strictEqual(tree.nodes[0].text, "item 1"); + assert.dom(tree.nodes[0].textElement).hasText("item 1"); assert.strictEqual(tree.nodes[0].children.length, 2); - assert.strictEqual(tree.nodes[0].children[0].text, "child 1-1"); - assert.strictEqual(tree.nodes[0].children[1].text, "child 1-2"); + assert.dom(tree.nodes[0].children[0].textElement).hasText("child 1-1"); + assert.dom(tree.nodes[0].children[1].textElement).hasText("child 1-2"); - assert.strictEqual(tree.nodes[1].text, "item 2"); + assert.dom(tree.nodes[1].textElement).hasText("item 2"); assert.strictEqual(tree.nodes[1].children.length, 0); await click(tree.nodes[1].element); @@ -140,35 +158,47 @@ module( tree.refresh(); assert.strictEqual(tree.nodes.length, 2); - assert.strictEqual(tree.nodes[0].text, "item 1"); + assert.dom(tree.nodes[0].textElement).hasText("item 1"); assert.false(tree.nodes[0].active); assert.strictEqual(tree.nodes[0].children.length, 0); - assert.strictEqual(tree.nodes[1].text, "item 2"); + assert.dom(tree.nodes[1].textElement).hasText("item 2"); assert.true(tree.nodes[1].active); assert.strictEqual(tree.nodes[1].children.length, 3); - assert.strictEqual(tree.nodes[1].children[0].text, "child 2-1"); - assert.strictEqual(tree.nodes[1].children[1].text, "child 2-2"); - assert.strictEqual(tree.nodes[1].children[2].text, "child 2-3"); + assert.dom(tree.nodes[1].children[0].textElement).hasText("child 2-1"); + assert.dom(tree.nodes[1].children[1].textElement).hasText("child 2-2"); + assert.dom(tree.nodes[1].children[2].textElement).hasText("child 2-3"); await click(tree.nodes[1].children[1].element); tree.refresh(); assert.strictEqual(tree.nodes.length, 3); - assert.strictEqual(tree.nodes[0].text, "child 2-1"); + assert.dom(tree.nodes[0].textElement).hasText("child 2-1"); assert.false(tree.nodes[0].active); assert.strictEqual(tree.nodes[0].children.length, 0); - assert.strictEqual(tree.nodes[1].text, "child 2-2"); + assert.dom(tree.nodes[1].textElement).hasText("child 2-2"); assert.true(tree.nodes[1].active); assert.strictEqual(tree.nodes[1].children.length, 4); - assert.strictEqual(tree.nodes[1].children[0].text, "grandchild 2-2-1"); - assert.strictEqual(tree.nodes[1].children[1].text, "grandchild 2-2-2"); - assert.strictEqual(tree.nodes[1].children[2].text, "grandchild 2-2-3"); - assert.strictEqual(tree.nodes[1].children[3].text, "grandchild 2-2-4"); - assert.strictEqual(tree.nodes[2].text, "child 2-3"); + assert + .dom(tree.nodes[1].children[0].textElement) + .hasText("grandchild 2-2-1"); + + assert + .dom(tree.nodes[1].children[1].textElement) + .hasText("grandchild 2-2-2"); + + assert + .dom(tree.nodes[1].children[2].textElement) + .hasText("grandchild 2-2-3"); + + assert + .dom(tree.nodes[1].children[3].textElement) + .hasText("grandchild 2-2-4"); + + assert.dom(tree.nodes[2].textElement).hasText("child 2-3"); assert.false(tree.nodes[2].active); assert.strictEqual(tree.nodes[2].children.length, 0); @@ -178,19 +208,19 @@ module( assert.strictEqual(tree.nodes.length, 4); - assert.strictEqual(tree.nodes[0].text, "grandchild 2-2-1"); + assert.dom(tree.nodes[0].textElement).hasText("grandchild 2-2-1"); assert.false(tree.nodes[0].active); assert.strictEqual(tree.nodes[0].children.length, 0); - assert.strictEqual(tree.nodes[1].text, "grandchild 2-2-2"); + assert.dom(tree.nodes[1].textElement).hasText("grandchild 2-2-2"); assert.true(tree.nodes[1].active); assert.strictEqual(tree.nodes[1].children.length, 0); - assert.strictEqual(tree.nodes[2].text, "grandchild 2-2-3"); + assert.dom(tree.nodes[2].textElement).hasText("grandchild 2-2-3"); assert.false(tree.nodes[2].active); assert.strictEqual(tree.nodes[2].children.length, 0); - assert.strictEqual(tree.nodes[3].text, "grandchild 2-2-4"); + assert.dom(tree.nodes[3].textElement).hasText("grandchild 2-2-4"); assert.false(tree.nodes[3].active); assert.strictEqual(tree.nodes[3].children.length, 0); }); @@ -202,32 +232,36 @@ module( ); - assert.dom(".back-button").doesNotExist(); + assert + .dom(".schema-theme-setting-editor__tree-node--back-btn") + .doesNotExist(); const tree = new TreeFromDOM(); await click(tree.nodes[0].children[0].element); - assert.dom(".back-button").exists(); + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").exists(); tree.refresh(); - assert.strictEqual(tree.nodes[0].text, "child 1-1"); + assert.dom(tree.nodes[0].textElement).hasText("child 1-1"); await click(tree.nodes[0].children[0].element); tree.refresh(); - assert.strictEqual(tree.nodes[0].text, "grandchild 1-1-1"); - assert.dom(".back-button").exists(); + assert.dom(tree.nodes[0].textElement).hasText("grandchild 1-1-1"); + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").exists(); - await click(".back-button"); + await click(".schema-theme-setting-editor__tree-node--back-btn"); tree.refresh(); - assert.strictEqual(tree.nodes[0].text, "child 1-1"); - assert.dom(".back-button").exists(); + assert.dom(tree.nodes[0].textElement).hasText("child 1-1"); + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").exists(); - await click(".back-button"); + await click(".schema-theme-setting-editor__tree-node--back-btn"); tree.refresh(); - assert.strictEqual(tree.nodes[0].text, "item 1"); - assert.dom(".back-button").doesNotExist(); + assert.dom(tree.nodes[0].textElement).hasText("item 1"); + assert + .dom(".schema-theme-setting-editor__tree-node--back-btn") + .doesNotExist(); }); test("the back button navigates to the index of the active element at the previous level", async function (assert) { @@ -243,16 +277,16 @@ module( tree.refresh(); await click(tree.nodes[1].children[1].element); - await click(".back-button"); + await click(".schema-theme-setting-editor__tree-node--back-btn"); tree.refresh(); assert.strictEqual(tree.nodes.length, 2); - assert.strictEqual(tree.nodes[0].text, "item 1"); + assert.dom(tree.nodes[0].textElement).hasText("item 1"); assert.false(tree.nodes[0].active); assert.strictEqual(tree.nodes[0].children.length, 0); - assert.strictEqual(tree.nodes[1].text, "item 2"); + assert.dom(tree.nodes[1].textElement).hasText("item 2"); assert.true(tree.nodes[1].active); assert.strictEqual(tree.nodes[1].children.length, 3); }); @@ -270,7 +304,7 @@ module( tree.refresh(); await click(tree.nodes[1].children[1].element); - assert.dom(".back-button").hasText( + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").hasText( I18n.t("admin.customize.theme.schema.back_button", { name: "item 2", }) @@ -279,15 +313,15 @@ module( tree.refresh(); await click(tree.nodes[1].children[0].element); - assert.dom(".back-button").hasText( + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").hasText( I18n.t("admin.customize.theme.schema.back_button", { name: "child 2-2", }) ); - await click(".back-button"); + await click(".schema-theme-setting-editor__tree-node--back-btn"); - assert.dom(".back-button").hasText( + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").hasText( I18n.t("admin.customize.theme.schema.back_button", { name: "item 2", }) @@ -377,11 +411,12 @@ module( assert.dom(inputFields.fields.text.labelElement).hasText("text"); assert.dom(inputFields.fields.url.labelElement).hasText("url"); assert.dom(inputFields.fields.icon.labelElement).hasText("icon"); - assert.dom(inputFields.fields.text.inputElement).hasValue("About"); + assert .dom(inputFields.fields.url.inputElement) .hasValue("https://example.com/about"); + assert.dom(inputFields.fields.icon.inputElement).hasValue("asterisk"); }); @@ -657,16 +692,16 @@ module( const tree = new TreeFromDOM(); - assert.dom(tree.nodes[0].element).hasText("section 1"); - assert.dom(tree.nodes[0].children[0].element).hasText("link 1"); - assert.dom(tree.nodes[0].children[1].element).hasText("link 2"); - assert.dom(tree.nodes[1].element).hasText("section 2"); + assert.dom(tree.nodes[0].textElement).hasText("section 1"); + assert.dom(tree.nodes[0].children[0].textElement).hasText("link 1"); + assert.dom(tree.nodes[0].children[1].textElement).hasText("link 2"); + assert.dom(tree.nodes[1].textElement).hasText("section 2"); await click(tree.nodes[1].element); tree.refresh(); - assert.dom(tree.nodes[1].children[0].element).hasText("link 1"); + assert.dom(tree.nodes[1].children[0].textElement).hasText("link 1"); }); test("identifier field instantly updates in the navigation tree when the input field is changed", async function (assert) { @@ -684,7 +719,9 @@ module( "nice section is really nice" ); - assert.dom(tree.nodes[0].element).hasText("nice section is really nice"); + assert + .dom(tree.nodes[0].textElement) + .hasText("nice section is really nice"); await click(tree.nodes[0].children[0].element); @@ -696,7 +733,9 @@ module( "Security instead of Privacy" ); - assert.dom(tree.nodes[0].element).hasText("Security instead of Privacy"); + assert + .dom(tree.nodes[0].textElement) + .hasText("Security instead of Privacy"); }); test("edits are remembered when navigating between levels", async function (assert) { @@ -729,26 +768,26 @@ module( tree.refresh(); inputFields.refresh(); - assert.dom(".back-button").hasText( + assert.dom(".schema-theme-setting-editor__tree-node--back-btn").hasText( I18n.t("admin.customize.theme.schema.back_button", { name: "cool section is no longer cool", }) ); await fillIn(inputFields.fields.text.inputElement, "Talk to us"); - - await click(".back-button"); + await click(".schema-theme-setting-editor__tree-node--back-btn"); tree.refresh(); inputFields.refresh(); - assert.dom(tree.nodes[0].element).hasText("changed section name"); + assert.dom(tree.nodes[0].textElement).hasText("changed section name"); + assert - .dom(tree.nodes[1].element) + .dom(tree.nodes[1].textElement) .hasText("cool section is no longer cool"); - assert.dom(tree.nodes[1].children[0].element).hasText("About"); - assert.dom(tree.nodes[1].children[1].element).hasText("Talk to us"); + assert.dom(tree.nodes[1].children[0].textElement).hasText("About"); + assert.dom(tree.nodes[1].children[1].textElement).hasText("Talk to us"); assert .dom(inputFields.fields.name.inputElement) diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index 441e88c6e16..1eb9c6a4062 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -1068,6 +1068,8 @@ a.inline-editable-field { @import "common/admin/admin_intro"; @import "common/admin/admin_emojis"; @import "common/admin/mini_profiler"; +@import "common/admin/schema_theme_setting_editor"; +@import "common/admin/customize_themes_show_schema"; // EXPERIMENTAL: Revamped admin styles, probably can be split up later down the line. @import "common/admin/admin_revamp"; diff --git a/app/assets/stylesheets/common/admin/customize_themes_show_schema.scss b/app/assets/stylesheets/common/admin/customize_themes_show_schema.scss new file mode 100644 index 00000000000..47d4fe005dc --- /dev/null +++ b/app/assets/stylesheets/common/admin/customize_themes_show_schema.scss @@ -0,0 +1,3 @@ +.customize-themes-show-schema__header { + margin-bottom: 1em; +} diff --git a/app/assets/stylesheets/common/admin/schema_theme_setting_editor.scss b/app/assets/stylesheets/common/admin/schema_theme_setting_editor.scss new file mode 100644 index 00000000000..8d0df542b0c --- /dev/null +++ b/app/assets/stylesheets/common/admin/schema_theme_setting_editor.scss @@ -0,0 +1,76 @@ +.schema-theme-setting-editor { + display: grid; + grid-template-columns: 0.2fr 0.8fr; + + &__navigation { + margin-right: 2em; + + ul { + list-style: none; + } + + .schema-theme-setting-editor__tree { + margin: 0; + + .schema-theme-setting-editor__tree-node--back-btn { + cursor: pointer; + width: 100%; + text-align: left; + + .schema-theme-setting-editor__tree-node-text { + .d-icon { + margin-left: 0; + margin-right: 0.5em; + } + } + } + + .schema-theme-setting-editor__tree-node-text { + padding: 0.5em; + color: var(--primary); + display: flex; + flex-direction: row; + align-items: center; + + .d-icon { + margin-left: auto; + font-size: var(--font-down-3); + color: var(--primary-500); + } + } + + .schema-theme-setting-editor__tree-node { + cursor: pointer; + + &.--active { + > .schema-theme-setting-editor__tree-node-text { + background-color: var(--tertiary); + color: var(--secondary); + + .d-icon { + color: var(--secondary); + } + } + } + + &.--child { + margin-left: 0.5em; + border-left: 1.5px solid var(--primary-200); + } + + &.--heading { + cursor: default; + margin-top: 0.5em; + font-weight: bold; + } + } + } + } + + &__fields { + } + + &__footer { + margin-top: 0.5em; + } +} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index f4c5e5313c8..e724d53c0ee 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5643,6 +5643,7 @@ en: inactive_filter: "Inactive" updates_available_filter: "Updates Available" schema: + title: "Edit %{name} setting" back_button: "Back to %{name}" colors: select_base: diff --git a/spec/system/page_objects/pages/admin_objects_theme_setting_editor.rb b/spec/system/page_objects/pages/admin_objects_theme_setting_editor.rb index 7aef609d92c..a4f26266ac0 100644 --- a/spec/system/page_objects/pages/admin_objects_theme_setting_editor.rb +++ b/spec/system/page_objects/pages/admin_objects_theme_setting_editor.rb @@ -17,7 +17,11 @@ module PageObjects end def click_link(name) - find(".schema-editor-navigation .node", text: name).click + find( + ".schema-theme-setting-editor__navigation .schema-theme-setting-editor__tree-node", + text: name, + ).click + self end