From 0dd343f2d40939900d12f8c42c5c7d4d6be97f63 Mon Sep 17 00:00:00 2001 From: Brian Underwood Date: Tue, 7 Feb 2023 21:48:57 +0100 Subject: [PATCH 01/25] 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 112ca85d91be42b11c91bee25cdbe89c1d57beda Mon Sep 17 00:00:00 2001 From: Pleroma Renovate Bot Date: Wed, 20 Mar 2024 08:52:22 +0000 Subject: [PATCH 02/25] 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 03/25] 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 0878f5bfb43bdc52d72968cbd7bf343e2ec6460d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 13 Aug 2024 19:39:26 +0200 Subject: [PATCH 04/25] Inform users that Smithereen public polls are public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- changelog.d/non-anonymous-polls.add | 1 + src/components/poll/poll.vue | 7 +++++++ src/i18n/en.json | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelog.d/non-anonymous-polls.add diff --git a/changelog.d/non-anonymous-polls.add b/changelog.d/non-anonymous-polls.add new file mode 100644 index 00000000..9ff7f3ad --- /dev/null +++ b/changelog.d/non-anonymous-polls.add @@ -0,0 +1 @@ +Inform users that Smithereen public polls are public \ No newline at end of file diff --git a/src/components/poll/poll.vue b/src/components/poll/poll.vue index 580e5377..e12f3e61 100644 --- a/src/components/poll/poll.vue +++ b/src/components/poll/poll.vue @@ -76,6 +76,13 @@ > {{ $t('polls.vote') }} + + {{ $t('polls.non_anonymous') }} +  ·  +
@@ -16,16 +16,28 @@ export default { props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'], data () { return { + relativeTimeMs: 0, relativeTime: { key: 'time.now', num: 0 }, interval: null } }, computed: { - localeDateString () { - const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale) + shouldUseAbsoluteTimeFormat () { + if (!this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { + return false + } + return DateUtils.durationStrToMs(this.$store.getters.mergedConfig.absoluteTimeFormatMinAge) <= this.relativeTimeMs + }, + browserLocale () { + return localeService.internalToBrowserLocale(this.$i18n.locale) + }, + timeAsDate () { return typeof this.time === 'string' - ? new Date(Date.parse(this.time)).toLocaleString(browserLocale) - : this.time.toLocaleString(browserLocale) + ? new Date(Date.parse(this.time)) + : this.time + }, + localeDateString () { + return this.timeAsDate.toLocaleString(this.browserLocale) }, relativeTimeString () { const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num]) @@ -35,6 +47,40 @@ export default { } return timeString + }, + absoluteTimeString () { + if (this.longFormat) { + return this.localeDateString + } + const now = new Date() + const formatter = (() => { + if (DateUtils.isSameDay(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + minute: 'numeric', + hour: 'numeric' + }) + } else if (DateUtils.isSameMonth(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + hour: 'numeric', + day: 'numeric' + }) + } else if (DateUtils.isSameYear(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + month: 'short', + day: 'numeric' + }) + } else { + return new Intl.DateTimeFormat(this.browserLocale, { + year: 'numeric', + month: 'short' + }) + } + })() + + return formatter.format(this.timeAsDate) + }, + relativeOrAbsoluteTimeString () { + return this.shouldUseAbsoluteTimeFormat ? this.absoluteTimeString : this.relativeTimeString } }, watch: { @@ -54,6 +100,7 @@ export default { methods: { refreshRelativeTimeObject () { const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1 + this.relativeTimeMs = DateUtils.relativeTimeMs(this.time) this.relativeTime = this.longFormat ? DateUtils.relativeTime(this.time, nowThreshold) : DateUtils.relativeTimeShort(this.time, nowThreshold) diff --git a/src/i18n/en.json b/src/i18n/en.json index 3f7ea282..0ed481c0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -506,6 +506,8 @@ "autocomplete_select_first": "Automatically select the first candidate when autocomplete results are available", "emoji_reactions_on_timeline": "Show emoji reactions on timeline", "emoji_reactions_scale": "Reactions scale factor", + "absolute_time_format": "Use absolute time format", + "absolute_time_format_min_age": "Only use for time older than this amount of time", "export_theme": "Save preset", "filtering": "Filtering", "wordfilter": "Wordfilter", diff --git a/src/modules/config.js b/src/modules/config.js index cf84234a..835dcce4 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -180,7 +180,9 @@ export const defaultState = { autocompleteSelect: undefined, // instance default closingDrawerMarksAsSeen: undefined, // instance default unseenAtTop: undefined, // instance default - ignoreInactionableSeen: undefined // instance default + ignoreInactionableSeen: undefined, // instance default + useAbsoluteTimeFormat: undefined, // instance defualt + absoluteTimeFormatMinAge: undefined // instance default } // caching the instance default properties diff --git a/src/modules/instance.js b/src/modules/instance.js index 99b8b5d5..994f60a5 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -119,6 +119,8 @@ const defaultState = { closingDrawerMarksAsSeen: true, unseenAtTop: false, ignoreInactionableSeen: false, + useAbsoluteTimeFormat: false, + absoluteTimeFormatMinAge: '0d', // Nasty stuff customEmoji: [], diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js index ed8e1417..69398c0c 100644 --- a/src/services/date_utils/date_utils.js +++ b/src/services/date_utils/date_utils.js @@ -6,10 +6,13 @@ export const WEEK = 7 * DAY export const MONTH = 30 * DAY export const YEAR = 365.25 * DAY -export const relativeTime = (date, nowThreshold = 1) => { +export const relativeTimeMs = (date) => { if (typeof date === 'string') date = Date.parse(date) + return Math.abs(Date.now() - date) +} +export const relativeTime = (date, nowThreshold = 1) => { const round = Date.now() > date ? Math.floor : Math.ceil - const d = Math.abs(Date.now() - date) + const d = relativeTimeMs(date) const r = { num: round(d / YEAR), key: 'time.unit.years' } if (d < nowThreshold * SECOND) { r.num = 0 @@ -57,3 +60,39 @@ export const secondsToUnit = (unit, amount) => { case 'days': return (1000 * amount) / DAY } } + +export const isSameYear = (a, b) => { + return a.getFullYear() === b.getFullYear() +} + +export const isSameMonth = (a, b) => { + return a.getFullYear() === b.getFullYear() && + a.getMonth() === b.getMonth() +} + +export const isSameDay = (a, b) => { + return a.getFullYear() === b.getFullYear() && + a.getMonth() === b.getMonth() && + a.getDate() === b.getDate() +} + +export const durationStrToMs = (str) => { + if (typeof str !== 'string') { + return 0 + } + + const unit = str.replace(/[0-9,.]+/, '') + const value = str.replace(/[^0-9,.]+/, '') + switch (unit) { + case 'd': + return value * DAY + case 'h': + return value * HOUR + case 'm': + return value * MINUTE + case 's': + return value * SECOND + default: + return 0 + } +} From 74e5bb9104551bfd8105ef6780c40502e9087adc Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 04:24:35 +0300 Subject: [PATCH 09/25] serializer working --- src/services/theme_data/iss_deserializer.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/services/theme_data/iss_deserializer.js diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js new file mode 100644 index 00000000..44a0fade --- /dev/null +++ b/src/services/theme_data/iss_deserializer.js @@ -0,0 +1,3 @@ +export const deserializer (string) { +let level = 0 +} From 5d7a72cfd2ad914e85d3e697e58f0774c582a9b3 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 15:40:52 +0300 Subject: [PATCH 10/25] update browserslist and update versions we support --- .browserslistrc | 7 +++++++ yarn.lock | 28 ++++------------------------ 2 files changed, 11 insertions(+), 24 deletions(-) create mode 100644 .browserslistrc diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 00000000..df2d4716 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,7 @@ +>0.2% +not op_mini all +Safari > 15 +Firefox >= 115 +Firefox ESR +Android > 4 +not dead diff --git a/yarn.lock b/yarn.lock index c42fe8fa..d6474250 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3144,30 +3144,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001370: - version "1.0.30001376" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001376.tgz#af2450833e5a06873fbb030a9556ca9461a2736d" - integrity sha512-I27WhtOQ3X3v3it9gNs/oTpoE5KpwmqKR5oKPA8M0G7uMXh9Ty81Q904HpKUrM30ei7zfcL5jE7AXefgbOfMig== - -caniuse-lite@^1.0.30001359: - version "1.0.30001366" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001366.tgz#c73352c83830a9eaf2dea0ff71fb4b9a4bbaa89c" - integrity sha512-yy7XLWCubDobokgzudpkKux8e0UOOnLHE6mlNJBzT3lZJz6s5atSEzjoL+fsCPkI0G8MP5uVdDx1ur/fXEWkZA== - -caniuse-lite@^1.0.30001400: - version "1.0.30001418" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz#5f459215192a024c99e3e3a53aac310fc7cf24e6" - integrity sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg== - -caniuse-lite@^1.0.30001587: - version "1.0.30001591" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz#16745e50263edc9f395895a7cd468b9f3767cf33" - integrity sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ== - -caniuse-lite@^1.0.30001599: - version "1.0.30001599" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce" - integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001359, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: + version "1.0.30001662" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz" + integrity sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA== chai-nightwatch@0.5.3: version "0.5.3" From 1794d52731607baa3f80ea6a5ab2dbac5bd747ef Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 15:43:38 +0300 Subject: [PATCH 11/25] changelog --- changelog.d/browsers-support.change | 9 ++++ src/services/theme_data/iss_serializer.js | 62 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 changelog.d/browsers-support.change create mode 100644 src/services/theme_data/iss_serializer.js diff --git a/changelog.d/browsers-support.change b/changelog.d/browsers-support.change new file mode 100644 index 00000000..a62e5024 --- /dev/null +++ b/changelog.d/browsers-support.change @@ -0,0 +1,9 @@ +Updated our build system to support browsers: + Safari >= 15 + Firefox >= 115 + Android > 4 + no Opera Mini support + no IE support + no "dead" (unmaintained) browsers support + +This does not guarantee that browsers will or will not work. diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js new file mode 100644 index 00000000..39151e41 --- /dev/null +++ b/src/services/theme_data/iss_serializer.js @@ -0,0 +1,62 @@ +import { unroll } from './iss_utils' + +const getCanonicState = (state) => { + if (state) { + return ['normal', ...state.filter(x => x !== 'normal')] + } else { + return ['normal'] + } +} + +const getCanonicRuleHeader = ({ + component, + variant = 'normal', + parent, + state +}) => ({ + component, + variant, + parent, + state: getCanonicState(state) +}) + +const prepareRule = (rule) => { + const { parent } = rule + const chain = [...unroll(parent), rule].map(getCanonicRuleHeader) + const header = chain.map(({ component, variant, state }) => [ + component, + variant === 'normal' ? '' : ('.' + variant), + state.filter(s => s !== 'normal').map(s => ':' + s).join('') + ].join('')).join(' ') + + console.log(header, rule.directives) + const content = Object.entries(rule.directives).map(([key, value]) => { + let realValue = value + + switch (key) { + case 'shadow': + realValue = realValue.map(v => `${v.inset ? 'inset ' : ''}${v.x} ${v.y} ${v.blur} ${v.spread} ${v.color} / ${v.alpha}`) + } + + if (Array.isArray(realValue)) { + realValue = realValue.join(', ') + } + + return ` ${key}: ${realValue};` + }).sort().join('\n') + + return [ + header, + content + ] +} + +export const serialize = (ruleset) => { + // Scrapped idea: automatically combine same-set directives + // problem: might violate the order rules + + return ruleset.filter(r => Object.keys(r.directives).length > 0).map(r => { + const [header, content] = prepareRule(r) + return `${header} {\n${content}\n}\n\n` + }) +} From e089ca6d9a4592eb2ed0998419113b09906b94b8 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 18:25:37 +0300 Subject: [PATCH 12/25] require himem runner to do building and tests --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25e499c4..f4c5cf43 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,6 +45,7 @@ test: stage: test tags: - amd64 + - himem variables: APT_CACHE_DIR: apt-cache script: @@ -58,6 +59,7 @@ build: stage: build tags: - amd64 + - himem script: - yarn - npm run build From af3b2e3dc9043e66806be85869d867e6b0d23c3c Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 20:37:14 +0300 Subject: [PATCH 13/25] temp --- src/services/theme_data/iss_deserializer.js | 44 ++++++++++++++++- .../theme_data/theme_data_3.service.js | 30 +++++++++++- .../theme_data/iss_deserializer.spec.js | 47 +++++++++++++++++++ 3 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 test/unit/specs/services/theme_data/iss_deserializer.spec.js diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js index 44a0fade..431e1b94 100644 --- a/src/services/theme_data/iss_deserializer.js +++ b/src/services/theme_data/iss_deserializer.js @@ -1,3 +1,43 @@ -export const deserializer (string) { -let level = 0 +// this works nearly the same as HTML tree converter +export const deserialize = (input) => { + const buffer = [] + let textBuffer = '' + + const getCurrentBuffer = () => { + let current = buffer[buffer.length - 1][1] + if (current == null) { + current = { name: null, content: [] } + } + buffer.push(current) + return current + } + + // Processes current line buffer, adds it to output buffer and clears line buffer + const flushText = (content) => { + if (textBuffer === '') return + if (content) { + getCurrentBuffer().content.push(textBuffer) + } else { + getCurrentBuffer().name = textBuffer + } + textBuffer = '' + } + + for (let i = 0; i < input.length; i++) { + const char = input[i] + + if (char === ';') { + flushText(true) + } else if (char === '{') { + flushText(false) + } else if (char === '}') { + buffer.push({ name: null, content: [] }) + textBuffer = '' + } else { + textBuffer += char + } + } + + flushText() + return buffer } diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js index cf58da11..cac450a8 100644 --- a/src/services/theme_data/theme_data_3.service.js +++ b/src/services/theme_data/theme_data_3.service.js @@ -23,6 +23,9 @@ import { findRules } from './iss_utils.js' import { parseCssShadow } from './css_utils.js' +import { + serialize +} from './iss_serializer.js' // Ensuring the order of components const components = { @@ -504,9 +507,32 @@ export const init = ({ console.debug('Eager processing took ' + (t2 - t1) + ' ms') } + // optimization to traverse big-ass array only once instead of twice + const eager = [] + const lazy = [] + + result.forEach(x => { + if (typeof x === 'function') { + lazy.push(x) + } else { + eager.push(x) + } + }) + + const serializedData = serialize(eager) + const file = new File(serializedData, 'ruleset.piss') + const blobUrl = URL.createObjectURL(file) + const a = document.createElement('a') + a.href = blobUrl + a.download = 'ruleset.piss' + document.body.appendChild(a) + a.dispatchEvent(new MouseEvent('click')) + URL.revokeObjectURL(blobUrl) + document.body.removeChild(a) + return { - lazy: result.filter(x => typeof x === 'function'), - eager: result.filter(x => typeof x !== 'function'), + lazy, + eager, staticVars, engineChecksum } diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js new file mode 100644 index 00000000..f1967144 --- /dev/null +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -0,0 +1,47 @@ +import { deserialize } from 'src/services/theme_data/iss_deserializer.js' + +/* eslint-disable quotes */ +const testData = ``` + Root { + --accent: color | #e2b188; + --badgeNotification: color | #e15932; + --bg: color | #0f161e; + --cBlue: color | #81beea; + --cGreen: color | #5dc94a; + --cOrange: color | #ffc459; + --cRed: color | #d31014; + --defaultButtonBevel: shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2); + --defaultButtonHoverGlow: shadow | 0 0 4 --text; + --defaultButtonShadow: shadow | 0 0 2 #000000; + --defaultInputBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2); + --fg: color | #151e2b; + --font: generic | sans-serif; + --link: color | #e2b188; + --monoFont: generic | monospace; + --pressedButtonBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2); + --selectionBackground: color | --accent; + --selectionText: color | $textColor(--accent, --text, no-preserve); + --text: color | #b9b9ba; + --wallpaper: color | #0c1118; + background: transparent; + opacity: 0; + } + + Root Underlay { + background: #000000; + opacity: 0.6; + } + + Root Underlay, test { + background: #000000; + opacity: 0.6; + } + ``` + +describe.only('html_tree_converter', () => { + describe('convertHtmlToTree', () => { + it('should parse ISS correctly', () => { + console.log(deserialize(testData)) + }) + }) +}) From 0c91c376456520b0b58779696067bbf78e46bfd0 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 19 Sep 2024 21:42:14 +0300 Subject: [PATCH 14/25] somehow i lost this file and had to rewrite it. now it's even better than before! --- src/services/theme_data/iss_serializer.js | 38 +++++++++++++++++++ .../theme_data/theme_data_3.service.js | 11 ------ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/services/theme_data/iss_serializer.js diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js new file mode 100644 index 00000000..8d6e9333 --- /dev/null +++ b/src/services/theme_data/iss_serializer.js @@ -0,0 +1,38 @@ +import { unroll } from './iss_utils.js' + +const serializeShadow = s => `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}` + +export const serialize = (ruleset) => { + return ruleset.map((rule) => { + if (Object.keys(rule.directives || {}).length === 0) return false + + const header = unroll(rule).reverse().map(rule => { + const { component } = rule + const newVariant = rule.variant === 'normal' ? '' : ('.' + rule.variant) + const newState = rule.state.filter(st => st !== 'normal') + + return `${component}${newVariant}${newState.map(st => ':' + st).join('')}` + }).join(' ') + + const content = Object.entries(rule.directives).map(([directive, value]) => { + if (directive.startsWith('--')) { + const [valType, newValue] = value.split('|') // only first one! intentional! + switch (valType) { + case 'shadow': + return ` ${directive}: ${newValue.map(serializeShadow).join(', ')}` + default: + return ` ${directive}: ${newValue}` + } + } else { + switch (directive) { + case 'shadow': + return ` ${directive}: ${value.map(serializeShadow).join(', ')}` + default: + return ` ${directive}: ${value}` + } + } + }) + + return `${header} {\n${content.join(';\n')}\n}` + }).filter(x => x).join('\n\n') +} diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js index cac450a8..b98cbb98 100644 --- a/src/services/theme_data/theme_data_3.service.js +++ b/src/services/theme_data/theme_data_3.service.js @@ -519,17 +519,6 @@ export const init = ({ } }) - const serializedData = serialize(eager) - const file = new File(serializedData, 'ruleset.piss') - const blobUrl = URL.createObjectURL(file) - const a = document.createElement('a') - a.href = blobUrl - a.download = 'ruleset.piss' - document.body.appendChild(a) - a.dispatchEvent(new MouseEvent('click')) - URL.revokeObjectURL(blobUrl) - document.body.removeChild(a) - return { lazy, eager, From 71a478108035ddf3489d75bec6ef11c91829ab27 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 02:05:25 +0300 Subject: [PATCH 15/25] at last... it's complete --- src/components/button.style.js | 4 +- src/services/theme_data/iss_deserializer.js | 126 ++++++++++++++++-- src/services/theme_data/iss_serializer.js | 16 ++- .../theme_data/theme_data_3.service.js | 3 - .../theme_data/iss_deserializer.spec.js | 51 ++----- 5 files changed, 136 insertions(+), 64 deletions(-) diff --git a/src/components/button.style.js b/src/components/button.style.js index 6fec67a0..1bee8f8e 100644 --- a/src/components/button.style.js +++ b/src/components/button.style.js @@ -34,8 +34,8 @@ export default { directives: { '--defaultButtonHoverGlow': 'shadow | 0 0 4 --text', '--defaultButtonShadow': 'shadow | 0 0 2 #000000', - '--defaultButtonBevel': 'shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2)', - '--pressedButtonBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2)' + '--defaultButtonBevel': 'shadow | $borderSide(#FFFFFF, top, 0.2), $borderSide(#000000, bottom, 0.2)', + '--pressedButtonBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2), $borderSide(#000000, top, 0.2)' } }, { diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js index 431e1b94..3cd2f15f 100644 --- a/src/services/theme_data/iss_deserializer.js +++ b/src/services/theme_data/iss_deserializer.js @@ -1,24 +1,51 @@ +import { flattenDeep } from 'lodash' + +const parseShadow = string => { + const modes = ['_full', 'inset', 'x', 'y', 'blur', 'spread', 'color', 'alpha'] + const regexPrep = [ + // inset keyword (optional) + '^(?:(inset)\\s+)?', + // x + '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)', + // y + '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)', + // blur (optional) + '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?', + // spread (optional) + '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?', + // either hex, variable or function + '(#[0-9a-f]{6}|--[a-z\\-_]+|\\$[a-z\\-()_]+)', + // opacity (optional) + '(?:\\s+\\/\\s+([0-9]+(?:\\.[0-9]+)?)\\s*)?$' + ].join('') + const regex = new RegExp(regexPrep, 'gis') // global, (stable) indices, single-string + const result = regex.exec(string) + if (result == null) { + return string + } else { + return Object.fromEntries(modes.map((mode, i) => [mode, result[i]])) + } +} // this works nearly the same as HTML tree converter -export const deserialize = (input) => { - const buffer = [] +const parseIss = (input) => { + const buffer = [{ selector: null, content: [] }] let textBuffer = '' const getCurrentBuffer = () => { - let current = buffer[buffer.length - 1][1] + let current = buffer[buffer.length - 1] if (current == null) { - current = { name: null, content: [] } + current = { selector: null, content: [] } } - buffer.push(current) return current } // Processes current line buffer, adds it to output buffer and clears line buffer - const flushText = (content) => { + const flushText = (kind) => { if (textBuffer === '') return - if (content) { - getCurrentBuffer().content.push(textBuffer) + if (kind === 'content') { + getCurrentBuffer().content.push(textBuffer.trim()) } else { - getCurrentBuffer().name = textBuffer + getCurrentBuffer().selector = textBuffer.trim() } textBuffer = '' } @@ -27,17 +54,90 @@ export const deserialize = (input) => { const char = input[i] if (char === ';') { - flushText(true) + flushText('content') } else if (char === '{') { - flushText(false) + flushText('header') } else if (char === '}') { - buffer.push({ name: null, content: [] }) + flushText('content') + buffer.push({ selector: null, content: [] }) textBuffer = '' } else { textBuffer += char } } - flushText() return buffer } +export const deserialize = (input) => { + const ast = parseIss(input) + const finalResult = ast.filter(i => i.selector != null).map(item => { + const { selector, content } = item + let stateCount = 0 + const selectors = selector.split(/,/g) + const result = selectors.map(selector => { + const output = { component: '' } + let currentDepth = null + + selector.split(/ /g).reverse().forEach((fragment, index, arr) => { + const fragmentObject = { component: '' } + + let mode = 'component' + for (let i = 0; i < fragment.length; i++) { + const char = fragment[i] + switch (char) { + case '.': { + mode = 'variant' + fragmentObject.variant = '' + break + } + case ':': { + mode = 'state' + fragmentObject.state = fragmentObject.state || [] + stateCount++ + break + } + default: { + if (mode === 'state') { + const currentState = fragmentObject.state[stateCount - 1] + if (currentState == null) { + fragmentObject.state.push('') + } + fragmentObject.state[stateCount - 1] += char + } else { + fragmentObject[mode] += char + } + } + } + } + if (currentDepth !== null) { + currentDepth.parent = { ...fragmentObject } + currentDepth = currentDepth.parent + } else { + Object.keys(fragmentObject).forEach(key => { + output[key] = fragmentObject[key] + }) + if (index !== (arr.length - 1)) { + output.parent = { component: '' } + } + currentDepth = output + } + }) + + output.directives = Object.fromEntries(content.map(d => { + const [property, value] = d.split(':') + console.log(property, value) + let realValue = value.trim() + if (property === 'shadow') { + realValue = parseShadow(value.split(',').map(v => v.trim())) + } if (!Number.isNaN(Number(value))) { + realValue = Number(value) + } + return [property, realValue] + })) + + return output + }) + return result + }) + return flattenDeep(finalResult) +} diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js index 8d6e9333..6bba85e4 100644 --- a/src/services/theme_data/iss_serializer.js +++ b/src/services/theme_data/iss_serializer.js @@ -1,6 +1,12 @@ import { unroll } from './iss_utils.js' -const serializeShadow = s => `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}` +const serializeShadow = s => { + if (typeof s === 'object') { + return `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}` + } else { + return s + } +} export const serialize = (ruleset) => { return ruleset.map((rule) => { @@ -8,8 +14,8 @@ export const serialize = (ruleset) => { const header = unroll(rule).reverse().map(rule => { const { component } = rule - const newVariant = rule.variant === 'normal' ? '' : ('.' + rule.variant) - const newState = rule.state.filter(st => st !== 'normal') + const newVariant = (rule.variant == null || rule.variant === 'normal') ? '' : ('.' + rule.variant) + const newState = (rule.state || []).filter(st => st !== 'normal') return `${component}${newVariant}${newState.map(st => ':' + st).join('')}` }).join(' ') @@ -19,9 +25,9 @@ export const serialize = (ruleset) => { const [valType, newValue] = value.split('|') // only first one! intentional! switch (valType) { case 'shadow': - return ` ${directive}: ${newValue.map(serializeShadow).join(', ')}` + return ` ${directive}: ${valType.trim()} | ${newValue.map(serializeShadow).map(s => s.trim()).join(', ')}` default: - return ` ${directive}: ${newValue}` + return ` ${directive}: ${valType.trim()} | ${newValue.trim()}` } } else { switch (directive) { diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js index b98cbb98..39c8b74f 100644 --- a/src/services/theme_data/theme_data_3.service.js +++ b/src/services/theme_data/theme_data_3.service.js @@ -23,9 +23,6 @@ import { findRules } from './iss_utils.js' import { parseCssShadow } from './css_utils.js' -import { - serialize -} from './iss_serializer.js' // Ensuring the order of components const components = { diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index f1967144..3488801c 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -1,47 +1,16 @@ import { deserialize } from 'src/services/theme_data/iss_deserializer.js' +import { serialize } from 'src/services/theme_data/iss_serializer.js' +import Button from 'src/components/button.style.js' -/* eslint-disable quotes */ -const testData = ``` - Root { - --accent: color | #e2b188; - --badgeNotification: color | #e15932; - --bg: color | #0f161e; - --cBlue: color | #81beea; - --cGreen: color | #5dc94a; - --cOrange: color | #ffc459; - --cRed: color | #d31014; - --defaultButtonBevel: shadow | $borderSide(#FFFFFF, top, 0.2) | $borderSide(#000000, bottom, 0.2); - --defaultButtonHoverGlow: shadow | 0 0 4 --text; - --defaultButtonShadow: shadow | 0 0 2 #000000; - --defaultInputBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2); - --fg: color | #151e2b; - --font: generic | sans-serif; - --link: color | #e2b188; - --monoFont: generic | monospace; - --pressedButtonBevel: shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2); - --selectionBackground: color | --accent; - --selectionText: color | $textColor(--accent, --text, no-preserve); - --text: color | #b9b9ba; - --wallpaper: color | #0c1118; - background: transparent; - opacity: 0; - } +describe.only('ISS (de)serialization', () => { + describe('ISS deserialization', () => { + it('Output should = input', () => { + const normalized = Button.defaultRules.map(x => ({ component: 'Button', ...x })) + const serialized = serialize(normalized) + const deserialized = deserialize(serialized) + // deserialized.toString() - Root Underlay { - background: #000000; - opacity: 0.6; - } - - Root Underlay, test { - background: #000000; - opacity: 0.6; - } - ``` - -describe.only('html_tree_converter', () => { - describe('convertHtmlToTree', () => { - it('should parse ISS correctly', () => { - console.log(deserialize(testData)) + expect(JSON.stringify(deserialized)).to.equal(JSON.stringify(normalized)) }) }) }) From d8d766932a8b3caff7634ca1f9679525ce7123f1 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 02:07:27 +0300 Subject: [PATCH 16/25] cleanup --- src/services/theme_data/iss_deserializer.js | 1 - test/unit/specs/services/theme_data/iss_deserializer.spec.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js index 3cd2f15f..8d4c987e 100644 --- a/src/services/theme_data/iss_deserializer.js +++ b/src/services/theme_data/iss_deserializer.js @@ -125,7 +125,6 @@ export const deserialize = (input) => { output.directives = Object.fromEntries(content.map(d => { const [property, value] = d.split(':') - console.log(property, value) let realValue = value.trim() if (property === 'shadow') { realValue = parseShadow(value.split(',').map(v => v.trim())) diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index 3488801c..d7d96130 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -4,12 +4,12 @@ import Button from 'src/components/button.style.js' describe.only('ISS (de)serialization', () => { describe('ISS deserialization', () => { - it('Output should = input', () => { + it('Output should equal input', () => { const normalized = Button.defaultRules.map(x => ({ component: 'Button', ...x })) const serialized = serialize(normalized) const deserialized = deserialize(serialized) - // deserialized.toString() + // for some reason comparing objects directly fails the assert expect(JSON.stringify(deserialized)).to.equal(JSON.stringify(normalized)) }) }) From dae206add31955484850f40be3f1dde7303a404d Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 02:07:46 +0300 Subject: [PATCH 17/25] remove 'only' --- test/unit/specs/services/theme_data/iss_deserializer.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index d7d96130..7654fb53 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -2,7 +2,7 @@ import { deserialize } from 'src/services/theme_data/iss_deserializer.js' import { serialize } from 'src/services/theme_data/iss_serializer.js' import Button from 'src/components/button.style.js' -describe.only('ISS (de)serialization', () => { +describe('ISS (de)serialization', () => { describe('ISS deserialization', () => { it('Output should equal input', () => { const normalized = Button.defaultRules.map(x => ({ component: 'Button', ...x })) From 1124ace7f62b7564bd85b66e618dfb3ed2e551e6 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 11:19:16 +0300 Subject: [PATCH 18/25] lack of changelog --- changelog.d/piss-serialization.skip | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 changelog.d/piss-serialization.skip diff --git a/changelog.d/piss-serialization.skip b/changelog.d/piss-serialization.skip new file mode 100644 index 00000000..e69de29b From 48f0a95a3bf53321d950f23e480607cf94349751 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 12:50:05 +0300 Subject: [PATCH 19/25] more tests, fixed some issues --- src/components/alert.style.js | 4 ++- src/components/button_unstyled.style.js | 3 +- src/components/input.style.js | 2 +- src/components/panel_header.style.js | 1 - src/services/theme_data/iss_deserializer.js | 23 ++++++++---- src/services/theme_data/iss_serializer.js | 2 +- .../theme_data/iss_deserializer.spec.js | 36 +++++++++++++++---- 7 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/components/alert.style.js b/src/components/alert.style.js index 19bd4bbb..abbeb5ba 100644 --- a/src/components/alert.style.js +++ b/src/components/alert.style.js @@ -27,7 +27,9 @@ export default { component: 'Alert' }, component: 'Border', - textColor: '--parent' + directives: { + textColor: '--parent' + } }, { variant: 'error', diff --git a/src/components/button_unstyled.style.js b/src/components/button_unstyled.style.js index 65b5c57b..435f9cc6 100644 --- a/src/components/button_unstyled.style.js +++ b/src/components/button_unstyled.style.js @@ -16,8 +16,7 @@ export default { { directives: { background: '#ffffff', - opacity: 0, - shadow: [] + opacity: 0 } }, { diff --git a/src/components/input.style.js b/src/components/input.style.js index 139a0034..7302cd6d 100644 --- a/src/components/input.style.js +++ b/src/components/input.style.js @@ -26,7 +26,7 @@ export default { { component: 'Root', directives: { - '--defaultInputBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2)| $borderSide(#000000, top, 0.2)' + '--defaultInputBevel': 'shadow | $borderSide(#FFFFFF, bottom, 0.2), $borderSide(#000000, top, 0.2)' } }, { diff --git a/src/components/panel_header.style.js b/src/components/panel_header.style.js index 32464bc5..7c145758 100644 --- a/src/components/panel_header.style.js +++ b/src/components/panel_header.style.js @@ -17,7 +17,6 @@ export default { directives: { backgroundNoCssColor: 'yes', background: '--fg', - shadow: [] } } ] diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js index 8d4c987e..5d71f35f 100644 --- a/src/services/theme_data/iss_deserializer.js +++ b/src/services/theme_data/iss_deserializer.js @@ -6,13 +6,13 @@ const parseShadow = string => { // inset keyword (optional) '^(?:(inset)\\s+)?', // x - '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)', + '(?:(-?[0-9]+(?:\\.[0-9]+)?)\\s+)', // y - '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)', + '(?:(-?[0-9]+(?:\\.[0-9]+)?)\\s+)', // blur (optional) - '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?', + '(?:(-?[0-9]+(?:\\.[0-9]+)?)\\s+)?', // spread (optional) - '(?:([0-9]+(?:\\.[0-9]+)?)\\s+)?', + '(?:(-?[0-9]+(?:\\.[0-9]+)?)\\s+)?', // either hex, variable or function '(#[0-9a-f]{6}|--[a-z\\-_]+|\\$[a-z\\-()_]+)', // opacity (optional) @@ -23,7 +23,18 @@ const parseShadow = string => { if (result == null) { return string } else { - return Object.fromEntries(modes.map((mode, i) => [mode, result[i]])) + const numeric = new Set(['x', 'y', 'blur', 'spread', 'alpha']) + const { x, y, blur, spread, alpha, inset, color } = Object.fromEntries(modes.map((mode, i) => { + if (numeric.has(mode)) { + return [mode, Number(result[i])] + } else if (mode === 'inset') { + return [mode, !!result[i]] + } else { + return [mode, result[i]] + } + }).filter(([k, v]) => v !== false).slice(1)) + + return { x, y, blur, spread, color, alpha, inset } } } // this works nearly the same as HTML tree converter @@ -127,7 +138,7 @@ export const deserialize = (input) => { const [property, value] = d.split(':') let realValue = value.trim() if (property === 'shadow') { - realValue = parseShadow(value.split(',').map(v => v.trim())) + realValue = value.split(',').map(v => parseShadow(v.trim())) } if (!Number.isNaN(Number(value))) { realValue = Number(value) } diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js index 6bba85e4..959852b7 100644 --- a/src/services/theme_data/iss_serializer.js +++ b/src/services/theme_data/iss_serializer.js @@ -2,7 +2,7 @@ import { unroll } from './iss_utils.js' const serializeShadow = s => { if (typeof s === 'object') { - return `{${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}}` + return `${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}` } else { return s } diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index 7654fb53..6141015c 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -1,16 +1,40 @@ import { deserialize } from 'src/services/theme_data/iss_deserializer.js' import { serialize } from 'src/services/theme_data/iss_serializer.js' -import Button from 'src/components/button.style.js' +const componentsContext = require.context('src', true, /\.style.js(on)?$/) -describe('ISS (de)serialization', () => { - describe('ISS deserialization', () => { - it('Output should equal input', () => { - const normalized = Button.defaultRules.map(x => ({ component: 'Button', ...x })) +describe.only('ISS (de)serialization', () => { + componentsContext.keys().forEach(key => { + const component = componentsContext(key).default + + it(`(De)serialization of component ${component.name} works`, () => { + const normalized = component.defaultRules.map(x => ({ component: component.name, ...x })) const serialized = serialize(normalized) const deserialized = deserialize(serialized) // for some reason comparing objects directly fails the assert - expect(JSON.stringify(deserialized)).to.equal(JSON.stringify(normalized)) + expect(JSON.stringify(deserialized, null, 2)).to.equal(JSON.stringify(normalized, null, 2)) }) }) + + /* + // Debug snippet + const onlyComponent = componentsContext('./components/panel_header.style.js').default + it(`(De)serialization of component ${onlyComponent.name} works`, () => { + const normalized = onlyComponent.defaultRules.map(x => ({ component: onlyComponent.name, ...x })) + console.log('BEGIN INPUT ================') + console.log(normalized) + console.log('END INPUT ==================') + const serialized = serialize(normalized) + console.log('BEGIN SERIAL ===============') + console.log(serialized) + console.log('END SERIAL =================') + const deserialized = deserialize(serialized) + console.log('BEGIN DESERIALIZED =========') + console.log(serialized) + console.log('END DESERIALIZED ===========') + + // for some reason comparing objects directly fails the assert + expect(JSON.stringify(deserialized, null, 2)).to.equal(JSON.stringify(normalized, null, 2)) + }) + */ }) From b5da1f8b89ddbfcb7bb5ad0c53005ddd93c1ba48 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 12:54:47 +0300 Subject: [PATCH 20/25] fix lint --- src/components/panel_header.style.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/panel_header.style.js b/src/components/panel_header.style.js index 7c145758..010e42cd 100644 --- a/src/components/panel_header.style.js +++ b/src/components/panel_header.style.js @@ -16,7 +16,7 @@ export default { component: 'PanelHeader', directives: { backgroundNoCssColor: 'yes', - background: '--fg', + background: '--fg' } } ] From 14328917f1a25770f90dc2181fad090ace4954da Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 20 Sep 2024 14:25:36 +0300 Subject: [PATCH 21/25] only --- test/unit/specs/services/theme_data/iss_deserializer.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index 6141015c..01f8dacf 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -2,7 +2,7 @@ import { deserialize } from 'src/services/theme_data/iss_deserializer.js' import { serialize } from 'src/services/theme_data/iss_serializer.js' const componentsContext = require.context('src', true, /\.style.js(on)?$/) -describe.only('ISS (de)serialization', () => { +describe('ISS (de)serialization', () => { componentsContext.keys().forEach(key => { const component = componentsContext(key).default From 32d82f10d9e8ffd8b55f777f8865087981abdea7 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 21 Sep 2024 11:56:34 +0300 Subject: [PATCH 22/25] remove .only --- test/unit/specs/components/gallery.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/specs/components/gallery.spec.js b/test/unit/specs/components/gallery.spec.js index 108e2b6b..3c92ae26 100644 --- a/test/unit/specs/components/gallery.spec.js +++ b/test/unit/specs/components/gallery.spec.js @@ -1,6 +1,6 @@ import Gallery from 'src/components/gallery/gallery.vue' -describe.only('Gallery', () => { +describe('Gallery', () => { let local it('attachments is falsey', () => { From ab8907909b1cb02b091e6ed22b7a2806bc837f33 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Sep 2024 00:23:25 +0300 Subject: [PATCH 23/25] add 'none' keyword to PISS shadow definiton that equals empty array --- src/components/button_unstyled.style.js | 3 ++- src/components/panel_header.style.js | 3 ++- src/services/theme_data/iss_deserializer.js | 6 +++++- src/services/theme_data/iss_serializer.js | 6 +++++- .../unit/specs/services/theme_data/iss_deserializer.spec.js | 4 ++-- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/button_unstyled.style.js b/src/components/button_unstyled.style.js index 435f9cc6..65b5c57b 100644 --- a/src/components/button_unstyled.style.js +++ b/src/components/button_unstyled.style.js @@ -16,7 +16,8 @@ export default { { directives: { background: '#ffffff', - opacity: 0 + opacity: 0, + shadow: [] } }, { diff --git a/src/components/panel_header.style.js b/src/components/panel_header.style.js index 010e42cd..32464bc5 100644 --- a/src/components/panel_header.style.js +++ b/src/components/panel_header.style.js @@ -16,7 +16,8 @@ export default { component: 'PanelHeader', directives: { backgroundNoCssColor: 'yes', - background: '--fg' + background: '--fg', + shadow: [] } } ] diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js index 5d71f35f..909e9411 100644 --- a/src/services/theme_data/iss_deserializer.js +++ b/src/services/theme_data/iss_deserializer.js @@ -138,7 +138,11 @@ export const deserialize = (input) => { const [property, value] = d.split(':') let realValue = value.trim() if (property === 'shadow') { - realValue = value.split(',').map(v => parseShadow(v.trim())) + if (realValue === 'none') { + realValue = [] + } else { + realValue = value.split(',').map(v => parseShadow(v.trim())) + } } if (!Number.isNaN(Number(value))) { realValue = Number(value) } diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js index 959852b7..8b7cf5d8 100644 --- a/src/services/theme_data/iss_serializer.js +++ b/src/services/theme_data/iss_serializer.js @@ -32,7 +32,11 @@ export const serialize = (ruleset) => { } else { switch (directive) { case 'shadow': - return ` ${directive}: ${value.map(serializeShadow).join(', ')}` + if (value.length > 0) { + return ` ${directive}: ${value.map(serializeShadow).join(', ')}` + } else { + return ` ${directive}: none` + } default: return ` ${directive}: ${value}` } diff --git a/test/unit/specs/services/theme_data/iss_deserializer.spec.js b/test/unit/specs/services/theme_data/iss_deserializer.spec.js index 01f8dacf..6eb25dfe 100644 --- a/test/unit/specs/services/theme_data/iss_deserializer.spec.js +++ b/test/unit/specs/services/theme_data/iss_deserializer.spec.js @@ -19,7 +19,7 @@ describe('ISS (de)serialization', () => { /* // Debug snippet const onlyComponent = componentsContext('./components/panel_header.style.js').default - it(`(De)serialization of component ${onlyComponent.name} works`, () => { + it.only(`(De)serialization of component ${onlyComponent.name} works`, () => { const normalized = onlyComponent.defaultRules.map(x => ({ component: onlyComponent.name, ...x })) console.log('BEGIN INPUT ================') console.log(normalized) @@ -36,5 +36,5 @@ describe('ISS (de)serialization', () => { // for some reason comparing objects directly fails the assert expect(JSON.stringify(deserialized, null, 2)).to.equal(JSON.stringify(normalized, null, 2)) }) - */ + /* */ }) From 7a7ed917b369c44b62edde52c01ef615f476ed47 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 24 Sep 2024 00:26:05 +0300 Subject: [PATCH 24/25] """changelog""" --- changelog.d/piss-fix.skip | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 changelog.d/piss-fix.skip diff --git a/changelog.d/piss-fix.skip b/changelog.d/piss-fix.skip new file mode 100644 index 00000000..e69de29b From 6335a205c80336c70f4ac4d68e6f3ec305994070 Mon Sep 17 00:00:00 2001 From: Kian-ting Tan Date: Wed, 11 Sep 2024 12:34:58 +0000 Subject: [PATCH 25/25] Translated using Weblate (Chinese (Min Nan) (nan_TW)) Currently translated at 91.6% (1093 of 1193 strings) Translation: Pleroma/Pleroma-FE Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nan_TW/ --- src/i18n/nan-TW.json | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/i18n/nan-TW.json b/src/i18n/nan-TW.json index 782a75f5..44a693dd 100644 --- a/src/i18n/nan-TW.json +++ b/src/i18n/nan-TW.json @@ -190,7 +190,8 @@ "mobile_notifications_close": "關掉通知", "announcements": "公告", "search": "Tshuē", - "mobile_notifications_mark_as_seen": "Lóng 標做有讀" + "mobile_notifications_mark_as_seen": "Lóng 標做有讀", + "quotes": "引用" }, "notifications": { "broken_favorite": "狀態毋知影,leh tshiau-tshuē……", @@ -212,7 +213,8 @@ "unread_follow_requests": "{num}ê新ê跟tuè請求", "configuration_tip": "用{theSettings},lí通自訂siánn物佇tsia顯示。{dismiss}", "configuration_tip_settings": "設定", - "configuration_tip_dismiss": "Mài koh顯示" + "configuration_tip_dismiss": "Mài koh顯示", + "subscribed_status": "有發送ê" }, "polls": { "add_poll": "開投票", @@ -252,7 +254,8 @@ }, "load_all_hint": "載入頭前 {saneAmount} ê 繪文字,規个攏載入效能可能 ē khah 食力。", "load_all": "Kā {emojiAmount} ê 繪文字攏載入", - "regional_indicator": "地區指引 {letter}" + "regional_indicator": "地區指引 {letter}", + "hide_custom_emoji": "Khàm掉自訂ê繪文字" }, "errors": { "storage_unavailable": "Pleroma buē-tàng the̍h 著瀏覽器儲存 ê。Lí ê 登入狀態抑是局部設定 buē 儲存,mā 凡勢 tú 著意料外 ê 問題。拍開 cookie 看māi。" @@ -263,7 +266,8 @@ "emoji_reactions": "繪文字 ê 反應", "reports": "檢舉", "moves": "用者 ê 移民", - "load_older": "載入 koh khah 早 ê 互動" + "load_older": "載入 koh khah 早 ê 互動", + "statuses": "訂ê" }, "post_status": { "edit_status": "編輯狀態", @@ -935,7 +939,34 @@ "notification_extra_chats": "顯示bô讀ê開講", "notification_extra_announcements": "顯示bô讀ê公告", "notification_extra_follow_requests": "顯示新ê跟tuè請求", - "notification_extra_tip": "顯示自訂其他通知ê撇步" + "notification_extra_tip": "顯示自訂其他通知ê撇步", + "confirm_new_setting": "Lí敢確認新ê設定?", + "text_size_tip": "用 {0} 做絕對值,{1} ē根據瀏覽器ê標準文字sài-suh放大縮小。", + "theme_debug": "佇處理透明ê時,顯示背景主題ia̋n-jín 所假使ê(DEBUG)", + "units": { + "time": { + "s": "秒鐘", + "m": "分鐘", + "h": "點鐘", + "d": "工" + } + }, + "actor_type": "Tsit ê口座是:", + "actor_type_Person": "一般ê用者", + "actor_type_description": "標記lí ê口座做群組,ē hōo自動轉送提起伊ê狀態。", + "actor_type_Group": "群組", + "actor_type_Service": "機器lâng", + "appearance": "外觀", + "confirm_new_question": "Tse看起來kám好?設定ē佇10秒鐘後改轉去。", + "revert": "改轉去", + "confirm": "確認", + "text_size": "文字kap界面ê sài-suh", + "text_size_tip2": "毋是 {0} ê值可能ē破壞一寡物件kap主題", + "emoji_size": "繪文字ê sài-suh", + "navbar_size": "頂 liâu-á êsài-suh", + "panel_header_size": "面pang標題ê sài-suh", + "visual_tweaks": "細細ê外觀調整", + "scale_and_layout": "界面ê sài-suh kap排列" }, "status": { "favorites": "收藏", @@ -1001,7 +1032,7 @@ "show_only_conversation_under_this": "Kan-ta顯示tsit ê狀態ê回應", "status_history": "狀態ê歷史", "reaction_count_label": "{num}ê lâng用表情反應", - "hide_quote": "Khàm條引用ê狀態", + "hide_quote": "Khàm掉引用ê狀態", "display_quote": "顯示引用ê狀態", "invisible_quote": "引用ê狀態bē當用:{link}", "more_actions": "佇tsit ê狀態ê其他動作"