From 93a87b56460393033ee672d31e8da12d57739395 Mon Sep 17 00:00:00 2001 From: newt Date: Tue, 22 Feb 2022 13:27:12 +0000 Subject: [PATCH 001/289] Add status check. --- src/services/entity_normalizer/entity_normalizer.service.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index f219c161..bd7f7ea5 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -380,7 +380,9 @@ export const parseNotification = (data) => { if (masto) { output.type = mastoDict[data.type] || data.type output.seen = data.pleroma.is_seen - output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null + // TODO: null check should be a temporary fix, I guess. + // Investigate why backend does this. + output.status = isStatusNotification(output.type) && data.status !== null ? parseStatus(data.status) : null output.action = output.status // TODO: Refactor, this is unneeded output.target = output.type !== 'move' ? null From 1bf256b34b020622718d4dcdcae4153a6f75e060 Mon Sep 17 00:00:00 2001 From: Xnuk Shuman Date: Tue, 20 Dec 2022 02:03:35 +0900 Subject: [PATCH 002/289] use normal checkbox component label in announcement --- src/components/announcement_editor/announcement_editor.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/announcement_editor/announcement_editor.vue b/src/components/announcement_editor/announcement_editor.vue index 0f29f9f7..32b05bb2 100644 --- a/src/components/announcement_editor/announcement_editor.vue +++ b/src/components/announcement_editor/announcement_editor.vue @@ -32,8 +32,9 @@ id="announcement-all-day" v-model="announcement.allDay" :disabled="disabled" - /> - + > + {{ $t('announcements.all_day_prompt') }} + From f8a0cd2dd3e298b2a771d786033a7c29df8dcbfc Mon Sep 17 00:00:00 2001 From: Xnuk Shuman Date: Tue, 20 Dec 2022 02:34:11 +0900 Subject: [PATCH 003/289] vertical centering the checkbox --- src/components/checkbox/checkbox.vue | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index b6768d67..d7839e82 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,20 +39,23 @@ export default { display: inline-block; min-height: 1.2em; + & > * { + vertical-align: middle; + } + &-indicator { + display: inline-block; position: relative; - padding-left: 1.2em; + width: 1.2em; + height: 1.2em; } &-indicator::before { position: absolute; - right: 0; - top: 0; + inset: 0; display: block; content: '✓'; transition: color 200ms; - width: 1.1em; - height: 1.1em; border-radius: $fallback--checkboxRadius; border-radius: var(--checkboxRadius, $fallback--checkboxRadius); box-shadow: 0px 0px 2px black inset; From 7d90c594fe9530e8f483c6912ffcb80319934a8c Mon Sep 17 00:00:00 2001 From: tusooa Date: Fri, 6 Jan 2023 13:52:49 -0500 Subject: [PATCH 004/289] Make in-reply-to i18n-friendly --- src/components/status/status.vue | 83 ++++++++++++++++++-------------- src/i18n/en.json | 2 + 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 82eb7ac6..2a394610 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -257,44 +257,57 @@ v-if="isReply" class="glued-label reply-glued-label" > - - - + + - - {{ $t('status.reply_to') }} - - + + {{ $t('status.reply_to') }} + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 1ee1147a..e98b1d4c 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -853,6 +853,8 @@ "unbookmark": "Unbookmark", "delete_confirm": "Do you really want to delete this status?", "reply_to": "Reply to", + "reply_to_with_icon": "{icon} {replyTo}", + "reply_to_with_arg": "{replyToWithIcon} {user}", "mentions": "Mentions", "replies_list": "Replies:", "replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):", From 1506d2421d9a16867c5d3f39fbbc650952c2849a Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 28 Jan 2023 21:44:24 -0500 Subject: [PATCH 005/289] Get rid of * --- src/components/checkbox/checkbox.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index cbebe578..6c23d9e4 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,7 +39,7 @@ export default { display: inline-block; min-height: 1.2em; - & > * { + .checkbox-indicator, .label { vertical-align: middle; } From f7daaead6f16d87aef5a6a26fa8f8cfe7f7caf10 Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 28 Jan 2023 21:54:08 -0500 Subject: [PATCH 006/289] Fix stylelint --- src/components/checkbox/checkbox.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index 6c23d9e4..32c8f79c 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,7 +39,8 @@ export default { display: inline-block; min-height: 1.2em; - .checkbox-indicator, .label { + &-indicator, + & .label { vertical-align: middle; } From 0dd343f2d40939900d12f8c42c5c7d4d6be97f63 Mon Sep 17 00:00:00 2001 From: Brian Underwood Date: Tue, 7 Feb 2023 21:48:57 +0100 Subject: [PATCH 007/289] Specs for the gallery component --- test/unit/specs/components/gallery.spec.js | 276 +++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 test/unit/specs/components/gallery.spec.js diff --git a/test/unit/specs/components/gallery.spec.js b/test/unit/specs/components/gallery.spec.js new file mode 100644 index 00000000..108e2b6b --- /dev/null +++ b/test/unit/specs/components/gallery.spec.js @@ -0,0 +1,276 @@ +import Gallery from 'src/components/gallery/gallery.vue' + +describe.only('Gallery', () => { + let local + + it('attachments is falsey', () => { + local = { attachments: false } + expect(Gallery.computed.rows.call(local)).to.eql([]) + + local = { attachments: null } + expect(Gallery.computed.rows.call(local)).to.eql([]) + + local = { attachments: undefined } + expect(Gallery.computed.rows.call(local)).to.eql([]) + }) + + it('no attachments', () => { + local = { attachments: [] } + expect(Gallery.computed.rows.call(local)).to.eql([]) + }) + + it('one audio attachment', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) + + it('one image attachment', () => { + local = { + attachments: [ + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/png' }] } + ]) + }) + + it('one audio attachment and one image attachment', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] } + ]) + }) + + it('has "size" key set to "hide"', () => { + let local + local = { + attachments: [ + { mimetype: 'audio/mpeg' } + ], + size: 'hide' + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' } + ], + size: 'hide' + } + + // When defining `size: hide`, the `items` aren't + // grouped and `audio` isn't set + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] } + ]) + }) + + // types other than image or audio should be `minimal` + it('non-image/audio', () => { + let local + local = { + attachments: [ + { mimetype: 'plain/text' } + ] + } + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'plain/text' }] } + ]) + + // No grouping of non-image/audio items + local = { + attachments: [ + { mimetype: 'plain/text' }, + { mimetype: 'plain/text' }, + { mimetype: 'plain/text' } + ] + } + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/png' }, + { mimetype: 'plain/text' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' } + ] + } + // NOTE / TODO: When defining `size: hide`, the `items` aren't + // grouped and `audio` isn't set + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { items: [{ mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) + + it('mixed attachments', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }, { mimetype: 'image/jpg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' } + ] + } + + // Group by three-per-row, unless there's one dangling, then stick it on the end of the last row + // https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1785#note_98514 + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/png' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }] } + ]) + }) + + it('does not do grouping when grid is set', () => { + const attachments = [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' } + ] + + local = { grid: true, attachments } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { grid: true, items: attachments } + ]) + }) + + it('limit is set', () => { + const attachments = [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' } + ] + + let local + local = { attachments, limit: 2 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] } + ]) + + local = { attachments, limit: 3 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }, { mimetype: 'image/jpg' }] } + ]) + + local = { attachments, limit: 4 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) +}) From 84cab03a1d2643481bdb686d839a95973788ae02 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Thu, 9 Nov 2023 08:27:58 +0100 Subject: [PATCH 008/289] Extract backend repository from nodeinfo Also removes extractCommit, could be kept when the forge is git.pleroma.social Partial fix of https://git.pleroma.social/pleroma/pleroma-fe/-/issues/1283 --- changelog.d/backend-repo-url.skip | 0 src/boot/after_store.js | 3 ++- src/components/settings_modal/tabs/version_tab.js | 7 +------ src/components/settings_modal/tabs/version_tab.vue | 2 +- src/modules/instance.js | 1 + src/services/version/version.service.js | 6 ------ .../specs/services/version/version.service.spec.js | 11 ----------- 7 files changed, 5 insertions(+), 25 deletions(-) create mode 100644 changelog.d/backend-repo-url.skip delete mode 100644 src/services/version/version.service.js delete mode 100644 test/unit/specs/services/version/version.service.spec.js diff --git a/changelog.d/backend-repo-url.skip b/changelog.d/backend-repo-url.skip new file mode 100644 index 00000000..e69de29b diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 395d4834..aa204f53 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -242,7 +242,7 @@ const resolveStaffAccounts = ({ store, accounts }) => { const getNodeInfo = async ({ store }) => { try { - const res = await preloadFetch('/nodeinfo/2.0.json') + const res = await preloadFetch('/nodeinfo/2.1.json') if (res.ok) { const data = await res.json() const metadata = data.metadata @@ -277,6 +277,7 @@ const getNodeInfo = async ({ store }) => { const software = data.software store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) + store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository }) store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) const priv = metadata.private diff --git a/src/components/settings_modal/tabs/version_tab.js b/src/components/settings_modal/tabs/version_tab.js index 616bdadf..20a67173 100644 --- a/src/components/settings_modal/tabs/version_tab.js +++ b/src/components/settings_modal/tabs/version_tab.js @@ -1,22 +1,17 @@ -import { extractCommit } from 'src/services/version/version.service' - const pleromaFeCommitUrl = 'https://git.pleroma.social/pleroma/pleroma-fe/commit/' -const pleromaBeCommitUrl = 'https://git.pleroma.social/pleroma/pleroma/commit/' const VersionTab = { data () { const instance = this.$store.state.instance return { backendVersion: instance.backendVersion, + backendRepository: instance.backendRepository, frontendVersion: instance.frontendVersion } }, computed: { frontendVersionLink () { return pleromaFeCommitUrl + this.frontendVersion - }, - backendVersionLink () { - return pleromaBeCommitUrl + extractCommit(this.backendVersion) } } } diff --git a/src/components/settings_modal/tabs/version_tab.vue b/src/components/settings_modal/tabs/version_tab.vue index 0330d49f..917a618e 100644 --- a/src/components/settings_modal/tabs/version_tab.vue +++ b/src/components/settings_modal/tabs/version_tab.vue @@ -7,7 +7,7 @@
  • {{ backendVersion }}
  • diff --git a/src/modules/instance.js b/src/modules/instance.js index 034348ff..f908f16c 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -141,6 +141,7 @@ const defaultState = { // Version Information backendVersion: '', + backendRepository: '', frontendVersion: '', pollsAvailable: false, diff --git a/src/services/version/version.service.js b/src/services/version/version.service.js deleted file mode 100644 index 2e11bf3a..00000000 --- a/src/services/version/version.service.js +++ /dev/null @@ -1,6 +0,0 @@ - -export const extractCommit = versionString => { - const regex = /-g(\w+)/i - const matches = versionString.match(regex) - return matches ? matches[1] : '' -} diff --git a/test/unit/specs/services/version/version.service.spec.js b/test/unit/specs/services/version/version.service.spec.js deleted file mode 100644 index 519145ee..00000000 --- a/test/unit/specs/services/version/version.service.spec.js +++ /dev/null @@ -1,11 +0,0 @@ -import { extractCommit } from 'src/services/version/version.service.js' - -describe('extractCommit', () => { - it('return short commit hash following "-g" characters', () => { - expect(extractCommit('1.0.0-45-g5e7aeebc')).to.eql('5e7aeebc') - }) - - it('return short commit hash without branch name', () => { - expect(extractCommit('1.0.0-45-g5e7aeebc-branch')).to.eql('5e7aeebc') - }) -}) From 112ca85d91be42b11c91bee25cdbe89c1d57beda Mon Sep 17 00:00:00 2001 From: Pleroma Renovate Bot Date: Wed, 20 Mar 2024 08:52:22 +0000 Subject: [PATCH 009/289] Update dependency @vue/babel-plugin-jsx to v1.2.2 --- package.json | 2 +- yarn.lock | 144 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 9470f059..940f9ae4 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@intlify/vue-i18n-loader": "5.0.1", "@ungap/event-target": "0.2.4", "@vue/babel-helper-vue-jsx-merge-props": "1.4.0", - "@vue/babel-plugin-jsx": "1.2.1", + "@vue/babel-plugin-jsx": "1.2.2", "@vue/compiler-sfc": "3.2.45", "@vue/test-utils": "2.2.8", "autoprefixer": "10.4.18", diff --git a/yarn.lock b/yarn.lock index 6dcdaa32..664aa8dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -46,6 +46,14 @@ "@babel/highlight" "^7.23.4" chalk "^2.4.2" +"@babel/code-frame@^7.24.1": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + "@babel/compat-data@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" @@ -173,14 +181,14 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== +"@babel/generator@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0" + integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A== dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" + "@babel/types" "^7.24.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" "@babel/helper-annotate-as-pure@^7.16.7": @@ -422,7 +430,7 @@ dependencies: "@babel/types" "^7.21.4" -"@babel/helper-module-imports@^7.22.15": +"@babel/helper-module-imports@~7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== @@ -711,6 +719,16 @@ chalk "^2.4.2" js-tokens "^4.0.0" +"@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.14.7": version "7.18.11" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.11.tgz#68bb07ab3d380affa9a3f96728df07969645d2d9" @@ -756,6 +774,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== +"@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a" + integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg== + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2" @@ -1465,6 +1488,15 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" +"@babel/template@^7.23.9": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" + "@babel/traverse@^7.18.10": version "7.18.10" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.10.tgz#37ad97d1cb00efa869b91dd5d1950f8a6cf0cb08" @@ -1561,19 +1593,19 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.23.7": - version "7.23.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" - integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== +"@babel/traverse@^7.23.9": + version "7.24.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" + integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" + "@babel/code-frame" "^7.24.1" + "@babel/generator" "^7.24.1" "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.23.0" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.6" - "@babel/types" "^7.23.6" + "@babel/parser" "^7.24.1" + "@babel/types" "^7.24.0" debug "^4.3.1" globals "^11.1.0" @@ -1663,7 +1695,7 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== @@ -1672,6 +1704,15 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.23.9", "@babel/types@^7.24.0": + version "7.24.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@chenfengyuan/vue-qrcode@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@chenfengyuan/vue-qrcode/-/vue-qrcode-2.0.0.tgz#8cd01f6fc528d471680ebe812ec47c830aea7e63" @@ -1866,6 +1907,15 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -1876,11 +1926,21 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + "@jridgewell/source-map@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" @@ -1899,7 +1959,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== -"@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1928,6 +1988,14 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.9": version "0.3.14" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" @@ -2225,37 +2293,37 @@ resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz#8d53a1e21347db8edbe54d339902583176de09f2" integrity sha512-JkqXfCkUDp4PIlFdDQ0TdXoIejMtTHP67/pvxlgeY+u5k3LEdKuWZ3LK6xkxo52uDoABIVyRwqVkfLQJhk7VBA== -"@vue/babel-helper-vue-transform-on@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.1.tgz#3a48da809025b9a0eb4f4b3030e0d316c40fac0a" - integrity sha512-jtEXim+pfyHWwvheYwUwSXm43KwQo8nhOBDyjrUITV6X2tB7lJm6n/+4sqR8137UVZZul5hBzWHdZ2uStYpyRQ== +"@vue/babel-helper-vue-transform-on@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.2.2.tgz#7f1f817a4f00ad531651a8d1d22e22d9e42807ef" + integrity sha512-nOttamHUR3YzdEqdM/XXDyCSdxMA9VizUKoroLX6yTyRtggzQMHXcmwh8a7ZErcJttIBIc9s68a1B8GZ+Dmvsw== -"@vue/babel-plugin-jsx@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.1.tgz#786c5395605a1d2463d6b10d8a7f3abdc01d25ce" - integrity sha512-Yy9qGktktXhB39QE99So/BO2Uwm/ZG+gpL9vMg51ijRRbINvgbuhyJEi4WYmGRMx/MSTfK0xjgZ3/MyY+iLCEg== +"@vue/babel-plugin-jsx@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.2.2.tgz#eb426fb4660aa510bb8d188ff0ec140405a97d8a" + integrity sha512-nYTkZUVTu4nhP199UoORePsql0l+wj7v/oyQjtThUVhJl1U+6qHuoVhIvR3bf7eVKjbCK+Cs2AWd7mi9Mpz9rA== dependencies: - "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-module-imports" "~7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-jsx" "^7.23.3" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.23.7" - "@babel/types" "^7.23.6" - "@vue/babel-helper-vue-transform-on" "1.2.1" - "@vue/babel-plugin-resolve-type" "1.2.1" + "@babel/template" "^7.23.9" + "@babel/traverse" "^7.23.9" + "@babel/types" "^7.23.9" + "@vue/babel-helper-vue-transform-on" "1.2.2" + "@vue/babel-plugin-resolve-type" "1.2.2" camelcase "^6.3.0" html-tags "^3.3.1" svg-tags "^1.0.0" -"@vue/babel-plugin-resolve-type@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.1.tgz#874fb3e02d033b3dd2e0fc883a3d1ceef0bdf39b" - integrity sha512-IOtnI7pHunUzHS/y+EG/yPABIAp0VN8QhQ0UCS09jeMVxgAnI9qdOzO85RXdQGxq+aWCdv8/+k3W0aYO6j/8fQ== +"@vue/babel-plugin-resolve-type@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.2.2.tgz#66844898561da6449e0f4a261b0c875118e0707b" + integrity sha512-EntyroPwNg5IPVdUJupqs0CFzuf6lUrVvCspmv2J1FITLeGnUCuoGNNk78dgCusxEiYj6RMkTJflGSxk5aIC4A== dependencies: "@babel/code-frame" "^7.23.5" - "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-module-imports" "~7.22.15" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/parser" "^7.23.6" + "@babel/parser" "^7.23.9" "@vue/compiler-sfc" "^3.4.15" "@vue/compiler-core@3.2.45": From 148796b26634d9e04e7265ad5e7287469b025b64 Mon Sep 17 00:00:00 2001 From: Pleroma Renovate Bot Date: Sat, 23 Mar 2024 09:09:00 +0000 Subject: [PATCH 010/289] Update dependency karma-firefox-launcher to v2.1.3 --- package.json | 2 +- yarn.lock | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cbbcb170..8eae6c79 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "json-loader": "0.5.7", "karma": "6.4.2", "karma-coverage": "2.2.0", - "karma-firefox-launcher": "2.1.2", + "karma-firefox-launcher": "2.1.3", "karma-mocha": "2.0.1", "karma-mocha-reporter": "2.2.5", "karma-sinon-chai": "2.0.2", diff --git a/yarn.lock b/yarn.lock index c42fe8fa..14c0316b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5966,13 +5966,13 @@ karma-coverage@2.2.0: istanbul-reports "^3.0.5" minimatch "^3.0.4" -karma-firefox-launcher@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz#9a38cc783c579a50f3ed2a82b7386186385cfc2d" - integrity sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA== +karma-firefox-launcher@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-2.1.3.tgz#b278a4cbffa92ab81394b1a398813847b0624a85" + integrity sha512-LMM2bseebLbYjODBOVt7TCPP9OI2vZIXCavIXhkO9m+10Uj5l7u/SKoeRmYx8FYHTVGZSpk6peX+3BMHC1WwNw== dependencies: is-wsl "^2.2.0" - which "^2.0.1" + which "^3.0.0" karma-mocha-reporter@2.2.5: version "2.2.5" @@ -9417,6 +9417,13 @@ which@^1.3.1: dependencies: isexe "^2.0.0" +which@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/which/-/which-3.0.1.tgz#89f1cd0c23f629a8105ffe69b8172791c87b4be1" + integrity sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg== + dependencies: + isexe "^2.0.0" + widest-line@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" From 2b3c76cfb46fd851a92bfc532a909fafbddf512b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 31 Jul 2024 18:15:08 +0300 Subject: [PATCH 011/289] changelog for 2.7.0 --- CHANGELOG.md | 55 +++++++++++++++++++ changelog.d/add-apng.add | 1 - changelog.d/admin-emoji-packs.add | 1 - changelog.d/appearance-tab.change | 1 - changelog.d/ci-runner.skip | 1 - changelog.d/create-link-when-url-present.add | 1 - changelog.d/double-notifications.fix | 1 - changelog.d/emoji-scale.add | 1 - changelog.d/extra-notifications.add | 1 - changelog.d/firefox-redmon.fix | 1 - changelog.d/fixes-themes.skip | 1 - changelog.d/fixes.skip | 1 - changelog.d/focus-clear.add | 1 - changelog.d/group-actor.add | 1 - changelog.d/hide-custom-emojis-in-picker.add | 1 - changelog.d/mobile-chrome-notifs.fix | 1 - .../mobile-drawer-notifications.change | 1 - .../more-notification-types-setting.fix | 1 - changelog.d/mute-nsfw.add | 1 - changelog.d/native-filtering.add | 1 - changelog.d/native-notifications.add | 1 - changelog.d/no-preserve-selection-color.fix | 1 - changelog.d/non-expiring-polls-indication.fix | 1 - changelog.d/noninteractive-ignore-read.add | 1 - changelog.d/notif-types.fix | 1 - changelog.d/notification-read.add | 1 - changelog.d/notifications-sorting.change | 1 - changelog.d/poll-ended-notifications.fix | 1 - changelog.d/preview-interference.skip | 1 - changelog.d/profile-mentions.fix | 1 - changelog.d/public-favorites.add | 1 - changelog.d/public-favorites.skip | 0 changelog.d/quotes-count.add | 1 - changelog.d/registration-notice.add | 1 - changelog.d/scrobbles-age-filter.add | 1 - changelog.d/serviceworkers.change | 1 - changelog.d/show-recent-scrobble.skip | 1 - changelog.d/status-loading-indicator.add | 1 - changelog.d/status-notification-type.add | 1 - changelog.d/theme-selector.add | 1 - changelog.d/themes3-cache.add | 1 - changelog.d/themes3-fixes.fix | 1 - changelog.d/themes3.change | 1 - changelog.d/themesv3-on-safari.fix | 1 - changelog.d/ui-scale.add | 1 - changelog.d/unreads-sync.fix | 1 - changelog.d/user-overrides.add | 1 - changelog.d/video-poster.fix | 1 - changelog.d/video-poster.update.skip | 1 - changelog.d/web-push-always.add | 1 - 50 files changed, 55 insertions(+), 48 deletions(-) delete mode 100644 changelog.d/add-apng.add delete mode 100644 changelog.d/admin-emoji-packs.add delete mode 100644 changelog.d/appearance-tab.change delete mode 100644 changelog.d/ci-runner.skip delete mode 100644 changelog.d/create-link-when-url-present.add delete mode 100644 changelog.d/double-notifications.fix delete mode 100644 changelog.d/emoji-scale.add delete mode 100644 changelog.d/extra-notifications.add delete mode 100644 changelog.d/firefox-redmon.fix delete mode 100644 changelog.d/fixes-themes.skip delete mode 100644 changelog.d/fixes.skip delete mode 100644 changelog.d/focus-clear.add delete mode 100644 changelog.d/group-actor.add delete mode 100644 changelog.d/hide-custom-emojis-in-picker.add delete mode 100644 changelog.d/mobile-chrome-notifs.fix delete mode 100644 changelog.d/mobile-drawer-notifications.change delete mode 100644 changelog.d/more-notification-types-setting.fix delete mode 100644 changelog.d/mute-nsfw.add delete mode 100644 changelog.d/native-filtering.add delete mode 100644 changelog.d/native-notifications.add delete mode 100644 changelog.d/no-preserve-selection-color.fix delete mode 100644 changelog.d/non-expiring-polls-indication.fix delete mode 100644 changelog.d/noninteractive-ignore-read.add delete mode 100644 changelog.d/notif-types.fix delete mode 100644 changelog.d/notification-read.add delete mode 100644 changelog.d/notifications-sorting.change delete mode 100644 changelog.d/poll-ended-notifications.fix delete mode 100644 changelog.d/preview-interference.skip delete mode 100644 changelog.d/profile-mentions.fix delete mode 100644 changelog.d/public-favorites.add delete mode 100644 changelog.d/public-favorites.skip delete mode 100644 changelog.d/quotes-count.add delete mode 100644 changelog.d/registration-notice.add delete mode 100644 changelog.d/scrobbles-age-filter.add delete mode 100644 changelog.d/serviceworkers.change delete mode 100644 changelog.d/show-recent-scrobble.skip delete mode 100644 changelog.d/status-loading-indicator.add delete mode 100644 changelog.d/status-notification-type.add delete mode 100644 changelog.d/theme-selector.add delete mode 100644 changelog.d/themes3-cache.add delete mode 100644 changelog.d/themes3-fixes.fix delete mode 100644 changelog.d/themes3.change delete mode 100644 changelog.d/themesv3-on-safari.fix delete mode 100644 changelog.d/ui-scale.add delete mode 100644 changelog.d/unreads-sync.fix delete mode 100644 changelog.d/user-overrides.add delete mode 100644 changelog.d/video-poster.fix delete mode 100644 changelog.d/video-poster.update.skip delete mode 100644 changelog.d/web-push-always.add diff --git a/CHANGELOG.md b/CHANGELOG.md index 444a863c..445308d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,61 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.7.0 + +### Known issues +We got some reports related to emoji picker performance, this hopefully will be fixed in 2.7.1. + +### Notes +This release overhauls how themes work, themes now need to be "compiled", which can cause some delay when loading for the first time and temporarily look "wrong" in some places (popups, menus, dialogs). Please do report any issues, especially if your theme looks wrong or breaks interface when loading. Also report issues if you're experiencing constant performance issues. + +To admins: remember that you can update PleromaFE to recent `master` or `develop` in admin dashboard in "Front-ends" tab, scroll down to find PleromaFE box and click "Reinstall `master`" or dropdown and then "Reinstall `develop`". Currently there is no mechanism to check if there is an update or not. + +### Changed +- Overhauled the way themes work, migrating to new Pleroma Interface Style Sheets system aka "Themes 3". +- Notifications are no longer sorted by "seen" status since interacting with them can change their read status and makes UI jumpy. Old behavior can be restored in settings. +- Notifications are now shown through a ServiceWorker (since mobile chrome does not allow them otherwise), it's always enabled, even if previously we only enabled it for WebPush notifications only. If you don't like websites "running" while closed, check how to disable them in your browser. Old way to show notifications will be used as a fallback but might not have all the new features. +- Reorganized Settings modal to move out visual stuff into Appearance tab + +### Added +- Emoji pack management to the admin panel +- Support `status` notification type (subscriptions/bell, fixes PleromaFE on newer PleromaBE versions) +- Poll end notifications. +- Added option to not mark all notifications when closing notifications drawer on mobile, this creates a new button to mark all as seen. +- Option to always "show" notifications when using web push for better compatibility with some browsers (chrome, edge, safari) +- Option to toggle what notification types appear in native notifications, by default less important ones (likes, repeats, etc) will no longer show up in native notifications. +- Option to treat non-interactive notifications (likes, repeats et all) as seen for visual purposes (no read mark, ignored in counters, still can show in native notifications) +- Ability to resize UI (and certain components) scale independent of browser/text scale +- Ability to override certain aspects of UI style independent of theme used (UI roundness, fonts, underlay) +- Theme selector with visual previews of the theme +- Display loading and error indicator for conversation page +- Option to only show scrobbles that are recent enough +- Interacting (opening reply box etc) or simply clicking on non-interactive notifications now marks them as read. Clicking on native notifications for non-interactive ones also marks them as seen. +- Support group actors +- Focusing into a tab clears all current desktop notifications +- Ability to change size of emoji +- Ability to view APNG (Animated PNG) attachments. +- Support showing extra notifications in the notifications column +- Create a link to the URL of the scrobble when it's present +- Allow hiding custom emojis in picker. +- Ability to mute sensitive posts (ported from eintei). +- Native notifications now also have "badge" property that matches instance's favicon (visible in Android Chromium at least) +- Display public favorites on user profiles +- Display quotes count on posts and add quotes list page +- Show a dedicated registration notice page when further action is required after registering + +### Fixed +- Synchronized requested notification types with backend, hopefully should fix missing notifications for polls and follow requests +- Error that appeared on mobile Chromium (and derivatives) when native notifications are allowed +- Being unable to set notification visibility for reports and follow requests +- Native notifications appearing as many times as there are open tabs. Clicking on notification will focus last focused tab. +- The expiry date indication won't be shown if the poll never expires +- Profile mentions causing a 422 error on newer PleromaBE versions. +- Color inputs are less ugly now +- Unread notifications should now properly catch up between sessions (eventually) in polling mode +- Video posters on Safari + + ## 2.6.1 ### Fixed - fix admin dashboard not having any feedback on frontend installation diff --git a/changelog.d/add-apng.add b/changelog.d/add-apng.add deleted file mode 100644 index cdec58af..00000000 --- a/changelog.d/add-apng.add +++ /dev/null @@ -1 +0,0 @@ -Make Pleroma FE to also view apng (Animated PNG) attachment. diff --git a/changelog.d/admin-emoji-packs.add b/changelog.d/admin-emoji-packs.add deleted file mode 100644 index 243163e8..00000000 --- a/changelog.d/admin-emoji-packs.add +++ /dev/null @@ -1 +0,0 @@ -Added emoji pack management to the admin panel diff --git a/changelog.d/appearance-tab.change b/changelog.d/appearance-tab.change deleted file mode 100644 index 7fe1b45e..00000000 --- a/changelog.d/appearance-tab.change +++ /dev/null @@ -1 +0,0 @@ -Reorganized Settings modal to move out visual stuff into Appearance tab diff --git a/changelog.d/ci-runner.skip b/changelog.d/ci-runner.skip deleted file mode 100644 index ad4b79d5..00000000 --- a/changelog.d/ci-runner.skip +++ /dev/null @@ -1 +0,0 @@ -stop using that one runner for intensive tasks \ No newline at end of file diff --git a/changelog.d/create-link-when-url-present.add b/changelog.d/create-link-when-url-present.add deleted file mode 100644 index 11aa3758..00000000 --- a/changelog.d/create-link-when-url-present.add +++ /dev/null @@ -1 +0,0 @@ -Create a link to the URL of the scrobble when it's present diff --git a/changelog.d/double-notifications.fix b/changelog.d/double-notifications.fix deleted file mode 100644 index 24e08c0f..00000000 --- a/changelog.d/double-notifications.fix +++ /dev/null @@ -1 +0,0 @@ -Fix native notifications appearing as many times as there are open tabs. Clicking on notification will focus last focused tab. diff --git a/changelog.d/emoji-scale.add b/changelog.d/emoji-scale.add deleted file mode 100644 index 791d80d9..00000000 --- a/changelog.d/emoji-scale.add +++ /dev/null @@ -1 +0,0 @@ -Ability to change size of emoji diff --git a/changelog.d/extra-notifications.add b/changelog.d/extra-notifications.add deleted file mode 100644 index 90f21f54..00000000 --- a/changelog.d/extra-notifications.add +++ /dev/null @@ -1 +0,0 @@ -Support showing extra notifications in the notifications column diff --git a/changelog.d/firefox-redmon.fix b/changelog.d/firefox-redmon.fix deleted file mode 100644 index 64ab9b14..00000000 --- a/changelog.d/firefox-redmon.fix +++ /dev/null @@ -1 +0,0 @@ -Bug with firefox and redmond themes diff --git a/changelog.d/fixes-themes.skip b/changelog.d/fixes-themes.skip deleted file mode 100644 index af691507..00000000 --- a/changelog.d/fixes-themes.skip +++ /dev/null @@ -1 +0,0 @@ -fixed themes for spw and kazvmoew diff --git a/changelog.d/fixes.skip b/changelog.d/fixes.skip deleted file mode 100644 index cc40793e..00000000 --- a/changelog.d/fixes.skip +++ /dev/null @@ -1 +0,0 @@ -fix post appearance tab bugs part I diff --git a/changelog.d/focus-clear.add b/changelog.d/focus-clear.add deleted file mode 100644 index 70f54ab6..00000000 --- a/changelog.d/focus-clear.add +++ /dev/null @@ -1 +0,0 @@ -Focusing into a tab clears all current desktop notifications diff --git a/changelog.d/group-actor.add b/changelog.d/group-actor.add deleted file mode 100644 index 7b62676a..00000000 --- a/changelog.d/group-actor.add +++ /dev/null @@ -1 +0,0 @@ -Support group actors diff --git a/changelog.d/hide-custom-emojis-in-picker.add b/changelog.d/hide-custom-emojis-in-picker.add deleted file mode 100644 index 4cfd2ca8..00000000 --- a/changelog.d/hide-custom-emojis-in-picker.add +++ /dev/null @@ -1 +0,0 @@ -Allow hiding custom emojis in picker. diff --git a/changelog.d/mobile-chrome-notifs.fix b/changelog.d/mobile-chrome-notifs.fix deleted file mode 100644 index 7db10c56..00000000 --- a/changelog.d/mobile-chrome-notifs.fix +++ /dev/null @@ -1 +0,0 @@ -Fixed error that appeared on mobile Chrome(ium) (and derivatives) when native notifications are allowed diff --git a/changelog.d/mobile-drawer-notifications.change b/changelog.d/mobile-drawer-notifications.change deleted file mode 100644 index 9353c709..00000000 --- a/changelog.d/mobile-drawer-notifications.change +++ /dev/null @@ -1 +0,0 @@ -Added option to not mark all notifications when closing notifications drawer on mobile, this creates a new button to mark all as seen. diff --git a/changelog.d/more-notification-types-setting.fix b/changelog.d/more-notification-types-setting.fix deleted file mode 100644 index 2d71b599..00000000 --- a/changelog.d/more-notification-types-setting.fix +++ /dev/null @@ -1 +0,0 @@ -Fixed being unable to set notification visibility for reports and follow requests diff --git a/changelog.d/mute-nsfw.add b/changelog.d/mute-nsfw.add deleted file mode 100644 index b1794a0c..00000000 --- a/changelog.d/mute-nsfw.add +++ /dev/null @@ -1 +0,0 @@ -Added ability to mute sensitive posts (ported from eintei) diff --git a/changelog.d/native-filtering.add b/changelog.d/native-filtering.add deleted file mode 100644 index 82ab9a23..00000000 --- a/changelog.d/native-filtering.add +++ /dev/null @@ -1 +0,0 @@ -Added option to toggle what notification types appear in native notifications, by default less important ones (likes, repeats, etc) will no longer show up in native notifications. diff --git a/changelog.d/native-notifications.add b/changelog.d/native-notifications.add deleted file mode 100644 index d896e7c0..00000000 --- a/changelog.d/native-notifications.add +++ /dev/null @@ -1 +0,0 @@ -Native notifications now also have "badge" property that matches instance's favicon (visible in Android Chromium at least) diff --git a/changelog.d/no-preserve-selection-color.fix b/changelog.d/no-preserve-selection-color.fix deleted file mode 100644 index 669e744c..00000000 --- a/changelog.d/no-preserve-selection-color.fix +++ /dev/null @@ -1 +0,0 @@ -Ensure selection text color has enough contrast diff --git a/changelog.d/non-expiring-polls-indication.fix b/changelog.d/non-expiring-polls-indication.fix deleted file mode 100644 index 7979cc13..00000000 --- a/changelog.d/non-expiring-polls-indication.fix +++ /dev/null @@ -1 +0,0 @@ -The expiry date indication won't be shown if the poll never expires diff --git a/changelog.d/noninteractive-ignore-read.add b/changelog.d/noninteractive-ignore-read.add deleted file mode 100644 index 5e8710cf..00000000 --- a/changelog.d/noninteractive-ignore-read.add +++ /dev/null @@ -1 +0,0 @@ -Added option to treat non-interactive notifications (likes, repeats et all) as seen for visual purposes (no read mark, ignored in counters, still can show in native notifications) diff --git a/changelog.d/notif-types.fix b/changelog.d/notif-types.fix deleted file mode 100644 index fb0e5046..00000000 --- a/changelog.d/notif-types.fix +++ /dev/null @@ -1 +0,0 @@ -Synchronized requested notification types with backend, hopefully should fix missing notifications for polls and follow requests diff --git a/changelog.d/notification-read.add b/changelog.d/notification-read.add deleted file mode 100644 index e5027a95..00000000 --- a/changelog.d/notification-read.add +++ /dev/null @@ -1 +0,0 @@ -Interacting (opening reply box etc) or simply clicking on non-interactive notifications now marks them as read. Clicking on native notifications for non-interactive ones also marks them as seen. diff --git a/changelog.d/notifications-sorting.change b/changelog.d/notifications-sorting.change deleted file mode 100644 index 3a616244..00000000 --- a/changelog.d/notifications-sorting.change +++ /dev/null @@ -1 +0,0 @@ -Notifications are no longer sorted by "seen" status since interacting with them can change their read status and makes UI jumpy. Old behavior can be restored in settings. diff --git a/changelog.d/poll-ended-notifications.fix b/changelog.d/poll-ended-notifications.fix deleted file mode 100644 index d04b8cb0..00000000 --- a/changelog.d/poll-ended-notifications.fix +++ /dev/null @@ -1 +0,0 @@ -Add poll end notifications to fetched types. diff --git a/changelog.d/preview-interference.skip b/changelog.d/preview-interference.skip deleted file mode 100644 index e32e76dd..00000000 --- a/changelog.d/preview-interference.skip +++ /dev/null @@ -1 +0,0 @@ -skip diff --git a/changelog.d/profile-mentions.fix b/changelog.d/profile-mentions.fix deleted file mode 100644 index 3f38ab0c..00000000 --- a/changelog.d/profile-mentions.fix +++ /dev/null @@ -1 +0,0 @@ -Fix profile mentions causing a 422 error diff --git a/changelog.d/public-favorites.add b/changelog.d/public-favorites.add deleted file mode 100644 index 183fcc85..00000000 --- a/changelog.d/public-favorites.add +++ /dev/null @@ -1 +0,0 @@ -Display public favorites on user profiles \ No newline at end of file diff --git a/changelog.d/public-favorites.skip b/changelog.d/public-favorites.skip deleted file mode 100644 index e69de29b..00000000 diff --git a/changelog.d/quotes-count.add b/changelog.d/quotes-count.add deleted file mode 100644 index 86779b96..00000000 --- a/changelog.d/quotes-count.add +++ /dev/null @@ -1 +0,0 @@ -Display quotes count on posts and add quotes list page \ No newline at end of file diff --git a/changelog.d/registration-notice.add b/changelog.d/registration-notice.add deleted file mode 100644 index b2777ba2..00000000 --- a/changelog.d/registration-notice.add +++ /dev/null @@ -1 +0,0 @@ -Show a dedicated registration notice page when further action is required after registering diff --git a/changelog.d/scrobbles-age-filter.add b/changelog.d/scrobbles-age-filter.add deleted file mode 100644 index ecd3c7d8..00000000 --- a/changelog.d/scrobbles-age-filter.add +++ /dev/null @@ -1 +0,0 @@ -Option to only show scrobbles that are recent enough diff --git a/changelog.d/serviceworkers.change b/changelog.d/serviceworkers.change deleted file mode 100644 index b3b64f6d..00000000 --- a/changelog.d/serviceworkers.change +++ /dev/null @@ -1 +0,0 @@ -Notifications are now shown through a serviceworker (since mobile chrome does not allow them otherwise), it's always enabled, even if previously we only enabled it for WebPush notifications only. If you don't like websites "running" while closed, check how to disable them in your browser. Old way to show notifications will be used as a fallback but might not have all the new features. diff --git a/changelog.d/show-recent-scrobble.skip b/changelog.d/show-recent-scrobble.skip deleted file mode 100644 index 9227de06..00000000 --- a/changelog.d/show-recent-scrobble.skip +++ /dev/null @@ -1 +0,0 @@ -Shows the most recent scrobble under each post when available diff --git a/changelog.d/status-loading-indicator.add b/changelog.d/status-loading-indicator.add deleted file mode 100644 index d0725677..00000000 --- a/changelog.d/status-loading-indicator.add +++ /dev/null @@ -1 +0,0 @@ -Display loading and error indicator for conversation page diff --git a/changelog.d/status-notification-type.add b/changelog.d/status-notification-type.add deleted file mode 100644 index 0917dad4..00000000 --- a/changelog.d/status-notification-type.add +++ /dev/null @@ -1 +0,0 @@ -Support `status` notification type \ No newline at end of file diff --git a/changelog.d/theme-selector.add b/changelog.d/theme-selector.add deleted file mode 100644 index c303f97c..00000000 --- a/changelog.d/theme-selector.add +++ /dev/null @@ -1 +0,0 @@ -Theme selector with visual previews of the theme diff --git a/changelog.d/themes3-cache.add b/changelog.d/themes3-cache.add deleted file mode 100644 index a275e44c..00000000 --- a/changelog.d/themes3-cache.add +++ /dev/null @@ -1 +0,0 @@ -Add caching system for themes3 diff --git a/changelog.d/themes3-fixes.fix b/changelog.d/themes3-fixes.fix deleted file mode 100644 index 15c31e82..00000000 --- a/changelog.d/themes3-fixes.fix +++ /dev/null @@ -1 +0,0 @@ -fix color inputs and some in-development themes3 issues diff --git a/changelog.d/themes3.change b/changelog.d/themes3.change deleted file mode 100644 index 5255f9b1..00000000 --- a/changelog.d/themes3.change +++ /dev/null @@ -1 +0,0 @@ -Overhauled the way themes work, migrating to new Pleroma Interface Style Sheets system. diff --git a/changelog.d/themesv3-on-safari.fix b/changelog.d/themesv3-on-safari.fix deleted file mode 100644 index af767b3a..00000000 --- a/changelog.d/themesv3-on-safari.fix +++ /dev/null @@ -1 +0,0 @@ -Fix Themes v3 on Safari not working diff --git a/changelog.d/ui-scale.add b/changelog.d/ui-scale.add deleted file mode 100644 index 594a9aa5..00000000 --- a/changelog.d/ui-scale.add +++ /dev/null @@ -1 +0,0 @@ -Ability to resize UI (and certain components) scale independent of browser/text scale diff --git a/changelog.d/unreads-sync.fix b/changelog.d/unreads-sync.fix deleted file mode 100644 index 1eac3364..00000000 --- a/changelog.d/unreads-sync.fix +++ /dev/null @@ -1 +0,0 @@ -unread notifications should now properly catch up (eventually) in polling mode diff --git a/changelog.d/user-overrides.add b/changelog.d/user-overrides.add deleted file mode 100644 index c0cb839a..00000000 --- a/changelog.d/user-overrides.add +++ /dev/null @@ -1 +0,0 @@ -Ability to override certain aspects of UI style independent of theme used (UI roundness, fonts, underlay) diff --git a/changelog.d/video-poster.fix b/changelog.d/video-poster.fix deleted file mode 100644 index 43e95f6e..00000000 --- a/changelog.d/video-poster.fix +++ /dev/null @@ -1 +0,0 @@ -Video posters on Safari diff --git a/changelog.d/video-poster.update.skip b/changelog.d/video-poster.update.skip deleted file mode 100644 index 9dafe9be..00000000 --- a/changelog.d/video-poster.update.skip +++ /dev/null @@ -1 +0,0 @@ -nothing diff --git a/changelog.d/web-push-always.add b/changelog.d/web-push-always.add deleted file mode 100644 index f8b8888a..00000000 --- a/changelog.d/web-push-always.add +++ /dev/null @@ -1 +0,0 @@ -Added option to always "show" notifications when using web push for better compatibility with some browsers (chrome, edge, safari) From 9d51eccf5dd0b4b773db5ec146d818b6c8fe18ac Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 31 Jul 2024 18:16:00 +0300 Subject: [PATCH 012/289] version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fb157fae..82255914 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pleroma_fe", - "version": "2.6.1", + "version": "2.7.0", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors ", "private": false, From d67d24757f16bbbafc950e2b2b8261c6a7edd938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 13 Aug 2024 19:26:43 +0200 Subject: [PATCH 013/289] Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- changelog.d/deprecate-subscribe.change | 1 + src/components/user_card/user_card.vue | 2 +- src/modules/users.js | 4 ++-- src/services/api/api.service.js | 13 +------------ 4 files changed, 5 insertions(+), 15 deletions(-) create mode 100644 changelog.d/deprecate-subscribe.change diff --git a/changelog.d/deprecate-subscribe.change b/changelog.d/deprecate-subscribe.change new file mode 100644 index 00000000..10fb34f4 --- /dev/null +++ b/changelog.d/deprecate-subscribe.change @@ -0,0 +1 @@ +Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes \ No newline at end of file diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 70c4f67d..87af9d0f 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -208,7 +208,7 @@ /> + {{ ' ' }} +
    + +
    +import { ref, computed } from 'vue' + +import Select from 'src/components/select/select.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' +import StringSetting from '../../helpers/string_setting.vue' +// import Preview from '../theme_tab/theme_preview.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons' + +library.add( + faFile, + faFloppyDisk, + faFolderOpen +) + +const name = ref('') +const author = ref('') +const license = ref('') +const website = ref('') + +// Getting existing components +const componentsContext = require.context('src', true, /\.style.js(on)?$/) +const componentKeys = componentsContext.keys() + +const componentsMap = new Map( + componentKeys + .map( + key => [key, componentsContext(key).default] + ) +) +// const componentValues = componentsMap.values() + +// Initializing selected component and its computed descendants +const selectedComponentKey = ref(componentKeys[0]) +const selectedComponentValue = computed(() => componentsMap.get(selectedComponentKey.value)) + +// const selectedComponentName = computed(() => selectedComponent.value.name) +const selectedComponentVariants = computed(() => { + return new Set([...(Object.keys(selectedComponentValue.value.variants || {})), 'normal']) +}) +const selectedComponentStates = computed(() => { + return new Set([...(Object.keys(selectedComponentValue.value.states || {})), 'normal']) +}) + + + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 423ce65e..1321e556 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -753,6 +753,16 @@ "update_preview": "Update preview", "themes3": { "define": "Override", + "editor": { + "title": "Style", + "new_style": "New", + "load_style": "Open", + "save_style": "Save", + "style_name": "Stylesheet name", + "style_author": "Made by", + "style_license": "License", + "style_website": "Website" + }, "hacks": { "underlay_overrides": "Change underlay", "underlay_override_mode_none": "Theme default", From 735433beb48764ec560d852a58a8e2ed954220f6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Sep 2024 19:19:53 +0300 Subject: [PATCH 093/289] separate shadow preview into its own component, needed for themes3 editor --- .../component_preview/component_preview.vue | 195 ++++++++++++++++++ .../shadow_control/shadow_control.js | 5 +- .../shadow_control/shadow_control.scss | 99 --------- .../shadow_control/shadow_control.vue | 69 +------ 4 files changed, 205 insertions(+), 163 deletions(-) create mode 100644 src/components/component_preview/component_preview.vue diff --git a/src/components/component_preview/component_preview.vue b/src/components/component_preview/component_preview.vue new file mode 100644 index 00000000..087f48ea --- /dev/null +++ b/src/components/component_preview/component_preview.vue @@ -0,0 +1,195 @@ + + + + diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index ab1df53c..c9a04e4d 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -3,6 +3,7 @@ import OpacityInput from 'src/components/opacity_input/opacity_input.vue' import Select from 'src/components/select/select.vue' import Checkbox from 'src/components/checkbox/checkbox.vue' import Popover from 'src/components/popover/popover.vue' +import ComponentPreview from 'src/components/component_preview/component_preview.vue' import { getCssShadow, getCssShadowFilter } from '../../services/theme_data/theme_data.service.js' import { library } from '@fortawesome/fontawesome-svg-core' import { throttle } from 'lodash' @@ -49,7 +50,8 @@ export default { OpacityInput, Select, Checkbox, - Popover + Popover, + ComponentPreview }, beforeUpdate () { this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) @@ -81,7 +83,6 @@ export default { return this.modelValue == null }, style () { - console.log(this.separateInset) if (this.separateInset) { return { filter: getCssShadowFilter(this.cValue), diff --git a/src/components/shadow_control/shadow_control.scss b/src/components/shadow_control/shadow_control.scss index 19009a3d..cdaefa88 100644 --- a/src/components/shadow_control/shadow_control.scss +++ b/src/components/shadow_control/shadow_control.scss @@ -82,107 +82,8 @@ order: 2; flex: 3 3 15em; min-width: 10em; - display: grid; margin-left: 0.125em; align-self: start; - grid-template-columns: 3em 1fr 3em; - grid-template-rows: 2em 1fr 2em; - grid-template-areas: - ". header y-num " - ". preview y-slide" - "x-num x-slide . " - "options options options"; - grid-gap: 0.5em; - - .header { - grid-area: header; - justify-self: center; - align-self: baseline; - line-height: 2; - } - - .input-light-grid { - grid-area: options; - justify-self: center; - } - - .input-number { - min-width: 2em; - } - - .x-shift-number { - grid-area: x-num; - } - - .x-shift-slider { - grid-area: x-slide; - height: auto; - align-self: start; - min-width: 10em; - } - - .y-shift-number { - grid-area: y-num; - } - - .y-shift-slider { - grid-area: y-slide; - writing-mode: vertical-lr; - justify-self: left; - min-height: 10em; - } - - .x-shift-slider, - .y-shift-slider { - padding: 0; - } - - .preview-window { - --__grid-color1: rgb(102 102 102); - --__grid-color2: rgb(153 153 153); - --__grid-color1-disabled: rgba(102 102 102 / 20%); - --__grid-color2-disabled: rgba(153 153 153 / 20%); - - &.-light-grid { - --__grid-color1: rgb(205 205 205); - --__grid-color2: rgb(255 255 255); - --__grid-color1-disabled: rgba(205 205 205 / 20%); - --__grid-color2-disabled: rgba(255 255 255 / 20%); - } - - grid-area: preview; - aspect-ratio: 1; - display: flex; - align-items: center; - justify-content: center; - min-width: 10em; - min-height: 10em; - background-color: var(--__grid-color2); - background-image: - linear-gradient(45deg, var(--__grid-color1) 25%, transparent 25%), - linear-gradient(-45deg, var(--__grid-color1) 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, var(--__grid-color1) 75%), - linear-gradient(-45deg, transparent 75%, var(--__grid-color1) 75%); - background-size: 20px 20px; - background-position: 0 0, 0 10px, 10px -10px, -10px 0; - border-radius: var(--roundness); - - &.disabled { - background-color: var(--__grid-color2-disabled); - background-image: - linear-gradient(45deg, var(--__grid-color1-disabled) 25%, transparent 25%), - linear-gradient(-45deg, var(--__grid-color1-disabled) 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, var(--__grid-color1-disabled) 75%), - linear-gradient(-45deg, transparent 75%, var(--__grid-color1-disabled) 75%); - } - - .preview-block { - width: 33%; - height: 33%; - border-radius: var(--roundness); - background: var(--background); - } - } } } diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue index 6a7829c5..0305b55c 100644 --- a/src/components/shadow_control/shadow_control.vue +++ b/src/components/shadow_control/shadow_control.vue @@ -3,68 +3,13 @@ class="label shadow-control" :class="{ disabled: !present }" > -
    - - - -
    -
    -
    - - - - {{ $t('settings.style.shadows.light_grid') }} - -
    +
    Date: Tue, 24 Sep 2024 21:32:13 +0300 Subject: [PATCH 095/289] some initial drafts of component editor --- .../component_preview/component_preview.vue | 9 +- .../tabs/style_tab/style_tab.js | 217 +++++++++++++++--- .../tabs/style_tab/style_tab.scss | 53 ++++- .../tabs/style_tab/style_tab.vue | 124 +++++----- src/i18n/en.json | 38 ++- .../theme_data/theme_data_3.service.js | 26 ++- 6 files changed, 352 insertions(+), 115 deletions(-) diff --git a/src/components/component_preview/component_preview.vue b/src/components/component_preview/component_preview.vue index f29284c8..f8f51620 100644 --- a/src/components/component_preview/component_preview.vue +++ b/src/components/component_preview/component_preview.vue @@ -33,8 +33,11 @@ >
    + > + TEST +
    @@ -163,6 +165,9 @@ } .preview-block { + display: flex; + justify-content: center; + align-items: center; width: 33%; height: 33%; border-radius: var(--roundness); diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index a2e6f7db..54920805 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -1,40 +1,183 @@ -// import { -// rgb2hex, -// hex2rgb, -// getContrastRatioLayers, -// relativeLuminance -// } from 'src/services/color_convert/color_convert.js' - -// import { -// getThemes -// } from 'src/services/style_setter/style_setter.js' - -// import { -// newImporter, -// newExporter -// } from 'src/services/export_import/export_import.js' - -// import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' -// import { init } from 'src/services/theme_data/theme_data_3.service.js' -// import { -// getCssRules, -// getScopedVersion -// } from 'src/services/theme_data/css_utils.js' - -// import ColorInput from 'src/components/color_input/color_input.vue' -// import RangeInput from 'src/components/range_input/range_input.vue' -// import OpacityInput from 'src/components/opacity_input/opacity_input.vue' -// import ShadowControl from 'src/components/shadow_control/shadow_control.vue' -// import FontControl from 'src/components/font_control/font_control.vue' -// import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' -// import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' -// import Checkbox from 'src/components/checkbox/checkbox.vue' -/* eslint-disable no-unused-vars */ +import { ref, reactive, computed, watch } from 'vue' import Select from 'src/components/select/select.vue' -import Preview from './theme_preview.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' +import ComponentPreview from 'src/components/component_preview/component_preview.vue' +import StringSetting from '../../helpers/string_setting.vue' -import { defineOptions, ref } from 'vue' -const componentsContext = require.context('src', true, /\.style.js(on)?$/) -const componentNames = componentsContext.keys() -const componentName = ref(componentNames[0]) +import { init } from 'src/services/theme_data/theme_data_3.service.js' +import { getCssRules } from 'src/services/theme_data/css_utils.js' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons' + +library.add( + faFile, + faFloppyDisk, + faFolderOpen +) + +export default { + components: { + Select, + Checkbox, + StringSetting, + ComponentPreview + }, + setup () { + const name = ref('') + const author = ref('') + const license = ref('') + const website = ref('') + + const palette = { + // These are here just to establish order, + // themes should override those + bg: '#121a24', + fg: '#182230', + text: '#b9b9ba', + link: '#d8a070', + accent: '#d8a070', + cRed: '#FF0000', + cBlue: '#0095ff', + cGreen: '#0fa00f', + cOrange: '#ffa500' + } + + const getI18nPath = (componentName) => `settings.style.themes3.editor.components.${componentName}` + + const getFriendlyNamePath = (componentName) => getI18nPath(componentName) + '.friendlyName' + + const getVariantPath = (componentName, variant) => { + return variant === 'normal' + ? 'settings.style.themes3.editor.components.normal.variant' + : `${getI18nPath(componentName)}.variants.${variant}` + } + const getStatePath = (componentName, state) => { + return state === 'normal' + ? 'settings.style.themes3.editor.components.normal.state' + : `${getI18nPath(componentName)}.states.${state}` + } + + // Getting existing components + const componentsContext = require.context('src', true, /\.style.js(on)?$/) + const componentKeysRaw = componentsContext.keys() + + const componentsMap = new Map( + componentKeysRaw + .map( + key => [key, componentsContext(key).default] + ).filter(([key, component]) => !component.virtual) + ) + const componentKeys = [...componentsMap.keys()] + + // const componentValues = componentsMap.values() + + // Initializing selected component and its computed descendants + const selectedComponentKey = ref(componentKeys[0]) + const selectedComponentValue = computed(() => componentsMap.get(selectedComponentKey.value)) + + const selectedComponentName = computed(() => selectedComponentValue.value.name) + const selectedComponentVariants = computed(() => { + return new Set(['normal', ...(Object.keys(selectedComponentValue.value.variants || {}))]) + }) + const selectedComponentStates = computed(() => { + return new Set([...(Object.keys(selectedComponentValue.value.states || {}).filter(x => x !== 'normal'))]) + }) + + const selectedVariant = ref('normal') + const selectedStates = reactive(new Set()) + + const updateSelectedStates = (state, v) => { + if (v) { + selectedStates.add(state) + } else { + selectedStates.delete(state) + } + } + + const simulatePseudoSelectors = css => css + .replace(selectedComponentValue.value.selector, '.ComponentPreview .preview-block') + .replace(':active', '.preview-active') + .replace(':hover', '.preview-hover') + .replace(':active', '.preview-active') + .replace(':focus', '.preview-focus') + .replace(':focus-within', '.preview-focus-within') + .replace(':disabled', '.preview-disabled') + + const previewRules = reactive([]) + const previewClass = computed(() => { + const selectors = [] + selectors.push(selectedComponentValue.value.variants[selectedVariant.value]) + if (selectedStates.size > 0) { + selectedStates.forEach(state => { + const original = selectedComponentValue.value.states[state] + selectors.push(simulatePseudoSelectors(original)) + }) + } + console.log(selectors) + return selectors.map(x => x.substring(1)).join('') + }) + + const previewCss = computed(() => { + console.log(previewRules) + const scoped = getCssRules(previewRules).map(simulatePseudoSelectors) + return scoped.join('\n') + }) + + const updateSelectedComponent = () => { + selectedVariant.value = 'normal' + selectedStates.clear() + + previewRules.splice(0, previewRules.length) + previewRules.push(...init({ + inputRuleset: [{ + component: selectedComponentName.value + }], + initialStaticVars: { + ...palette + }, + ultimateBackgroundColor: '#000000', + rootComponentName: selectedComponentName.value, + editMode: true, + debug: true + }).eager) + } + + updateSelectedComponent() + + watch( + selectedComponentName, + updateSelectedComponent + ) + + return { + name, + author, + license, + website, + componentKeys, + componentsMap, + + selectedComponentValue, + selectedComponentName, + selectedComponentKey, + selectedComponentVariants, + selectedComponentStates, + updateSelectedStates, + selectedVariant, + selectedStates, + getFriendlyNamePath, + getStatePath, + getVariantPath, + previewCss, + previewClass, + fallbackI18n (translated, fallback) { + if (translated.startsWith('settings.style.themes3')) { + return fallback + } + return translated + } + } + } +} diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.scss b/src/components/settings_modal/tabs/style_tab/style_tab.scss index 04b6d984..91c5572b 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.scss +++ b/src/components/settings_modal/tabs/style_tab/style_tab.scss @@ -40,11 +40,37 @@ .component-editor { display: grid; - grid-template-columns: 10em, 1fr, 2fr; - grid-template-rows: auto 1fr; + grid-template-columns: 10em 2fr 3fr; + grid-template-rows: auto auto 1fr; + grid-gap: 0.5em; grid-template-areas: - "variant" "preview" "controls", - "state" "preview" "controls"; + "component-label component ." + "variant preview settings" + "state preview settings"; + + .compopnent-selector { + grid-area: component; + align-self: center; + } + + .component-selector-label { + grid-area: component-label; + align-self: center; + text-align: right; + font-weight: bold; + } + + .state-selector, + .variant-selector { + display: grid; + grid-template-rows: auto auto; + grid-auto-flow: rows; + grid-gap: 0.5em; + + > label { + font-weight: bold; + } + } .state-selector { grid-area: state; @@ -52,8 +78,23 @@ .variant-selector { grid-area: variant; - display: flex; - flex-direction: column; + } + + .state-selector-list { + display: grid; + list-style: none; + grid-template-rows: auto; + grid-gap: 0.5em; + padding: 0; + margin: 0; + } + + .preview-container { + grid-area: preview; + } + + .component-settings { + grid-area: settings; } } } diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index 1a1180b7..c92c9217 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -1,49 +1,4 @@ - +
    + +
    @@ -97,9 +130,49 @@ } .panel-body { + display: flex; + gap: 0.5em; + } + + .emoji-picker-panel { + position: absolute; + z-index: 20; + margin-top: 2px; + + &.hide { + display: none; + } + } + + .input-emoji { + height: 2.5em; + width: 2.5em; + padding: 0; + + .iconEmoji { + display: inline-block; + text-align: center; + object-fit: contain; + vertical-align: middle; + height: 2.5em; + width: 2.5em; + + > span { + font-size: 1.5rem; + line-height: 2.5rem; + } + } + + img.iconEmoji { + padding: 0.25em; + box-sizing: border-box; + } + } + + .input-wrap { display: flex; flex-direction: column; - overflow: hidden; + gap: 0.5em; } .go-back-button { diff --git a/src/components/emoji_picker/emoji_picker.js b/src/components/emoji_picker/emoji_picker.js index 9ea5c877..d3d6563a 100644 --- a/src/components/emoji_picker/emoji_picker.js +++ b/src/components/emoji_picker/emoji_picker.js @@ -180,7 +180,7 @@ const EmojiPicker = { if (!this.keepOpen) { this.$refs.popover.hidePopover() } - this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen }) + this.$emit('emoji', { insertion: value, insertionUrl: emoji.imageUrl, keepOpen: this.keepOpen }) }, onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) { const target = this.$refs['emoji-groups'].$el diff --git a/src/i18n/en.json b/src/i18n/en.json index 5a9bee32..cc55a6d0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -1409,15 +1409,16 @@ "tooltip": "This domain contains non-ascii characters." }, "bookmark_folders": { - "create": "Create folder", + "select_folder": "Select bookmark folder", "creating_folder": "Creating bookmark folder", - "delete": "Delete folder", "editing_folder": "Editing folder {folderName}", - "error": "Error manipulating bookmark folders: {0}", + "emoji": "Emoji", "name": "Folder name", "new": "New Folder", + "create": "Create folder", + "delete": "Delete folder", + "update_folder": "Save changes", "really_delete": "Do you really want to delete the folder?", - "select_folder": "Select bookmark folder", - "update_folder": "Save changes" + "error": "Error manipulating bookmark folders: {0}" } } diff --git a/src/modules/bookmark_folders.js b/src/modules/bookmark_folders.js index 5dde58a7..c276adf4 100644 --- a/src/modules/bookmark_folders.js +++ b/src/modules/bookmark_folders.js @@ -8,14 +8,14 @@ export const mutations = { setBookmarkFolders (state, value) { state.allFolders = value }, - setBookmarkFolder (state, { id, name, emoji, emojiUrl }) { + setBookmarkFolder (state, { id, name, emoji, emoji_url: emojiUrl }) { const entry = find(state.allFolders, { id }) if (!entry) { - state.allFolders.push({ id, name, emoji, emojiUrl }) + state.allFolders.push({ id, name, emoji, emoji_url: emojiUrl }) } else { entry.name = name entry.emoji = emoji - entry.emojiUrl = emojiUrl + entry.emoji_url = emojiUrl } }, deleteBookmarkFolder (state, { folderId }) { From 44a7f8a4858065038cb9198e2a0bab0d1aabfdbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 26 Sep 2024 02:05:55 +0200 Subject: [PATCH 103/289] Styles improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/components/bookmark_folder_card/bookmark_folder_card.vue | 4 +++- src/components/bookmark_folders/bookmark_folders.vue | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/bookmark_folder_card/bookmark_folder_card.vue b/src/components/bookmark_folder_card/bookmark_folder_card.vue index b773c9fb..50863071 100644 --- a/src/components/bookmark_folder_card/bookmark_folder_card.vue +++ b/src/components/bookmark_folder_card/bookmark_folder_card.vue @@ -41,12 +41,14 @@ diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index 7be1446e..ecddf9d5 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -10,7 +10,7 @@ import ColorInput from 'src/components/color_input/color_input.vue' import PaletteEditor from 'src/components/palette_editor/palette_editor.vue' import OpacityInput from 'src/components/opacity_input/opacity_input.vue' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' -import Popover from 'src/components/popover/popover.vue' +import Tooltip from 'src/components/tooltip/tooltip.vue' import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' import { init } from 'src/services/theme_data/theme_data_3.service.js' @@ -43,7 +43,7 @@ export default { components: { Select, Checkbox, - Popover, + Tooltip, StringSetting, ComponentPreview, TabSwitcher, diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index 7184d33a..f5c605f9 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -165,44 +165,29 @@ :disabled="!isBackgroundColorPresent" :label="$t('settings.style.themes3.editor.background')" /> - - - - + + + - - - - + + + - - - - + +
    - - - - + +
    @@ -250,34 +230,24 @@ :disabled="!isLinkColorPresent" v-if="componentHas('Link')" /> - - - - + + - - - - + +
    + + + + + + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index f6267d9e..2c20e292 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -779,7 +779,7 @@ "no-auto": "Disabled" }, "palette": { - "label": "Edited palette", + "label": "Palette", "dark": "Dark mode", "light": "Light mode", "bg": "Panel background", From f0957bdb4ff1fed060696ac953679cef241e92be Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 1 Oct 2024 00:42:33 +0300 Subject: [PATCH 123/289] palettes that actually work --- src/components/button.style.js | 8 +- .../palette_editor/palette_editor.vue | 88 ++++++++++++--- .../settings_modal/tabs/appearance_tab.js | 98 +++++++++++------ .../settings_modal/tabs/appearance_tab.scss | 76 +++++++++++++ .../settings_modal/tabs/appearance_tab.vue | 102 ++++++++---------- .../tabs/style_tab/style_tab.vue | 6 +- .../tabs/theme_tab/theme_tab.js | 34 +----- src/i18n/en.json | 37 ++++--- src/modules/interface.js | 50 ++++++++- src/services/style_setter/style_setter.js | 26 ++++- static/palettes/index.json | 32 ++++++ static/styles.json | 6 -- 12 files changed, 393 insertions(+), 170 deletions(-) create mode 100644 src/components/settings_modal/tabs/appearance_tab.scss create mode 100644 static/palettes/index.json diff --git a/src/components/button.style.js b/src/components/button.style.js index 434189f3..defef21b 100644 --- a/src/components/button.style.js +++ b/src/components/button.style.js @@ -63,11 +63,17 @@ export default { } }, { - state: ['hover', 'pressed'], + state: ['pressed', 'hover'], directives: { shadow: ['--defaultButtonHoverGlow', '--pressedButtonBevel'] } }, + { + state: ['pressed', 'hover', 'focused'], + directives: { + shadow: ['--pressedButtonBevel'] + } + }, { state: ['toggled'], directives: { diff --git a/src/components/palette_editor/palette_editor.vue b/src/components/palette_editor/palette_editor.vue index 65398004..cf189941 100644 --- a/src/components/palette_editor/palette_editor.vue +++ b/src/components/palette_editor/palette_editor.vue @@ -1,21 +1,73 @@ - + diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index f5c605f9..8cce057b 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -54,7 +54,7 @@
    diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.js b/src/components/settings_modal/tabs/theme_tab/theme_tab.js index 64de28bc..98fa91e8 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.js +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.js @@ -5,7 +5,7 @@ import { relativeLuminance } from 'src/services/color_convert/color_convert.js' import { - getThemes + getThemeResources } from 'src/services/style_setter/style_setter.js' import { newImporter, @@ -125,25 +125,9 @@ export default { created () { const self = this - getThemes() - .then((promises) => { - return Promise.all( - Object.entries(promises) - .map(([k, v]) => v.then(res => [k, res])) - ) - }) - .then(themes => themes.reduce((acc, [k, v]) => { - if (v) { - return { - ...acc, - [k]: v - } - } else { - return acc - } - }, {})) + getThemeResources('/static/styles.json') .then((themesComplete) => { - self.availableStyles = themesComplete + self.availableStyles = Object.values(themesComplete) }) }, mounted () { @@ -412,9 +396,6 @@ export default { forceUseSource = false ) { this.dismissWarning() - if (!source && !theme) { - throw new Error('Can\'t load theme: empty') - } const version = (origin === 'localStorage' && !theme.colors) ? 'l1' : fileVersion @@ -494,14 +475,7 @@ export default { customTheme: theme, customThemeSource: source } = this.$store.getters.mergedConfig - if (!theme && !source) { - // Anon user or never touched themes - this.loadTheme( - this.$store.state.instance.themeData, - 'defaults', - confirmLoadSource - ) - } else { + if (theme || source) { this.loadTheme( { theme, diff --git a/src/i18n/en.json b/src/i18n/en.json index 2c20e292..0da8d4f0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -748,11 +748,31 @@ "more_settings": "More settings", "style": { "custom_theme_used": "(Custom theme)", + "stock_theme_used": "(Stock theme)", "themes2_outdated": "Editor for Themes V2 is being phased out and will eventually be replaced with a new one that takes advantage of new Themes V3 engine. It should still work but experience might be degraded and inconsistent.", "appearance_tab_note": "Changes on this tab do not affect the theme used, so exported theme will be different from what seen in the UI", "update_preview": "Update preview", "themes3": { "define": "Override", + "palette": { + "label": "Palette", + "import": "Import", + "export": "Export", + "dark": "Dark mode", + "light": "Light mode", + "bg": "Panel background", + "fg": "Buttons etc.", + "text": "Text", + "link": "Links", + "accent": "Accent color", + "cRed": "Red color", + "cBlue": "Blue color", + "cGreen": "Green color", + "cOrange": "Orange color", + "extra1": "Extra 1", + "extra2": "Extra 2", + "extra3": "Extra 3" + }, "editor": { "title": "Style", "new_style": "New", @@ -778,23 +798,6 @@ "preserve": "Keep color", "no-auto": "Disabled" }, - "palette": { - "label": "Palette", - "dark": "Dark mode", - "light": "Light mode", - "bg": "Panel background", - "fg": "Buttons etc.", - "text": "Text", - "link": "Links", - "accent": "Accent color", - "cRed": "Red color", - "cBlue": "Blue color", - "cGreen": "Green color", - "cOrange": "Orange color", - "extra1": "Extra 1", - "extra2": "Extra 2", - "extra3": "Extra 3" - }, "components": { "normal": { "state": "Normal", diff --git a/src/modules/interface.js b/src/modules/interface.js index 57bfe0c6..f52b677c 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -212,6 +212,11 @@ const interfaceMod = { setLastTimeline ({ commit }, value) { commit('setLastTimeline', value) }, + setPalette ({ dispatch, commit }, { paletteData }) { + console.log('PAL', paletteData) + commit('setOption', { name: 'userPalette', value: paletteData }) + dispatch('setTheme', { themeName: null, recompile: true }) + }, setTheme ({ commit, rootState }, { themeName, themeData, recompile, saveData } = {}) { const { theme: instanceThemeName @@ -221,21 +226,52 @@ const interfaceMod = { theme: userThemeName, customTheme: userThemeSnapshot, customThemeSource: userThemeSource, + userPalette, forceThemeRecompilation, themeDebug, theme3hacks } = rootState.config + const userPaletteIss = (() => { + if (!userPalette) return null + const result = { + component: 'Root', + directives: {} + } + + Object + .entries(userPalette) + .filter(([k]) => k !== 'name') + .forEach(([k, v]) => { + let issRootDirectiveName + switch (k) { + case 'background': + issRootDirectiveName = 'bg' + break + case 'foreground': + issRootDirectiveName = 'fg' + break + default: + issRootDirectiveName = k + } + result.directives['--' + issRootDirectiveName] = 'color | ' + v + }) + return result + })() const actualThemeName = userThemeName || instanceThemeName const forceRecompile = forceThemeRecompilation || recompile let promise = null + console.log('TEST', actualThemeName, themeData) + if (themeData) { promise = Promise.resolve(normalizeThemeData(themeData)) } else if (themeName) { promise = getPreset(themeName).then(themeData => normalizeThemeData(themeData)) + } else if (themeName === null) { + promise = Promise.resolve(null) } else if (userThemeSource || userThemeSnapshot) { promise = Promise.resolve(normalizeThemeData({ _pleroma_theme_version: 2, @@ -264,13 +300,14 @@ const interfaceMod = { promise .then(realThemeData => { - const theme2ruleset = convertTheme2To3(realThemeData) + const theme2ruleset = realThemeData ? convertTheme2To3(realThemeData) : null if (saveData) { commit('setOption', { name: 'theme', value: themeName || actualThemeName }) commit('setOption', { name: 'customTheme', value: realThemeData }) commit('setOption', { name: 'customThemeSource', value: realThemeData }) } + const hacks = [] Object.entries(theme3hacks).forEach(([key, value]) => { @@ -336,9 +373,15 @@ const interfaceMod = { }) const ruleset = [ - ...theme2ruleset, ...hacks ] + if (!theme2ruleset && userPaletteIss) { + ruleset.unshift(userPaletteIss) + } + + if (theme2ruleset) { + ruleset.unshift(...theme2ruleset) + } applyTheme( ruleset, @@ -355,6 +398,7 @@ const interfaceMod = { export default interfaceMod export const normalizeThemeData = (input) => { + console.log(input) if (Array.isArray(input)) { const themeData = { colors: {} } themeData.colors.bg = input[1] @@ -365,7 +409,7 @@ export const normalizeThemeData = (input) => { themeData.colors.cGreen = input[6] themeData.colors.cBlue = input[7] themeData.colors.cOrange = input[8] - return generatePreset(themeData).theme + return generatePreset(themeData).source || generatePreset(themeData).theme } let themeData, themeSource diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index e54a95bf..e75366ea 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -256,13 +256,13 @@ export const applyConfig = (input) => { body.classList.remove('hidden') } -export const getThemes = () => { +export const getThemeResources = (url) => { const cache = 'no-store' - return window.fetch('/static/styles.json', { cache }) + return window.fetch(url, { cache }) .then((data) => data.json()) - .then((themes) => { - return Object.entries(themes).map(([k, v]) => { + .then((resources) => { + return Object.entries(resources).map(([k, v]) => { let promise = null if (typeof v === 'object') { promise = Promise.resolve(v) @@ -284,10 +284,26 @@ export const getThemes = () => { return acc }, {}) }) + .then((promises) => { + return Promise.all( + Object.entries(promises) + .map(([k, v]) => v.then(res => [k, res])) + ) + }) + .then(themes => themes.reduce((acc, [k, v]) => { + if (v) { + return { + ...acc, + [k]: v + } + } else { + return acc + } + }, {})) } export const getPreset = (val) => { - return getThemes() + return getThemeResources('/static/styles.json') .then((themes) => themes[val] ? themes[val] : themes['pleroma-dark']) .then((theme) => { const isV1 = Array.isArray(theme) diff --git a/static/palettes/index.json b/static/palettes/index.json new file mode 100644 index 00000000..354be96a --- /dev/null +++ b/static/palettes/index.json @@ -0,0 +1,32 @@ +{ + "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "classic-dark": { + "name": "Classic Dark", + "background": "#161c20", + "foreground": "#282e32", + "text": "#b9b9b9", + "link": "#baaa9c", + "cRed": "#d31014", + "cBlue": "#0fa00f", + "cGreen": "#0095ff", + "cOrange": "#ffa500" + }, + "pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"], + "tomorrow-night": { + "name": "Tomorrow Night", + "background": "#1d1f21", + "foreground": "#373b41", + "link": "#81a2be", + "text": "#c5c8c6", + "cRed": "#cc6666", + "cBlue": "#8abeb7", + "cGreen": "#b5bd68", + "cOrange": "#de935f", + "_cYellow": "#f0c674", + "_cPurple": "#b294bb" + }, + "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], + "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], + "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ] +} diff --git a/static/styles.json b/static/styles.json index 23f57c65..2f836a47 100644 --- a/static/styles.json +++ b/static/styles.json @@ -1,12 +1,6 @@ { "pleroma-dark": "/static/themes/pleroma-dark.json", "pleroma-light": "/static/themes/pleroma-light.json", - "pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"], - "classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], - "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], - "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], - "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ], - "redmond-xx": "/static/themes/redmond-xx.json", "redmond-xx-se": "/static/themes/redmond-xx-se.json", "redmond-xxi": "/static/themes/redmond-xxi.json", From ba4be2cb22aa508589f89fe0c44e8da241e91321 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 2 Oct 2024 02:35:52 +0300 Subject: [PATCH 124/289] yet another massive overhaul on how themes are loaded/applied --- src/boot/after_store.js | 2 +- .../settings_modal/tabs/appearance_tab.js | 86 ++-- .../tabs/theme_tab/theme_tab.js | 23 +- src/modules/instance.js | 3 + src/modules/interface.js | 418 ++++++++++++------ src/services/style_setter/style_setter.js | 100 ++--- static/palettes/index.json | 8 +- 7 files changed, 381 insertions(+), 259 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 6cad05f6..9c2bbb52 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -350,7 +350,7 @@ const afterStoreSetup = async ({ store, i18n }) => { store.dispatch('setInstanceOption', { name: 'server', value: server }) await setConfig({ store }) - await store.dispatch('setTheme') + await store.dispatch('applyTheme', { recompile: false }) applyConfig(store.state.config) diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index b779231b..503f59b3 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -8,9 +8,6 @@ import FontControl from 'src/components/font_control/font_control.vue' import { normalizeThemeData } from 'src/modules/interface' -import { - getThemeResources -} from 'src/services/style_setter/style_setter.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { init } from 'src/services/theme_data/theme_data_3.service.js' import { @@ -42,8 +39,8 @@ const AppearanceTab = { 'link', 'text', 'cRed', - 'cBlue', 'cGreen', + 'cBlue', 'cOrange' ], intersectionObserver: null, @@ -75,37 +72,50 @@ const AppearanceTab = { Preview }, mounted () { - getThemeResources('/static/styles.json') - .then((themes) => { - this.availableStyles = Object - .entries(themes) - .map(([key, data]) => ({ key, data, name: data.name || data[0], version: 'v2' })) - }) + const updateIndex = (resource) => { + const capitalizedResource = resource[0].toUpperCase() + resource.slice(1) + const currentIndex = this.$store.state.instance[`${resource}sIndex`] - getThemeResources('/static/palettes/index.json') - .then((palettes) => { - const result = {} - console.log(palettes) - Object.entries(palettes).forEach(([k, v]) => { - if (Array.isArray(v)) { - const [ - name, - background, - foreground, - text, - link, - cRed = '#FF0000', - cBlue = '#0000FF', - cGreen = '#00FF00', - cOrange = '#E3FF00' - ] = v - result[k] = { name, background, foreground, text, link, cRed, cBlue, cGreen, cOrange } - } else { - result[k] = v - } - }) - this.availablePalettes = result + let promise + if (currentIndex) { + promise = Promise.resolve(currentIndex) + } else { + promise = this.$store.dispatch(`fetch${capitalizedResource}sIndex`) + } + + return promise.then(index => { + return Object + .entries(index) + .map(([k, func]) => [k, func()]) }) + } + + updateIndex('theme').then(themes => { + themes.forEach(([key, themePromise]) => themePromise.then(data => { + this.availableStyles.push({ key, data, name: data.name, version: 'v2' }) + })) + }) + + updateIndex('palette').then(palettes => { + palettes.forEach(([key, palettePromise]) => palettePromise.then(v => { + if (Array.isArray(v)) { + const [ + name, + background, + foreground, + text, + link, + cRed = '#FF0000', + cGreen = '#00FF00', + cBlue = '#0000FF', + cOrange = '#E3FF00' + ] = v + this.availablePalettes.push({ key, name, background, foreground, text, link, cRed, cBlue, cGreen, cOrange }) + } else { + this.availablePalettes.push({ key, ...v }) + } + })) + }) if (window.IntersectionObserver) { this.intersectionObserver = new IntersectionObserver((entries, observer) => { @@ -186,11 +196,13 @@ const AppearanceTab = { const { theme } = this.mergedConfig return key === theme }, - setTheme (name) { - this.$store.dispatch('setTheme', { themeName: name, saveData: true, recompile: true }) + async setTheme (name) { + await this.$store.dispatch('setTheme', name) + this.$store.dispatch('applyTheme') }, - setPalette (name) { - this.$store.dispatch('setPalette', { paletteData: name }) + async setPalette (name) { + await this.$store.dispatch('setPalette', name) + this.$store.dispatch('applyTheme') }, previewTheme (key, input) { let theme3 diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.js b/src/components/settings_modal/tabs/theme_tab/theme_tab.js index 98fa91e8..00418b03 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.js +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.js @@ -4,9 +4,6 @@ import { getContrastRatioLayers, relativeLuminance } from 'src/services/color_convert/color_convert.js' -import { - getThemeResources -} from 'src/services/style_setter/style_setter.js' import { newImporter, newExporter @@ -123,12 +120,22 @@ export default { } }, created () { - const self = this + const currentIndex = this.$store.state.instance.themesIndex - getThemeResources('/static/styles.json') - .then((themesComplete) => { - self.availableStyles = Object.values(themesComplete) - }) + let promise + if (currentIndex) { + promise = Promise.resolve(currentIndex) + } else { + promise = this.$store.dispatch('fetchThemesIndex') + } + + promise.then(themesIndex => { + Object + .values(themesIndex) + .forEach(themeFunc => { + themeFunc().then(themeData => this.availableStyles.push(themeData)) + }) + }) }, mounted () { this.loadThemeFromLocalStorage() diff --git a/src/modules/instance.js b/src/modules/instance.js index 994f60a5..35b1ea73 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -42,6 +42,9 @@ const defaultState = { registrationOpen: true, server: 'http://localhost:4040/', textlimit: 5000, + themesIndex: undefined, + stylesIndex: undefined, + palettesIndex: undefined, themeData: undefined, // used for theme editor v2 vapidPublicKey: undefined, diff --git a/src/modules/interface.js b/src/modules/interface.js index f52b677c..7c7ed74f 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -1,4 +1,4 @@ -import { getPreset, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js' +import { getResourcesIndex, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js' import { CURRENT_VERSION, generatePreset } from 'src/services/theme_data/theme_data.service.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' @@ -212,35 +212,229 @@ const interfaceMod = { setLastTimeline ({ commit }, value) { commit('setLastTimeline', value) }, - setPalette ({ dispatch, commit }, { paletteData }) { - console.log('PAL', paletteData) - commit('setOption', { name: 'userPalette', value: paletteData }) - dispatch('setTheme', { themeName: null, recompile: true }) + async fetchPalettesIndex ({ commit, state }) { + try { + const value = await getResourcesIndex('/static/palettes/index.json') + commit('setInstanceOption', { name: 'palettesIndex', value }) + return value + } catch (e) { + console.error('Could not fetch palettes index', e) + return {} + } }, - setTheme ({ commit, rootState }, { themeName, themeData, recompile, saveData } = {}) { + setPalette ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'palette', value }) + + dispatch('applyTheme') + }, + setPaletteCustom ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'paletteCustomData', value }) + + dispatch('applyTheme') + }, + async fetchStylesIndex ({ commit, state }) { + try { + const value = await getResourcesIndex('/static/styles/index.json') + commit('setInstanceOption', { name: 'stylesIndex', value }) + return value + } catch (e) { + console.error('Could not fetch styles index', e) + return Promise.resolve({}) + } + }, + setStyle ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'style', value }) + + dispatch('applyTheme') + }, + setStyleCustom ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'styleCustomData', value }) + + dispatch('applyTheme') + }, + async fetchThemesIndex ({ commit, state }) { + try { + const value = await getResourcesIndex('/static/styles.json') + commit('setInstanceOption', { name: 'themesIndex', value }) + return value + } catch (e) { + console.error('Could not fetch themes index', e) + return Promise.resolve({}) + } + }, + setTheme ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'theme', value }) + + dispatch('applyTheme') + }, + setThemeCustom ({ dispatch, commit }, value) { + dispatch('resetV3') + dispatch('resetV2') + + commit('setOption', { name: 'customTheme', value }) + commit('setOption', { name: 'customThemeSource', value }) + + dispatch('applyTheme') + }, + resetV3 ({ dispatch, commit }) { + commit('setOption', { name: 'style', value: null }) + commit('setOption', { name: 'styleCustomData', value: null }) + commit('setOption', { name: 'palette', value: null }) + commit('setOption', { name: 'paletteCustomData', value: null }) + }, + resetV2 ({ dispatch, commit }) { + commit('setOption', { name: 'theme', value: null }) + commit('setOption', { name: 'customTheme', value: null }) + commit('setOption', { name: 'customThemeSource', value: null }) + }, + async applyTheme ( + { dispatch, commit, rootState }, + { recompile = true } = {} + ) { + // If we're not not forced to recompile try using + // cache (tryLoadCache return true if load successful) + const { - theme: instanceThemeName + style: instanceStyleName, + palette: instancePaletteName + } = rootState.instance + let { + theme: instanceThemeV2Name, + themesIndex, + stylesIndex, + palettesIndex } = rootState.instance const { - theme: userThemeName, - customTheme: userThemeSnapshot, - customThemeSource: userThemeSource, - userPalette, + style: userStyleName, + styleCustomData: userStyleCustomData, + palette: userPaletteName, + paletteCustomData: userPaletteCustomData, forceThemeRecompilation, themeDebug, theme3hacks } = rootState.config + let { + theme: userThemeV2Name, + customTheme: userThemeV2Snapshot, + customThemeSource: userThemeV2Source - const userPaletteIss = (() => { - if (!userPalette) return null + } = rootState.config + + const forceRecompile = forceThemeRecompilation || recompile + if (!forceRecompile && !themeDebug && tryLoadCache()) { + return commit('setThemeApplied') + } + + let majorVersionUsed + + if (userPaletteName || userPaletteCustomData || + userStyleName || userStyleCustomData || + instancePaletteName || + instanceStyleName + ) { + // Palette and/or style overrides V2 themes + instanceThemeV2Name = null + userThemeV2Name = null + userThemeV2Source = null + userThemeV2Snapshot = null + + majorVersionUsed = 'v3' + if (!palettesIndex || !stylesIndex) { + const result = await Promise.all([ + dispatch('fetchPalettesIndex'), + dispatch('fetchStylesIndex') + ]) + + palettesIndex = result[0] + stylesIndex = result[1] + } + } else { + majorVersionUsed = 'v2' + // Promise.all just to be uniform with v3 + const result = await Promise.all([ + dispatch('fetchThemesIndex') + ]) + themesIndex = result[0] + } + + let styleDataUsed = null + let styleNameUsed = null + let paletteDataUsed = null + let paletteNameUsed = null + let themeNameUsed = null + let themeDataUsed = null + + if (majorVersionUsed === 'v3') { + if (userStyleCustomData) { + styleNameUsed = 'custom' // custom data overrides name + styleDataUsed = userStyleCustomData + } else { + styleNameUsed = userStyleName || instanceStyleName + let styleFetchFunc = stylesIndex[themeNameUsed] + if (!styleFetchFunc) { + const newName = Object.keys(stylesIndex)[0] + styleFetchFunc = stylesIndex[newName] + console.warn(`Style with id '${styleNameUsed}' not found, falling back to '${newName}'`) + } + styleDataUsed = await styleFetchFunc?.() + } + + if (userPaletteCustomData) { + paletteNameUsed = 'custom' // custom data overrides name + paletteDataUsed = userPaletteCustomData + } else { + paletteNameUsed = userPaletteName || instanceStyleName + let paletteFetchFunc = palettesIndex[themeNameUsed] + if (!paletteFetchFunc) { + const newName = Object.keys(palettesIndex)[0] + paletteFetchFunc = palettesIndex[newName] + console.warn(`Palette with id '${paletteNameUsed}' not found, falling back to '${newName}'`) + } + paletteDataUsed = await paletteFetchFunc?.() + } + } else { + if (userThemeV2Snapshot || userThemeV2Source) { + themeNameUsed = 'custom' // custom data overrides name + themeDataUsed = userThemeV2Snapshot || userThemeV2Source + } else { + themeNameUsed = userThemeV2Name || instanceThemeV2Name + let themeFetchFunc = themesIndex[themeNameUsed] + if (!themeFetchFunc) { + const newName = Object.keys(themesIndex)[0] + themeFetchFunc = themesIndex[newName] + console.warn(`Theme with id '${themeNameUsed}' not found, falling back to '${newName}'`) + } + themeDataUsed = await themeFetchFunc?.() + } + // Themes v2 editor support + commit('setInstanceOption', { name: 'themeData', value: themeDataUsed }) + } + + const paletteIss = (() => { + if (!paletteDataUsed) return null const result = { component: 'Root', directives: {} } Object - .entries(userPalette) + .entries(paletteDataUsed) .filter(([k]) => k !== 'name') .forEach(([k, v]) => { let issRootDirectiveName @@ -258,139 +452,84 @@ const interfaceMod = { }) return result })() - const actualThemeName = userThemeName || instanceThemeName - const forceRecompile = forceThemeRecompilation || recompile + const theme2ruleset = themeDataUsed && convertTheme2To3(normalizeThemeData(themeDataUsed)) + const hacks = [] - let promise = null - - console.log('TEST', actualThemeName, themeData) - - if (themeData) { - promise = Promise.resolve(normalizeThemeData(themeData)) - } else if (themeName) { - promise = getPreset(themeName).then(themeData => normalizeThemeData(themeData)) - } else if (themeName === null) { - promise = Promise.resolve(null) - } else if (userThemeSource || userThemeSnapshot) { - promise = Promise.resolve(normalizeThemeData({ - _pleroma_theme_version: 2, - theme: userThemeSnapshot, - source: userThemeSource - })) - } else if (actualThemeName && actualThemeName !== 'custom') { - promise = getPreset(actualThemeName).then(themeData => { - const realThemeData = normalizeThemeData(themeData) - if (actualThemeName === instanceThemeName) { - // This sole line is the reason why this whole block is above the recompilation check - commit('setInstanceOption', { name: 'themeData', value: { theme: realThemeData } }) - } - return realThemeData - }) - } else { - throw new Error('Cannot load any theme!') - } - - // If we're not not forced to recompile try using - // cache (tryLoadCache return true if load successful) - if (!forceRecompile && !themeDebug && tryLoadCache()) { - commit('setThemeApplied') - return - } - - promise - .then(realThemeData => { - const theme2ruleset = realThemeData ? convertTheme2To3(realThemeData) : null - - if (saveData) { - commit('setOption', { name: 'theme', value: themeName || actualThemeName }) - commit('setOption', { name: 'customTheme', value: realThemeData }) - commit('setOption', { name: 'customThemeSource', value: realThemeData }) - } - - const hacks = [] - - Object.entries(theme3hacks).forEach(([key, value]) => { - switch (key) { - case 'fonts': { - Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => { - if (!font?.family) return - switch (fontKey) { - case 'interface': - hacks.push({ - component: 'Root', - directives: { - '--font': 'generic | ' + font.family - } - }) - break - case 'input': - hacks.push({ - component: 'Input', - directives: { - '--font': 'generic | ' + font.family - } - }) - break - case 'post': - hacks.push({ - component: 'RichContent', - directives: { - '--font': 'generic | ' + font.family - } - }) - break - case 'monospace': - hacks.push({ - component: 'Root', - directives: { - '--monoFont': 'generic | ' + font.family - } - }) - break - } - }) - break + Object.entries(theme3hacks).forEach(([key, value]) => { + switch (key) { + case 'fonts': { + Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => { + if (!font?.family) return + switch (fontKey) { + case 'interface': + hacks.push({ + component: 'Root', + directives: { + '--font': 'generic | ' + font.family + } + }) + break + case 'input': + hacks.push({ + component: 'Input', + directives: { + '--font': 'generic | ' + font.family + } + }) + break + case 'post': + hacks.push({ + component: 'RichContent', + directives: { + '--font': 'generic | ' + font.family + } + }) + break + case 'monospace': + hacks.push({ + component: 'Root', + directives: { + '--monoFont': 'generic | ' + font.family + } + }) + break } - case 'underlay': { - if (value !== 'none') { - const newRule = { - component: 'Underlay', - directives: {} - } - if (value === 'opaque') { - newRule.directives.opacity = 1 - newRule.directives.background = '--wallpaper' - } - if (value === 'transparent') { - newRule.directives.opacity = 0 - } - hacks.push(newRule) - } - break + }) + break + } + case 'underlay': { + if (value !== 'none') { + const newRule = { + component: 'Underlay', + directives: {} } + if (value === 'opaque') { + newRule.directives.opacity = 1 + newRule.directives.background = '--wallpaper' + } + if (value === 'transparent') { + newRule.directives.opacity = 0 + } + hacks.push(newRule) } - }) - - const ruleset = [ - ...hacks - ] - if (!theme2ruleset && userPaletteIss) { - ruleset.unshift(userPaletteIss) + break } + } + }) - if (theme2ruleset) { - ruleset.unshift(...theme2ruleset) - } + const rulesetArray = [ + theme2ruleset, + styleDataUsed, + paletteIss, + hacks + ].filter(x => x) - applyTheme( - ruleset, - () => commit('setThemeApplied'), - themeDebug - ) - }) - - return promise + return applyTheme( + rulesetArray.flat(), + () => commit('setThemeApplied'), + themeDebug + ) } } } @@ -398,7 +537,6 @@ const interfaceMod = { export default interfaceMod export const normalizeThemeData = (input) => { - console.log(input) if (Array.isArray(input)) { const themeData = { colors: {} } themeData.colors.bg = input[1] diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index e75366ea..70b0b336 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -1,4 +1,3 @@ -import { hex2rgb } from '../color_convert/color_convert.js' import { init, getEngineChecksum } from '../theme_data/theme_data_3.service.js' import { getCssRules } from '../theme_data/css_utils.js' import { defaultState } from '../../modules/config.js' @@ -53,7 +52,7 @@ export const generateTheme = async (inputRuleset, callbacks, debug) => { // Assuming that "worst case scenario background" is panel background since it's the most likely one const themes3 = init({ inputRuleset, - ultimateBackgroundColor: inputRuleset[0].directives['--bg'].split('|')[1].trim(), + ultimateBackgroundColor: inputRuleset[0].directives['--bg']?.split('|')[1].trim() || '#000000', debug }) @@ -256,73 +255,36 @@ export const applyConfig = (input) => { body.classList.remove('hidden') } -export const getThemeResources = (url) => { +export const getResourcesIndex = async (url) => { const cache = 'no-store' - return window.fetch(url, { cache }) - .then((data) => data.json()) - .then((resources) => { - return Object.entries(resources).map(([k, v]) => { - let promise = null - if (typeof v === 'object') { - promise = Promise.resolve(v) - } else if (typeof v === 'string') { - promise = window.fetch(v, { cache }) - .then((data) => data.json()) - .catch((e) => { - console.error(e) - return null - }) - } - return [k, promise] - }) - }) - .then((promises) => { - return promises - .reduce((acc, [k, v]) => { - acc[k] = v - return acc - }, {}) - }) - .then((promises) => { - return Promise.all( - Object.entries(promises) - .map(([k, v]) => v.then(res => [k, res])) - ) - }) - .then(themes => themes.reduce((acc, [k, v]) => { - if (v) { - return { - ...acc, - [k]: v - } - } else { - return acc - } - }, {})) -} - -export const getPreset = (val) => { - return getThemeResources('/static/styles.json') - .then((themes) => themes[val] ? themes[val] : themes['pleroma-dark']) - .then((theme) => { - const isV1 = Array.isArray(theme) - const data = isV1 ? {} : theme.theme - - if (isV1) { - const bg = hex2rgb(theme[1]) - const fg = hex2rgb(theme[2]) - const text = hex2rgb(theme[3]) - const link = hex2rgb(theme[4]) - - const cRed = hex2rgb(theme[5] || '#FF0000') - const cGreen = hex2rgb(theme[6] || '#00FF00') - const cBlue = hex2rgb(theme[7] || '#0000FF') - const cOrange = hex2rgb(theme[8] || '#E3FF00') - - data.colors = { bg, fg, text, link, cRed, cBlue, cGreen, cOrange } - } - - return { theme: data, source: theme.source } - }) + try { + const data = await window.fetch(url, { cache }) + const resources = await data.json() + return Object.fromEntries( + Object + .entries(resources) + .map(([k, v]) => { + if (typeof v === 'object') { + return [k, () => Promise.resolve(v)] + } else if (typeof v === 'string') { + return [ + k, + () => window + .fetch(v, { cache }) + .then((data) => data.json()) + .catch((e) => { + console.error(e) + return null + }) + ] + } else { + console.error(`Unknown resource format - ${k} is a ${typeof v}`) + return [k, null] + } + }) + ) + } catch (e) { + return Promise.reject(e) + } } diff --git a/static/palettes/index.json b/static/palettes/index.json index 354be96a..356f4ae7 100644 --- a/static/palettes/index.json +++ b/static/palettes/index.json @@ -8,8 +8,8 @@ "text": "#b9b9b9", "link": "#baaa9c", "cRed": "#d31014", - "cBlue": "#0fa00f", - "cGreen": "#0095ff", + "cGreen": "#0fa00f", + "cBlue": "#0095ff", "cOrange": "#ffa500" }, "pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"], @@ -20,8 +20,8 @@ "link": "#81a2be", "text": "#c5c8c6", "cRed": "#cc6666", - "cBlue": "#8abeb7", - "cGreen": "#b5bd68", + "cGreen": "#8abeb7", + "cBlue": "#b5bd68", "cOrange": "#de935f", "_cYellow": "#f0c674", "_cPurple": "#b294bb" From e8d0e45b5b19722555b53f9009f8bc01a9ed8640 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 2 Oct 2024 16:22:28 +0300 Subject: [PATCH 125/289] it is working. finally. --- .../settings_modal/tabs/appearance_tab.js | 28 ++- .../settings_modal/tabs/appearance_tab.vue | 8 +- src/modules/config.js | 2 + src/modules/interface.js | 184 +++++++++++++----- src/services/style_setter/style_setter.js | 2 +- .../theme_data/theme_data_3.service.js | 6 + static/config.json | 2 +- 7 files changed, 168 insertions(+), 64 deletions(-) diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index 503f59b3..247a800e 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -174,7 +174,11 @@ const AppearanceTab = { }, isCustomThemeUsed () { const { theme } = this.mergedConfig - return theme === 'custom' || theme === null + return theme === 'custom' + }, + isCustomStyleUsed (name) { + const { style } = this.mergedConfig + return style === 'custom' }, ...SharedComputedObject() }, @@ -196,12 +200,26 @@ const AppearanceTab = { const { theme } = this.mergedConfig return key === theme }, - async setTheme (name) { - await this.$store.dispatch('setTheme', name) + isStyleActive (key) { + const { style } = this.mergedConfig + return key === style + }, + isPaletteActive (key) { + const { palette } = this.mergedConfig + return key === palette + }, + setTheme (name) { + this.$store.dispatch('setTheme', name) this.$store.dispatch('applyTheme') }, - async setPalette (name) { - await this.$store.dispatch('setPalette', name) + setPalette (name) { + this.$store.dispatch('setPalette', name) + this.$store.dispatch('applyTheme') + }, + resetTheming (name) { + this.$store.dispatch('resetThemeV2') + this.$store.dispatch('resetThemeV3') + this.$store.dispatch('setStyle', 'stock') this.$store.dispatch('applyTheme') }, previewTheme (key, input) { diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index 29db1961..164247fc 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -9,7 +9,8 @@
    diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index 164247fc..9c08fb54 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -1,16 +1,19 @@ From 13838a75a9b5b0f2b59fa5b10675952e1b7cae11 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 3 Oct 2024 02:16:55 +0300 Subject: [PATCH 133/289] import of v2 on appearance tab works now --- .../settings_modal/tabs/appearance_tab.js | 31 ++++++++++++++++++- .../settings_modal/tabs/appearance_tab.scss | 15 +++++++++ .../settings_modal/tabs/appearance_tab.vue | 11 ++++++- src/modules/interface.js | 31 +++++++------------ src/services/export_import/export_import.js | 8 +++-- 5 files changed, 71 insertions(+), 25 deletions(-) diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index 247a800e..1e48c7e8 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -8,6 +8,7 @@ import FontControl from 'src/components/font_control/font_control.vue' import { normalizeThemeData } from 'src/modules/interface' +import { newImporter } from 'src/services/export_import/export_import.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { init } from 'src/services/theme_data/theme_data_3.service.js' import { @@ -33,6 +34,12 @@ const AppearanceTab = { return { availableStyles: [], availablePalettes: [], + themeImporter: newImporter({ + accept: '.json, .piss', + validator: this.importValidator, + onImport: this.onImport, + onImportFailure: this.onImportFailure + }), palettesKeys: [ 'background', 'foreground', @@ -184,7 +191,6 @@ const AppearanceTab = { }, methods: { updateFont (key, value) { - console.log(key, value) this.$store.dispatch('setOption', { name: 'theme3hacks', value: { @@ -196,6 +202,26 @@ const AppearanceTab = { } }) }, + importTheme () { + this.themeImporter.importData() + }, + onImport (parsed, filename) { + if (filename.endsWith('.json')) { + this.$store.dispatch('setThemeCustom', parsed.source || parsed.theme) + this.$store.dispatch('applyTheme') + } + + // this.loadTheme(parsed, 'file', forceSource) + }, + onImportFailure (result) { + this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' }) + }, + importValidator (parsed, filename) { + if (filename.endsWith('.json')) { + const version = parsed._pleroma_theme_version + return version >= 1 || version <= 2 + } + }, isThemeActive (key) { const { theme } = this.mergedConfig return key === theme @@ -207,6 +233,9 @@ const AppearanceTab = { isPaletteActive (key) { const { palette } = this.mergedConfig return key === palette + }, + importStyle () { + }, setTheme (name) { this.$store.dispatch('setTheme', name) diff --git a/src/components/settings_modal/tabs/appearance_tab.scss b/src/components/settings_modal/tabs/appearance_tab.scss index 7d546741..77d668ec 100644 --- a/src/components/settings_modal/tabs/appearance_tab.scss +++ b/src/components/settings_modal/tabs/appearance_tab.scss @@ -5,6 +5,21 @@ margin: 1em; } + .setting-item { + padding-bottom: 0; + + &.heading { + display: grid; + align-items: baseline; + grid-template-columns: 1fr auto auto auto; + grid-gap: 0.5em; + + h2 { + flex: 1 0 auto; + } + } + } + .palettes { display: grid; grid-template-columns: 1fr 1fr; diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index 9c08fb54..d27f43fe 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -3,8 +3,17 @@ class="appearance-tab" :label="$t('settings.general')" > -
    +

    {{ $t('settings.theme') }}

    + +
    +
      true @@ -27,18 +28,19 @@ export const newImporter = ({ importData () { const filePicker = document.createElement('input') filePicker.setAttribute('type', 'file') - filePicker.setAttribute('accept', '.json') + filePicker.setAttribute('accept', accept) filePicker.addEventListener('change', event => { if (event.target.files[0]) { + const filename = event.target.files[0].name // eslint-disable-next-line no-undef const reader = new FileReader() reader.onload = ({ target }) => { try { const parsed = JSON.parse(target.result) - const validationResult = validator(parsed) + const validationResult = validator(parsed, filename) if (validationResult === true) { - onImport(parsed) + onImport(parsed, filename) } else { onImportFailure({ validationResult }) } From 81d9537f9d00ab18cab4305344d7563fb6418ddd Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 3 Oct 2024 23:03:33 +0300 Subject: [PATCH 134/289] show warning about palettes being unsupported when using v2 theme --- .../settings_modal/tabs/appearance_tab.js | 18 +++++--- .../settings_modal/tabs/appearance_tab.scss | 4 ++ .../settings_modal/tabs/appearance_tab.vue | 45 +++++++++++-------- src/i18n/en.json | 3 +- src/modules/interface.js | 5 ++- 5 files changed, 49 insertions(+), 26 deletions(-) diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index 1e48c7e8..bba4647c 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -34,7 +34,7 @@ const AppearanceTab = { return { availableStyles: [], availablePalettes: [], - themeImporter: newImporter({ + fileImporter: newImporter({ accept: '.json, .piss', validator: this.importValidator, onImport: this.onImport, @@ -179,6 +179,10 @@ const AppearanceTab = { this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) } }, + customThemeVersion () { + const { themeVersion } = this.$store.state.interface + return themeVersion + }, isCustomThemeUsed () { const { theme } = this.mergedConfig return theme === 'custom' @@ -202,8 +206,8 @@ const AppearanceTab = { } }) }, - importTheme () { - this.themeImporter.importData() + importFile () { + this.fileImporter.importData() }, onImport (parsed, filename) { if (filename.endsWith('.json')) { @@ -234,14 +238,18 @@ const AppearanceTab = { const { palette } = this.mergedConfig return key === palette }, - importStyle () { - + setStyle (name) { + this.$store.dispatch('resetThemeV2') + this.$store.dispatch('setTheme', name) + this.$store.dispatch('applyTheme') }, setTheme (name) { + this.$store.dispatch('resetThemeV3') this.$store.dispatch('setTheme', name) this.$store.dispatch('applyTheme') }, setPalette (name) { + this.$store.dispatch('resetThemeV2') this.$store.dispatch('setPalette', name) this.$store.dispatch('applyTheme') }, diff --git a/src/components/settings_modal/tabs/appearance_tab.scss b/src/components/settings_modal/tabs/appearance_tab.scss index 77d668ec..b95ef07d 100644 --- a/src/components/settings_modal/tabs/appearance_tab.scss +++ b/src/components/settings_modal/tabs/appearance_tab.scss @@ -24,6 +24,10 @@ display: grid; grid-template-columns: 1fr 1fr; grid-gap: 0.5em; + + .unsupported-theme-v2 { + grid-column: 1 / span 2; + } } .palette-entry { diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index d27f43fe..a65c5231 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -7,7 +7,7 @@

      {{ $t('settings.theme') }}

    {{ $t('settings.style.themes3.palette.label') }}

    - + +
    diff --git a/src/i18n/en.json b/src/i18n/en.json index 0da8d4f0..603bc491 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -771,7 +771,8 @@ "cOrange": "Orange color", "extra1": "Extra 1", "extra2": "Extra 2", - "extra3": "Extra 3" + "extra3": "Extra 3", + "v2_unsupported": "Older v2 themes don't support palettes. Switch to v3 theme to make use of palettes", }, "editor": { "title": "Style", diff --git a/src/modules/interface.js b/src/modules/interface.js index 96d23cbc..6daa4a1b 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -5,6 +5,7 @@ import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' const defaultState = { localFonts: null, themeApplied: false, + themeVersion: 'v3', temporaryChangesTimeoutId: null, // used for temporary options that revert after a timeout temporaryChangesConfirm: () => {}, // used for applying temporary options temporaryChangesRevert: () => {}, // used for reverting temporary options @@ -307,7 +308,7 @@ const interfaceMod = { commit('setOption', { name: 'customThemeSource', value: null }) }, async applyTheme ( - { dispatch, commit, rootState }, + { dispatch, commit, rootState, state }, { recompile = true } = {} ) { // If we're not not forced to recompile try using @@ -398,6 +399,8 @@ const interfaceMod = { majorVersionUsed = 'v3' } + state.themeVersion = majorVersionUsed + let styleDataUsed = null let styleNameUsed = null let paletteDataUsed = null From 9e3e4ed429e11594ffeccbe8000afeaebe066cb0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 3 Oct 2024 23:03:56 +0300 Subject: [PATCH 135/289] rearrange palettes so that Pleroma-dark is default (first) and bird is next to Pleroma-light in UI --- static/palettes/index.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/palettes/index.json b/static/palettes/index.json index acb4e4d9..63fbad5a 100644 --- a/static/palettes/index.json +++ b/static/palettes/index.json @@ -1,6 +1,6 @@ { - "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], "pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], + "pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ], "classic-dark": { "name": "Classic Dark", "background": "#161c20", @@ -12,6 +12,7 @@ "cBlue": "#0095ff", "cOrange": "#ffa500" }, + "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], "pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"], "tomorrow-night": { "name": "Tomorrow Night", @@ -26,7 +27,6 @@ "_cYellow": "#f0c674", "_cPurple": "#b294bb" }, - "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"], "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ] } From c937736feab589fb123b8208792d5f12e3a056de Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 4 Oct 2024 00:27:53 +0300 Subject: [PATCH 136/289] shadow editor now can handle expressions (functions and variables) --- .../tabs/style_tab/style_tab.js | 37 +- .../tabs/style_tab/style_tab.vue | 2 +- .../shadow_control/shadow_control.js | 80 ++-- .../shadow_control/shadow_control.scss | 10 +- .../shadow_control/shadow_control.vue | 353 ++++++++++-------- src/i18n/en.json | 3 + .../theme_data/theme_data_3.service.js | 7 +- 7 files changed, 285 insertions(+), 207 deletions(-) diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index ecddf9d5..cbd25dfc 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -219,9 +219,13 @@ export default { return selectors.map(x => x.substring(1)).join('') }) const previewCss = computed(() => { - const scoped = getCssRules(previewRules) - .map(simulatePseudoSelectors) - return scoped.join('\n') + try { + const scoped = getCssRules(previewRules).map(simulatePseudoSelectors) + return scoped.join('\n') + } catch (e) { + console.error('Invalid ruleset', e) + return null + } }) // ### Rules stuff aka meat and potatoes @@ -415,17 +419,22 @@ export default { }) const updatePreview = () => { - previewRules.splice(0, previewRules.length) - previewRules.push(...init({ - inputRuleset: editorFriendlyToOriginal.value, - initialStaticVars: { - ...palette.value - }, - ultimateBackgroundColor: '#000000', - rootComponentName: selectedComponentName.value, - editMode: true, - debug: true - }).eager) + try { + const rules = init({ + inputRuleset: editorFriendlyToOriginal.value, + initialStaticVars: { + ...palette.value + }, + ultimateBackgroundColor: '#000000', + rootComponentName: selectedComponentName.value, + editMode: true, + debug: true + }).eager + previewRules.splice(0, previewRules.length) + previewRules.push(...rules) + } catch (e) { + console.error('Could not compile preview theme', e) + } } const updateSelectedComponent = () => { diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index cd9d3e47..590624ff 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -125,7 +125,7 @@ :shadow-control="isShadowTabOpen" :preview-class="previewClass" :preview-style="editorHintStyle" - :disabled="!editedSubShadow" + :disabled="!editedSubShadow && typeof editedShadow !== 'string'" :shadow="editedSubShadow" @update:shadow="({ axis, value }) => updateSubShadow(axis, value)" /> diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index 4521305e..2befb8ba 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -21,16 +21,22 @@ library.add( faPlus ) -const toModel = (object = {}) => ({ - x: 0, - y: 0, - blur: 0, - spread: 0, - inset: false, - color: '#000000', - alpha: 1, - ...object -}) +const toModel = (input) => { + if (typeof input === 'object') { + return { + x: 0, + y: 0, + blur: 0, + spread: 0, + inset: false, + color: '#000000', + alpha: 1, + ...input + } + } else if (typeof input === 'string') { + return input + } +} export default { props: [ @@ -56,12 +62,29 @@ export default { this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) }, computed: { - selected () { - const selected = this.cValue[this.selectedId] - if (selected) { - return { ...selected } + selectedType: { + get () { + return typeof this.selected + }, + set (newType) { + this.selected = toModel(newType === 'object' ? {} : '') + } + }, + selected: { + get () { + const selected = this.cValue[this.selectedId] + console.log('SELECTED', selected) + if (selected && typeof selected === 'object') { + return { ...selected } + } else if (typeof selected === 'string') { + return selected + } + return null + }, + set (value) { + this.cValue[this.selectedId] = toModel(value) + this.$emit('update:modelValue', this.cValue) } - return null }, present () { return this.selected != null && !this.usingFallback @@ -82,14 +105,20 @@ export default { return this.modelValue == null }, style () { - if (this.separateInset) { - return { - filter: getCssShadowFilter(this.cValue), - boxShadow: getCssShadow(this.cValue, true) + try { + if (this.separateInset) { + return { + filter: getCssShadowFilter(this.cValue), + boxShadow: getCssShadow(this.cValue, true) + } + } + return { + boxShadow: getCssShadow(this.cValue) + } + } catch (e) { + return { + border: '1px solid red' } - } - return { - boxShadow: getCssShadow(this.cValue) } } }, @@ -99,6 +128,13 @@ export default { } }, methods: { + getSubshadowLabel (shadow, index) { + if (typeof shadow === 'object') { + return shadow?.name ?? this.$t('settings.style.shadows.shadow_id', { value: index }) + } else if (typeof shadow === 'string') { + return shadow || this.$t('settings.style.shadows.empty_expression') + } + }, updateProperty: throttle(function (prop, value) { this.cValue[this.selectedId][prop] = value if (prop === 'inset' && value === false && this.separateInset) { diff --git a/src/components/shadow_control/shadow_control.scss b/src/components/shadow_control/shadow_control.scss index dd049023..067895ee 100644 --- a/src/components/shadow_control/shadow_control.scss +++ b/src/components/shadow_control/shadow_control.scss @@ -4,6 +4,7 @@ justify-content: stretch; grid-gap: 0.25em; margin-bottom: 1em; + width: 100%; .shadow-switcher { order: 1; @@ -37,6 +38,9 @@ min-width: 10em; margin-left: 0.125em; margin-right: 0.125em; + display: grid; + grid-template-rows: auto 1fr; + grid-gap: 0.25em; /* hack */ .input-boolean { @@ -52,6 +56,11 @@ flex: 1 0 5em; } + .shadow-expression { + width: 100%; + height: 100%; + } + .id-control { align-items: stretch; @@ -100,6 +109,5 @@ } .inset-tooltip { - padding: 0.5em; max-width: 30em; } diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue index e1d20191..669de36e 100644 --- a/src/components/shadow_control/shadow_control.vue +++ b/src/components/shadow_control/shadow_control.vue @@ -8,7 +8,6 @@ class="shadow-preview" :shadow-control="true" :shadow="selected" - :preview-style="style" :disabled="disabled || !present" @update:shadow="({ axis, value }) => updateProperty(axis, value)" /> @@ -18,7 +17,7 @@ v-model="selectedId" class="shadow-list" size="10" - :disabled="shadowsAreNull" + :disabled="disabled || shadowsAreNull" >
    -
    -
    diff --git a/src/i18n/en.json b/src/i18n/en.json index 64d6201d..df0f8d6d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -966,6 +966,9 @@ "blur": "Blur", "spread": "Spread", "inset": "Inset", + "raw": "Plain shadow", + "expression": "Expression (advanced)", + "empty_expression": "Empty expression", "hintV3": "For shadows you can also use the {0} notation to use other color slot.", "filter_hint": { "always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.", diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js index 4765a773..e45d2cef 100644 --- a/src/services/theme_data/theme_data_3.service.js +++ b/src/services/theme_data/theme_data_3.service.js @@ -44,8 +44,8 @@ const findShadow = (shadows, { dynamicVars, staticVars }) => { if (shadow.startsWith('$')) { targetShadow = process(shadow, shadowFunctions, { findColor, findShadow }, { dynamicVars, staticVars }) } else if (shadow.startsWith('--')) { - const [variable] = shadow.split(/,/g).map(str => str.trim()) // discarding modifier since it's not supported - const variableSlot = variable.substring(2) + // modifiers are completely unsupported here + const variableSlot = shadow.substring(2) return findShadow(staticVars[variableSlot], { dynamicVars, staticVars }) } else { targetShadow = parseShadow(shadow) @@ -66,6 +66,7 @@ const findColor = (color, { dynamicVars, staticVars }) => { if (typeof color !== 'string' || (!color.startsWith('--') && !color.startsWith('$'))) return color let targetColor = null if (color.startsWith('--')) { + // Modifier support is pretty much for v2 themes only const [variable, modifier] = color.split(/,/g).map(str => str.trim()) const variableSlot = variable.substring(2) if (variableSlot === 'stack') { @@ -421,7 +422,7 @@ export const init = ({ break } case 'shadow': { - const shadow = value.split(/,/g).map(s => s.trim()) + const shadow = value.split(/,/g).map(s => s.trim()).filter(x => x) dynamicVars[k] = shadow if (combination.component === rootComponentName) { staticVars[k.substring(2)] = shadow From 3d77860e57892569cfe98bccfdc65d3a9c95dbf6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 4 Oct 2024 02:49:20 +0300 Subject: [PATCH 137/289] moved the select motion stuff into its own component --- src/components/select/select_motion.vue | 115 +++++ .../tabs/style_tab/style_tab.vue | 432 +++++++++--------- .../shadow_control/shadow_control.js | 45 +- .../shadow_control/shadow_control.vue | 55 +-- 4 files changed, 356 insertions(+), 291 deletions(-) create mode 100644 src/components/select/select_motion.vue diff --git a/src/components/select/select_motion.vue b/src/components/select/select_motion.vue new file mode 100644 index 00000000..1b9f4041 --- /dev/null +++ b/src/components/select/select_motion.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index 590624ff..7026f7af 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -51,231 +51,241 @@
-
-
- - -
+
- - - {{ fallbackI18n($t(getVariantPath(selectedComponentName, variant)), variant) }} - - -
-
- -
    + {{ fallbackI18n($t(getFriendlyNamePath(componentsMap.get(key).name)), componentsMap.get(key).name) }} + + +
+
-
  • + {{ $t('settings.style.themes3.editor.variant_selector') }} + + +
  • +
    + +
      +
    • + + {{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }} + +
    • +
    +
    +
    + + + + +
    + +
    + + + + + + + + + + + + +
    + + +
    + + + +
    + +
    +
    + +
    + + + + + + + + +
    +
    - {{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }} - - - + {{ $t('settings.style.themes3.editor.include_in_rule') }} + + +
    +
    -
    - - - - -
    - -
    - - - - - - - - - - + + + - - - -
    - - - -
    - -
    -
    - -
    - - - - - - - - + {{ $t('settings.style.themes3.palette.light') }} + + -
    - - {{ $t('settings.style.themes3.editor.include_in_rule') }} - - -
    -
    - -
    -
    - - +
    - -
    + diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index 2befb8ba..fc227b5b 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -1,6 +1,7 @@ import ColorInput from 'src/components/color_input/color_input.vue' import OpacityInput from 'src/components/opacity_input/opacity_input.vue' import Select from 'src/components/select/select.vue' +import SelectMotion from 'src/components/select/select_motion.vue' import Checkbox from 'src/components/checkbox/checkbox.vue' import Popover from 'src/components/popover/popover.vue' import ComponentPreview from 'src/components/component_preview/component_preview.vue' @@ -54,13 +55,11 @@ export default { ColorInput, OpacityInput, Select, + SelectMotion, Checkbox, Popover, ComponentPreview }, - beforeUpdate () { - this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) - }, computed: { selectedType: { get () { @@ -73,7 +72,6 @@ export default { selected: { get () { const selected = this.cValue[this.selectedId] - console.log('SELECTED', selected) if (selected && typeof selected === 'object') { return { ...selected } } else if (typeof selected === 'string') { @@ -95,12 +93,6 @@ export default { currentFallback () { return this.fallback?.[this.selectedId] }, - moveUpValid () { - return this.selectedId > 0 - }, - moveDnValid () { - return this.selectedId < this.cValue.length - 1 - }, usingFallback () { return this.modelValue == null }, @@ -123,11 +115,20 @@ export default { } }, watch: { + modelValue (value) { + if (!value) this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) + }, selected (value) { this.$emit('subShadowSelected', this.selectedId) } }, methods: { + getNewSubshadow () { + return toModel(this.selected) + }, + onSelectChange (id) { + this.selectedId = id + }, getSubshadowLabel (shadow, index) { if (typeof shadow === 'object') { return shadow?.name ?? this.$t('settings.style.shadows.shadow_id', { value: index }) @@ -141,28 +142,6 @@ export default { this.cValue[this.selectedId].spread = 0 } this.$emit('update:modelValue', this.cValue) - }, 100), - add () { - this.cValue.push(toModel(this.selected)) - this.selectedId = Math.max(this.cValue.length - 1, 0) - this.$emit('update:modelValue', this.cValue) - }, - del () { - this.cValue.splice(this.selectedId, 1) - this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0) - this.$emit('update:modelValue', this.cValue) - }, - moveUp () { - const movable = this.cValue.splice(this.selectedId, 1)[0] - this.cValue.splice(this.selectedId - 1, 0, movable) - this.selectedId -= 1 - this.$emit('update:modelValue', this.cValue) - }, - moveDn () { - const movable = this.cValue.splice(this.selectedId, 1)[0] - this.cValue.splice(this.selectedId + 1, 0, movable) - this.selectedId += 1 - this.$emit('update:modelValue', this.cValue) - } + }, 100) } } diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue index 669de36e..6a5cd186 100644 --- a/src/components/shadow_control/shadow_control.vue +++ b/src/components/shadow_control/shadow_control.vue @@ -28,53 +28,14 @@ {{ getSubshadowLabel(shadow, index) }} -
    - - - - -
    +
    - + /> diff --git a/src/services/export_import/export_import.js b/src/services/export_import/export_import.js index e1ac6a42..b8f84351 100644 --- a/src/services/export_import/export_import.js +++ b/src/services/export_import/export_import.js @@ -2,15 +2,22 @@ import utf8 from 'utf8' export const newExporter = ({ filename = 'data', + mime = 'application/json', + extension = '.json', getExportedObject }) => ({ exportData () { - const stringified = utf8.encode(JSON.stringify(getExportedObject(), null, 2)) // Pretty-print and indent with 2 spaces + let stringified + if (mime === 'application/json') { + stringified = utf8.encode(JSON.stringify(getExportedObject(), null, 2)) // Pretty-print and indent with 2 spaces + } else { + stringified = utf8.encode(getExportedObject()) // Pretty-print and indent with 2 spaces + } // Create an invisible link with a data url and simulate a click const e = document.createElement('a') - e.setAttribute('download', `${filename}.json`) - e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified)) + e.setAttribute('download', `${filename}.${extension}`) + e.setAttribute('href', `data:${mime};base64, ${window.btoa(stringified)}`) e.style.display = 'none' document.body.appendChild(e) From 756ea63b6709e3daf35d738b0a1f3a5e9439c4d9 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 6 Oct 2024 20:21:13 +0300 Subject: [PATCH 153/289] variables stuff seem to be at least somewhat working --- .../palette_editor/palette_editor.vue | 2 +- .../tabs/style_tab/style_tab.js | 36 +++++++++++++++---- .../tabs/style_tab/style_tab.scss | 8 ++--- .../tabs/style_tab/style_tab.vue | 9 +++-- .../shadow_control/shadow_control.js | 4 +++ src/i18n/en.json | 6 +++- 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/components/palette_editor/palette_editor.vue b/src/components/palette_editor/palette_editor.vue index cebe73ee..16148262 100644 --- a/src/components/palette_editor/palette_editor.vue +++ b/src/components/palette_editor/palette_editor.vue @@ -107,7 +107,7 @@ const updatePalette = (paletteKey, value) => { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(3, 1fr) auto; grid-gap: 0.5em; - align-items: space-between; + align-items: baseline; .palette-import-button { grid-column: 1 / span 2; diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index 4e9a3906..c75e6b6b 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -17,7 +17,7 @@ import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' import { init } from 'src/services/theme_data/theme_data_3.service.js' import { getCssRules } from 'src/services/theme_data/css_utils.js' import { serialize } from 'src/services/theme_data/iss_serializer.js' -// import { deserialize } from 'src/services/theme_data/iss_deserializer.js' +import { parseShadow /* , deserialize */ } from 'src/services/theme_data/iss_deserializer.js' import { // rgb2hex, hex2rgb, @@ -259,7 +259,7 @@ export default { } }) - const getEditedElement = (component, directive) => computed({ + const getEditedElement = (component, directive, postProcess = x => x) => computed({ get () { let usedRule const fallback = editorFriendlyFallbackStructure.value @@ -271,7 +271,11 @@ export default { usedRule = get(fallback, path) } - return usedRule + if (directive === 'shadow') { + console.log('EDITED', usedRule) + console.log('PP', postProcess(usedRule)) + } + return postProcess(usedRule) }, set (value) { set(allEditedRules, getPath(component, directive), value) @@ -316,9 +320,22 @@ export default { } } + const normalizeShadows = (shadows) => { + console.log('NORMALIZE') + return shadows?.map(shadow => { + if (typeof shadow === 'object') { + return shadow + } + if (typeof shadow === 'string') { + return parseShadow(shadow) + } + return null + }) + } + // Shadow is partially edited outside the ShadowControl // for better space utilization - const editedShadow = getEditedElement(null, 'shadow') + const editedShadow = getEditedElement(null, 'shadow', normalizeShadows) const editedSubShadowId = ref(null) const editedSubShadow = computed(() => { if (editedShadow.value == null || editedSubShadowId.value == null) return null @@ -511,8 +528,15 @@ export default { const selectedVirtualDirectiveParsed = computed({ get () { switch (selectedVirtualDirective.value.valType) { - case 'shadow': - return {} + case 'shadow': { + const directiveValue = selectedVirtualDirective.value.value + if (Array.isArray(directiveValue)) { + return normalizeShadows(directiveValue) + } else { + const splitShadow = directiveValue.split(/,/g).map(x => x.trim()) + return normalizeShadows(splitShadow) + } + } default: return null } diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.scss b/src/components/settings_modal/tabs/style_tab/style_tab.scss index 0f8540f9..0384f7a4 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.scss +++ b/src/components/settings_modal/tabs/style_tab/style_tab.scss @@ -93,7 +93,7 @@ "label editor" "selector editor" "movement editor"; - grid-template-columns: auto 1fr; + grid-template-columns: 10em 1fr; grid-template-rows: auto 1fr auto; grid-gap: 0.5em; @@ -124,9 +124,9 @@ grid-template-rows: auto auto 1fr; grid-gap: 0.5em; grid-template-areas: - "component component variant" - "state state state" - "preview settings settings"; + "component component variant" + "state state state" + "preview settings settings"; .component-selector { grid-area: component; diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index 8aaa6713..430b7c61 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -245,6 +245,7 @@ > {{ $t('settings.style.themes3.editor.include_in_rule') }} + {{ editedShadow }}
    + - {{ selectedVirtualDirective.valType }}
    diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index fc227b5b..3fe1aa29 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -45,6 +45,7 @@ export default { ], emits: ['update:modelValue', 'subShadowSelected'], data () { + console.log('MODEL VALUE', this.modelValue, this.fallback) return { selectedId: 0, // TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason) @@ -60,6 +61,9 @@ export default { Popover, ComponentPreview }, + beforeUpdate () { + this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) + }, computed: { selectedType: { get () { diff --git a/src/i18n/en.json b/src/i18n/en.json index 3694a390..bad4ddb0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -774,6 +774,9 @@ "extra3": "Extra 3", "v2_unsupported": "Older v2 themes don't support palettes. Switch to v3 theme to make use of palettes" }, + "variables": { + "label": "Variables" + }, "editor": { "title": "Style", "new_style": "New", @@ -800,7 +803,8 @@ "no-auto": "Disabled" }, "component_tab": "Components style", - "palette_tab": "Color presets" + "palette_tab": "Color presets", + "variables_tab": "Variables (Advanced)" }, "hacks": { "underlay_overrides": "Change underlay", From cfe52185f74684ebb599754ebb5b888302498231 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 7 Oct 2024 00:57:54 +0300 Subject: [PATCH 154/289] neat-looking variables tab (sans shadow editor) --- .../tabs/style_tab/style_tab.scss | 16 ++++ .../tabs/style_tab/style_tab.vue | 90 ++++++++++++------- src/i18n/en.json | 4 +- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.scss b/src/components/settings_modal/tabs/style_tab/style_tab.scss index 0384f7a4..69349f78 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.scss +++ b/src/components/settings_modal/tabs/style_tab/style_tab.scss @@ -109,6 +109,7 @@ font-weight: bold; grid-area: label; margin: 0; + align-self: baseline; } &-movement { @@ -118,6 +119,21 @@ } } + .variables-editor { + .variable-selector { + display: grid; + grid-template-columns: auto 1fr auto 10em; + grid-template-rows: subgrid; + align-items: baseline; + grid-gap: 0 0.5em; + } + + .list-edit-area { + display: grid; + grid-template-rows: subgrid; + } + } + .component-editor { display: grid; grid-template-columns: 6fr 3fr 4fr; diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index 430b7c61..9b5a4f9e 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -259,7 +259,7 @@
    diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index 3fe1aa29..8eab5c91 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -41,7 +41,12 @@ const toModel = (input) => { export default { props: [ - 'modelValue', 'fallback', 'separateInset', 'noPreview', 'disabled' + 'modelValue', + 'fallback', + 'separateInset', + 'noPreview', + 'disabled', + 'compact' ], emits: ['update:modelValue', 'subShadowSelected'], data () { diff --git a/src/components/shadow_control/shadow_control.scss b/src/components/shadow_control/shadow_control.scss index de4159c1..b0cf7014 100644 --- a/src/components/shadow_control/shadow_control.scss +++ b/src/components/shadow_control/shadow_control.scss @@ -1,12 +1,32 @@ -.settings-modal .settings-modal-panel .shadow-control { - display: flex; - flex-wrap: wrap; +.ShadowControl { + display: grid; + grid-template-columns: 10em 1fr 1fr; + grid-template-rows: 1fr; + grid-template-areas: "selector preview tweak"; + grid-gap: 0.5em; justify-content: stretch; - grid-gap: 0.25em; margin-bottom: 1em; width: 100%; + &.-compact { + grid-template-columns: 1fr; + grid-template-rows: 10em auto auto; + grid-template-areas: + "selector" + "preview" + "tweak"; + + &.-no-preview { + grid-template-columns: 1fr; + grid-template-rows: 10em 1fr; + grid-template-areas: + "selector" + "tweak"; + } + } + .shadow-switcher { + grid-area: selector; order: 1; flex: 1 0 6em; min-width: 6em; @@ -20,6 +40,7 @@ } .shadow-tweak { + grid-area: tweak; order: 3; flex: 2 0 10em; min-width: 10em; @@ -65,6 +86,10 @@ } &.-no-preview { + grid-template-columns: 10em 1fr; + grid-template-rows: 1fr; + grid-template-areas: "selector tweak"; + .shadow-tweak { order: 0; flex: 2 0 8em; @@ -87,8 +112,7 @@ } .shadow-preview { - order: 2; - flex: 3 3 15em; + grid-area: preview; min-width: 10em; margin-left: 0.125em; align-self: start; diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue index 29adfff4..4f0906c7 100644 --- a/src/components/shadow_control/shadow_control.vue +++ b/src/components/shadow_control/shadow_control.vue @@ -1,7 +1,7 @@