diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 34af3774f..000000000 --- a/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -build/*.js -config/*.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 361cff5f2..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,27 +0,0 @@ -module.exports = { - root: true, - parserOptions: { - parser: '@babel/eslint-parser', - sourceType: 'module' - }, - // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style - extends: [ - 'standard', - 'plugin:vue/recommended' - ], - // required to lint *.vue files - plugins: [ - 'vue' - ], - // add your custom rules here - rules: { - // allow paren-less arrow functions - 'arrow-parens': 0, - // allow async-await - 'generator-star-spacing': 0, - // allow debugger during development - 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, - 'vue/require-prop-types': 0, - 'vue/multi-word-component-names': 0 - } -} diff --git a/.gitattributes b/.gitattributes index c5b9ea10e..1bea4dc8f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -/build/webpack.prod.conf.js export-subst +/build/commit_hash.js export-subst diff --git a/.gitignore b/.gitignore index 0d5befd28..01ffda9a8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ test/e2e/reports selenium-debug.log .idea/ config/local.json -static/emoji.json +src/assets/emoji.json logs/ +__screenshots__/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4c5cf43a..99c85dd36 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ # This file is a template, and might need editing before it works on your project. # Official framework image. Look for the different tagged releases at: # https://hub.docker.com/r/library/node/tags/ -image: node:16 +image: node:18 stages: - check-changelog @@ -38,8 +38,8 @@ lint: stage: lint script: - yarn - - npm run lint - - npm run stylelint + - yarn lint + - yarn stylelint test: stage: test @@ -50,10 +50,15 @@ test: APT_CACHE_DIR: apt-cache script: - mkdir -pv $APT_CACHE_DIR && apt-get -qq update - - apt install firefox-esr -y --no-install-recommends - - firefox --version - yarn - - yarn unit + - yarn playwright install firefox + - yarn playwright install-deps + - yarn unit-ci + artifacts: + # When the test fails, upload screenshots for better context on why it fails + paths: + - test/**/__screenshots__ + when: on_failure build: stage: build @@ -62,7 +67,7 @@ build: - himem script: - yarn - - npm run build + - yarn build artifacts: paths: - dist/ diff --git a/.gitlab/merge_request_templates/Release.md b/.gitlab/merge_request_templates/Release.md new file mode 100644 index 000000000..d02e14a73 --- /dev/null +++ b/.gitlab/merge_request_templates/Release.md @@ -0,0 +1,8 @@ +### Release checklist +* [ ] Bump version in `package.json` +* [ ] Compile a changelog with the `tools/collect-changelog` script +* [ ] Create an MR with an announcement to pleroma.social +#### post-merge +* [ ] Tag the release on the merge commit +* [ ] Make the tag into a Gitlab Release™ +* [ ] Merge `master` into `develop` (in case the fixes are already in develop, use `git merge -s ours --no-commit` and manually merge the changelogs) diff --git a/.node-version b/.node-version index 5397c87fa..08b7109d0 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16.18.1 +18.20.8 diff --git a/.stylelintrc.json b/.stylelintrc.json index d6689cc01..afdfd5f5b 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1,6 +1,5 @@ { "extends": [ - "stylelint-rscss/config", "stylelint-config-standard", "stylelint-config-recommended-scss", "stylelint-config-html", @@ -8,20 +7,13 @@ ], "rules": { "declaration-no-important": true, - "rscss/no-descendant-combinator": false, - "rscss/class-format": [ - false, - { - "component": "pascal-case", - "variant": "^-[a-z]\\w+", - "element": "^[a-z]\\w+" - } - ], "selector-class-pattern": null, "import-notation": null, "custom-property-pattern": null, "keyframes-name-pattern": null, "scss/operator-no-newline-after": null, + "declaration-property-value-no-unknown": true, + "scss/declaration-property-value-no-unknown": true, "declaration-block-no-redundant-longhand-properties": [ true, { diff --git a/CHANGELOG.md b/CHANGELOG.md index 9844319e3..20c9c2693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,114 @@ 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.9.3 +### Fixed +- Being unable to update profile + +## 2.9.2 +### Changed +- BREAKING: due to some internal technical changes logging into AdminFE through PleromaFE is no longer possible +- User card/profile got an overhaul +- Profile editing overhaul +- Visually combined subject and content fields in post form +- Moved post form's emoji button into input field +- Minor visual changes and fixes +- Clicking on fav/rt/emoji notifications' contents expands/collapses it +- Reduced time taken processing theme by half +- Splash screen only appears if loading takes more than 2 seconds + +### Added +- Mutes received an update, adding support for regex, muting based on username and expiration time. +- Mutes are now synchronized across sessions +- Support for expiring mutes and blocks (if available) +- Clicking on emoji shows bigger version of it alongside with its shortcode + - Admins also are able to copy it into a local pack +- Added support for Akkoma and IceShrimp.NET backends +- Compatibility with stricter CSP (Akkoma backend) +- Added a way to upload new packs from a URL or ZIP file via the Admin Dashboard +- Unify show/hide content buttons +- Add support for detachable scrollTop button +- Option to left-align user bio +- Cache assets and emojis with service worker +- Indicate currently active V3 theme as a body element class +- Add arithmetic blend ISS function + +### Fixed +- Display counter for status action buttons when they are in the menu +- Fix bookmark button alignment in the extra actions menu +- Instance favicons are no longer stretched +- A lot more scalable UI fixes + - Emoji picker now should work fine when emoji size is increased + +## 2.8.0 +### Changed +- BREAKING: static/img/nsfw.2958239.png is now static/img/nsfw.DepQPhG0.png, which may affect people who specify exactly this path as the cover image +- BREAKING: static/emoji.json is replaced with a properly hashed path under static/js in the production build, meaning server admins cannot provide their own set of unicode emojis by overriding this file (custom (image-based) emojis not affected) +- Speed up initial boot. +- 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. + +- Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes +- Modal layout for mobile has new layout to make it easy to use +- Better display of mute reason on posts +- Simplify the OAuth client_name to 'PleromaFE' +- Partially migrated from vuex to pinia +- Authenticate and subscribe to streaming after connection +- Tabs now have indentation for better visibility of which tab is currently active +- Upgraded Vue to version 3.5 + +### Added +- Support bookmark folders +- Some new default color schemes +- Added support for fetching /{resource}.custom.ext to allow adding instance-specific themes without altering sourcetree +- Post actions customization +- Support displaying time in absolute format +- Add draft management system +- Compress most kinds of images on upload. +- Added option to always convert images to JPEG format instead of using WebP when compressing images. +- Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload. +- Inform users that Smithereen public polls are public +- Splash screen + loading indicator to make process of identifying initialization issues and load performance +- UI for making v3 themes and palettes, support for bundling v3 themes +- Make UserLink wrappable + +### Fixed +- Fixed occasional overflows in emoji picker and made header scrollable +- Updated shadow editor, hopefully fixed long-standing bugs, added ability to specify shadow's name. +- Checkbox vertical alignment +- Check for canvas extract permission when initializing favicon service +- Fix some of the color manipulation functions +- Fix draft saving when auto-save is off +- Switch from class hack to normalButton attribute for emoji count popover +- Fix emoji inconsistencies in notifications, +- Fix some emoji not scaling with interface +- Make sure hover style is also applied to :focus-visible +- Improved ToS and registration +- Fix small markup inconsistencies +- Fixed modals buttons overflow +- Fix whitespaces for multiple status mute reasons, display bot status reason +- Create an OAuth app only when needed +- Fix CSS compatibility issues in style_setter.js for older browsers like Palemoon +- Proper sticky header for conversations on user page +- Add text label for more actions button in post status form +- Reply-or-quote buttons now take less space +- Allow repeats of own posts with private scopes +- Bookmarks visible again on mobile +- Remove focusability on hidden popover in subject input +- Show only month and day instead of weird "day, hour" format. + +### Removed +- BREAKING: drop support for browsers that do not support ` diff --git a/package.json b/package.json index 403a2b231..21d75f0fb 100644 --- a/package.json +++ b/package.json @@ -1,137 +1,122 @@ { "name": "pleroma_fe", - "version": "2.7.1", + "version": "2.9.3", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors ", "private": false, "scripts": { - "dev": "node build/dev-server.js", - "build": "node build/build.js", - "unit": "karma start test/unit/karma.conf.js --single-run", - "unit:watch": "karma start test/unit/karma.conf.js --single-run=false", + "dev": "node build/update-emoji.js && vite dev", + "build": "node build/update-emoji.js && vite build", + "unit": "node build/update-emoji.js && vitest --run", + "unit-ci": "node build/update-emoji.js && vitest --run --browser.headless", + "unit:watch": "node build/update-emoji.js && vitest", "e2e": "node test/e2e/runner.js", - "test": "npm run unit && npm run e2e", - "stylelint": "npx stylelint '**/*.scss' '**/*.vue'", - "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs", - "lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs" + "test": "yarn run unit && yarn run e2e", + "stylelint": "yarn exec stylelint '**/*.scss' '**/*.vue'", + "lint": "eslint src test/unit/specs test/e2e/specs", + "lint-fix": "eslint --fix src test/unit/specs test/e2e/specs" }, "dependencies": { - "@babel/runtime": "7.21.5", + "@babel/runtime": "7.28.4", "@chenfengyuan/vue-qrcode": "2.0.0", - "@fortawesome/fontawesome-svg-core": "6.4.0", - "@fortawesome/free-regular-svg-icons": "6.4.0", - "@fortawesome/free-solid-svg-icons": "6.4.0", - "@fortawesome/vue-fontawesome": "3.0.3", - "@kazvmoe-infra/pinch-zoom-element": "1.2.0", + "@fortawesome/fontawesome-svg-core": "7.1.0", + "@fortawesome/free-regular-svg-icons": "7.1.0", + "@fortawesome/free-solid-svg-icons": "7.1.0", + "@fortawesome/vue-fontawesome": "3.1.2", + "@kazvmoe-infra/pinch-zoom-element": "1.3.0", "@kazvmoe-infra/unicode-emoji-json": "0.4.0", - "@ruffle-rs/ruffle": "0.1.0-nightly.2024.8.21", + "@ruffle-rs/ruffle": "0.1.0-nightly.2025.6.22", "@vuelidate/core": "2.0.3", "@vuelidate/validators": "2.0.4", + "@web3-storage/parse-link-header": "^3.1.0", "body-scroll-lock": "3.1.5", "chromatism": "3.0.0", "click-outside-vue3": "4.0.1", - "cropperjs": "1.5.13", + "cropperjs": "2.0.1", "escape-html": "1.0.3", + "globals": "^16.0.0", "hash-sum": "^2.0.0", "js-cookie": "3.0.5", "localforage": "1.10.0", "parse-link-header": "2.0.0", - "phoenix": "1.7.7", - "punycode.js": "2.3.0", - "qrcode": "1.5.3", + "phoenix": "1.8.1", + "pinia": "^3.0.0", + "punycode.js": "2.3.1", + "qrcode": "1.5.4", "querystring-es3": "0.2.1", - "url": "0.11.0", + "url": "0.11.4", "utf8": "3.0.0", - "vue": "3.2.45", - "vue-i18n": "9.2.2", - "vue-router": "4.1.6", - "vue-template-compiler": "2.7.14", + "uuid": "11.1.0", + "vue": "3.5.22", + "vue-i18n": "11", + "vue-router": "4.5.1", "vue-virtual-scroller": "^2.0.0-beta.7", "vuex": "4.1.0" }, "devDependencies": { - "@babel/core": "7.21.8", - "@babel/eslint-parser": "7.21.8", - "@babel/plugin-transform-runtime": "7.21.4", - "@babel/preset-env": "7.21.5", - "@babel/register": "7.21.0", - "@intlify/vue-i18n-loader": "5.0.1", + "@babel/core": "7.28.4", + "@babel/eslint-parser": "7.28.4", + "@babel/plugin-transform-runtime": "7.28.3", + "@babel/preset-env": "7.28.3", + "@babel/register": "7.28.3", "@ungap/event-target": "0.2.4", + "@vitejs/plugin-vue": "^5.2.1", + "@vitejs/plugin-vue-jsx": "^4.1.1", + "@vitest/browser": "^3.0.7", + "@vitest/ui": "^3.0.7", "@vue/babel-helper-vue-jsx-merge-props": "1.4.0", - "@vue/babel-plugin-jsx": "1.2.2", - "@vue/compiler-sfc": "3.2.45", - "@vue/test-utils": "2.2.8", - "autoprefixer": "10.4.19", - "babel-loader": "9.1.3", + "@vue/babel-plugin-jsx": "1.5.0", + "@vue/compiler-sfc": "3.5.22", + "@vue/test-utils": "2.4.6", + "autoprefixer": "10.4.21", "babel-plugin-lodash": "3.3.4", - "chai": "4.3.7", - "chalk": "1.1.3", - "chromedriver": "108.0.0", + "chai": "5.3.3", + "chalk": "5.6.2", + "chromedriver": "135.0.4", "connect-history-api-fallback": "2.0.0", - "copy-webpack-plugin": "11.0.0", - "cross-spawn": "7.0.3", - "css-loader": "6.10.0", - "css-minimizer-webpack-plugin": "4.2.2", + "cross-spawn": "7.0.6", "custom-event-polyfill": "1.0.7", - "eslint": "8.33.0", - "eslint-config-standard": "17.0.0", + "eslint": "9.37.0", + "vue-eslint-parser": "10.2.0", + "eslint-config-standard": "17.1.0", "eslint-formatter-friendly": "7.0.0", - "eslint-plugin-import": "2.27.5", - "eslint-plugin-n": "15.6.1", - "eslint-plugin-promise": "6.1.1", - "eslint-plugin-vue": "9.9.0", - "eslint-webpack-plugin": "3.2.0", + "eslint-plugin-import": "2.32.0", + "eslint-plugin-n": "17.23.1", + "eslint-plugin-promise": "7.2.1", + "eslint-plugin-vue": "10.5.0", "eventsource-polyfill": "0.9.6", - "express": "4.18.2", - "function-bind": "1.1.1", - "html-webpack-plugin": "5.5.1", - "http-proxy-middleware": "2.0.6", - "iso-639-1": "2.1.15", - "json-loader": "0.5.7", - "karma": "6.4.4", - "karma-coverage": "2.2.0", - "karma-firefox-launcher": "2.1.3", - "karma-mocha": "2.0.1", - "karma-mocha-reporter": "2.2.5", - "karma-sinon-chai": "2.0.2", - "karma-sourcemap-loader": "0.3.8", - "karma-spec-reporter": "0.0.36", - "karma-webpack": "5.0.0", + "express": "5.1.0", + "function-bind": "1.1.2", + "http-proxy-middleware": "3.0.5", + "iso-639-1": "3.1.5", "lodash": "4.17.21", - "mini-css-extract-plugin": "2.7.6", - "mocha": "10.2.0", - "nightwatch": "2.6.25", - "opn": "5.5.0", - "ora": "0.4.1", - "postcss": "8.4.23", + "msw": "2.10.5", + "nightwatch": "3.12.2", + "playwright": "1.55.0", + "postcss": "8.5.6", "postcss-html": "^1.5.0", - "postcss-loader": "7.0.2", "postcss-scss": "^4.0.6", - "sass": "1.60.0", - "sass-loader": "13.2.2", - "selenium-server": "2.53.1", - "semver": "7.3.8", - "serviceworker-webpack5-plugin": "2.0.0", - "shelljs": "0.8.5", - "sinon": "15.0.4", - "sinon-chai": "3.7.0", - "stylelint": "14.16.1", + "sass": "1.93.2", + "selenium-server": "3.141.59", + "semver": "7.7.3", + "serve-static": "2.2.0", + "shelljs": "0.10.0", + "sinon": "20.0.0", + "sinon-chai": "4.0.1", + "stylelint": "16.25.0", "stylelint-config-html": "^1.1.0", - "stylelint-config-recommended-scss": "^8.0.0", - "stylelint-config-recommended-vue": "^1.4.0", - "stylelint-config-standard": "29.0.0", - "stylelint-rscss": "0.4.0", - "stylelint-webpack-plugin": "^3.3.0", - "vue-loader": "17.0.1", - "vue-style-loader": "4.1.3", - "webpack": "5.75.0", - "webpack-dev-middleware": "3.7.3", - "webpack-hot-middleware": "2.25.3", - "webpack-merge": "0.20.0" + "stylelint-config-recommended": "^16.0.0", + "stylelint-config-recommended-scss": "^14.0.0", + "stylelint-config-recommended-vue": "^1.6.0", + "stylelint-config-standard": "38.0.0", + "vite": "^6.1.0", + "vite-plugin-eslint2": "^5.0.3", + "vite-plugin-stylelint": "^6.0.0", + "vitest": "^3.0.7" }, + "type": "module", "engines": { - "node": ">= 16.0.0", - "npm": ">= 3.0.0" + "node": ">= 16.0.0" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/postcss.config.js b/postcss.config.js index 88752c6cb..95ebbf2a6 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,7 @@ -module.exports = { +import autoprefixer from 'autoprefixer' + +export default { plugins: [ - require('autoprefixer') + autoprefixer ] } diff --git a/public/static/.gitignore b/public/static/.gitignore new file mode 100644 index 000000000..3332292a1 --- /dev/null +++ b/public/static/.gitignore @@ -0,0 +1 @@ +*.custom.* diff --git a/static/.gitkeep b/public/static/.gitkeep similarity index 100% rename from static/.gitkeep rename to public/static/.gitkeep diff --git a/static/aurora_borealis.jpg b/public/static/aurora_borealis.jpg similarity index 100% rename from static/aurora_borealis.jpg rename to public/static/aurora_borealis.jpg diff --git a/static/config.json b/public/static/config.json similarity index 92% rename from static/config.json rename to public/static/config.json index fb39ff77f..6df21bb9e 100644 --- a/static/config.json +++ b/public/static/config.json @@ -24,6 +24,8 @@ "showInstanceSpecificPanel": false, "sidebarRight": false, "subjectLineBehavior": "email", - "theme": "pleroma-dark", + "theme": null, + "style": "BreezyDX", + "palette": "sigsegv2", "webPushNotifications": false } diff --git a/static/logo.svg b/public/static/logo.svg similarity index 100% rename from static/logo.svg rename to public/static/logo.svg diff --git a/public/static/palettes/index.json b/public/static/palettes/index.json new file mode 100644 index 000000000..2cd110d1e --- /dev/null +++ b/public/static/palettes/index.json @@ -0,0 +1,75 @@ +{ + "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", + "bg": "#161c20", + "fg": "#282e32", + "text": "#b9b9b9", + "link": "#baaa9c", + "cRed": "#d31014", + "cGreen": "#0fa00f", + "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", + "bg": "#1d1f21", + "fg": "#373b41", + "link": "#81a2be", + "text": "#c5c8c6", + "cRed": "#cc6666", + "cBlue": "#8abeb7", + "cGreen": "#b5bd68", + "cOrange": "#de935f" + }, + "dracula": { + "name": "Dracula", + "bg": "#282A36", + "fg": "#44475A", + "link": "#BC92F9", + "text": "#f8f8f2", + "cRed": "#FF5555", + "cBlue": "#8BE9FD", + "cGreen": "#50FA7B", + "cOrange": "#FFB86C" + }, + "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ], + "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ], + "purple-stream": { + "name": "Purple stream", + "bg": "#17171A", + "fg": "#450F92", + "link": "#8769B4", + "text": "#C0C0C5", + "cRed": "#EB0300", + "cBlue": "#4656FF", + "cGreen": "#B0E020", + "cOrange": "#FF9046" + }, + "feud": { + "name": "Feud", + "bg": "#323337", + "fg": "#1D1E21", + "link": "#18A0E3", + "accent": "#6671E2", + "text": "#DBDDE0", + "cRed": "#E05053", + "cBlue": "#6671E2", + "cGreen": "#3A8D5D", + "cOrange": "#DCAA45" + }, + "constabulary": { + "name": "Constabulary", + "bg": "#FFFFFF", + "fg": "#3B5897", + "link": "#28487C", + "text": "#333333", + "cRed": "#FA3C4C", + "cBlue": "#0083FF", + "cGreen": "#44BDC6", + "cOrange": "#FFC200" + } +} diff --git a/static/pleromatan_apology.png b/public/static/pleromatan_apology.png similarity index 100% rename from static/pleromatan_apology.png rename to public/static/pleromatan_apology.png diff --git a/static/pleromatan_apology_fox.png b/public/static/pleromatan_apology_fox.png similarity index 100% rename from static/pleromatan_apology_fox.png rename to public/static/pleromatan_apology_fox.png diff --git a/public/static/pleromatan_apology_fox_small.webp b/public/static/pleromatan_apology_fox_small.webp new file mode 100644 index 000000000..eacbf3cbf Binary files /dev/null and b/public/static/pleromatan_apology_fox_small.webp differ diff --git a/public/static/pleromatan_apology_small.webp b/public/static/pleromatan_apology_small.webp new file mode 100644 index 000000000..e27e06d06 Binary files /dev/null and b/public/static/pleromatan_apology_small.webp differ diff --git a/static/pleromatan_orz.png b/public/static/pleromatan_orz.png similarity index 100% rename from static/pleromatan_orz.png rename to public/static/pleromatan_orz.png diff --git a/static/pleromatan_orz_fox.png b/public/static/pleromatan_orz_fox.png similarity index 100% rename from static/pleromatan_orz_fox.png rename to public/static/pleromatan_orz_fox.png diff --git a/public/static/splash.css b/public/static/splash.css new file mode 100644 index 000000000..f56f33d07 --- /dev/null +++ b/public/static/splash.css @@ -0,0 +1,132 @@ +body { + margin: 0; + padding: 0; +} + +#splash { + --scale: 1; + + width: 100vw; + height: 100vh; + display: grid; + grid-template-rows: auto; + grid-template-columns: auto; + align-content: center; + place-items: center; + flex-direction: column; + background: #0f161e; + font-family: sans-serif; + color: #b9b9ba; + position: absolute; + z-index: 9999; + font-size: calc(1vw + 1vh + 1vmin); + opacity: 1; + transition: opacity 500ms ease-out 2s; +} + +#splash.hidden, +#splash.initial-hidden { + opacity: 0; +} + +#splash-credit { + position: absolute; + font-size: 1em; + bottom: 1em; + right: 1em; +} + +#splash-container { + align-items: center; +} + +#mascot-container { + display: flex; + align-items: flex-end; + justify-content: center; + perspective: 60em; + perspective-origin: 0 -15em; + transform-style: preserve-3d; +} + +#mascot { + width: calc(10em * var(--scale)); + height: calc(10em * var(--scale)); + object-fit: contain; + object-position: bottom; + transform: translateZ(-2em); +} + +#throbber { + display: grid; + width: calc(5em * 0.5 * var(--scale)); + height: calc(8em * 0.5 * var(--scale)); + margin-left: 4.1em; + z-index: 2; + grid-template-rows: repeat(8, 1fr); + grid-template-columns: repeat(5, 1fr); + grid-template-areas: "P P . L L" + "P P . L L" + "P P . L L" + "P P . L L" + "P P . . ." + "P P . . ." + "P P . E E" + "P P . E E"; + + --logoChunkSize: calc(2em * 0.5 * var(--scale)) +} + +.chunk { + background-color: #e2b188; + box-shadow: 0.01em 0.01em 0.1em 0 #e2b188; +} + +#chunk-P { + grid-area: P; + border-top-left-radius: calc(var(--logoChunkSize) / 2); +} + +#chunk-L { + grid-area: L; + border-bottom-right-radius: calc(var(--logoChunkSize) / 2); +} + +#chunk-E { + grid-area: E; + border-bottom-right-radius: calc(var(--logoChunkSize) / 2); +} + +#status { + margin-top: 1em; + line-height: 2; + width: 100%; + text-align: center; +} + +#statusError { + display: none; + margin-top: 1em; + font-size: calc(1vw + 1vh + 1vmin); + line-height: 2; + width: 100%; + text-align: center; +} + +#statusStack { + display: none; + margin-top: 1em; + font-size: calc((1vw + 1vh + 1vmin) / 2.5); + width: calc(100vw - 5em); + padding: 1em; + text-overflow: ellipsis; + overflow-x: hidden; + text-align: left; + line-height: 2; +} + +@media (prefers-reduced-motion) { + #throbber { + animation: none !important; + } +} diff --git a/public/static/styles.json b/public/static/styles.json new file mode 100644 index 000000000..2f836a47a --- /dev/null +++ b/public/static/styles.json @@ -0,0 +1,11 @@ +{ + "pleroma-dark": "/static/themes/pleroma-dark.json", + "pleroma-light": "/static/themes/pleroma-light.json", + "redmond-xx": "/static/themes/redmond-xx.json", + "redmond-xx-se": "/static/themes/redmond-xx-se.json", + "redmond-xxi": "/static/themes/redmond-xxi.json", + "breezy-dark": "/static/themes/breezy-dark.json", + "breezy-light": "/static/themes/breezy-light.json", + "mammal": "/static/themes/mammal.json", + "paper": "/static/themes/paper.json" +} diff --git a/public/static/styles/Breezy DX.iss b/public/static/styles/Breezy DX.iss new file mode 100644 index 000000000..69cc3befe --- /dev/null +++ b/public/static/styles/Breezy DX.iss @@ -0,0 +1,102 @@ +@meta { + name: Breezy DX; + author: HJ; + license: WTFPL; + website: ebin.club; +} + +@palette.Dark { + bg: #292C32; + fg: #292C32; + text: #ffffff; + link: #1CA4F3; + accent: #1CA4F3; + cRed: #f41a51; + cBlue: #1CA4F3; + cGreen: #1af46e; + cOrange: #f4af1a; +} + +@palette.Light { + bg: #EFF0F2; + fg: #EFF0F2; + text: #1B1F22; + underlay: #5d6086; + accent: #1CA4F3; + cBlue: #1CA4F3; + cRed: #f41a51; + cGreen: #0b6a30; + cOrange: #f4af1a; + border: #d8e6f9; + link: #1CA4F3; +} + +@palette.Panda { + bg: #EFF0F2; + fg: #292C32; + text: #1B1F22; + link: #1CA4F3; + accent: #1CA4F3; + cRed: #f41a51; + cBlue: #1CA4F3; + cGreen: #0b6a30; + cOrange: #f4af1a; +} + +Root { + --badgeNotification: color | --cRed; + --buttonDefaultHoverGlow: shadow | inset 0 0 0 1 --accent / 1; + --buttonDefaultFocusGlow: shadow | inset 0 0 0 1 --accent / 1; + --buttonDefaultShadow: shadow | inset 0 0 0 1 --text / 0.35, 0 5 5 -5 #000000 / 0.35; + --buttonDefaultBevel: shadow | inset 0 14 14 -14 #FFFFFF / 0.1; + --buttonPressedBevel: shadow | inset 0 -20 20 -20 #000000 / 0.05; + --defaultInputBevel: shadow | inset 0 0 0 1 --text / 0.35; + --defaultInputHoverGlow: shadow | 0 0 0 1 --accent / 1; + --defaultInputFocusGlow: shadow | 0 0 0 1 --link / 1; +} + +Button { + background: --parent; +} + +Button:disabled { + shadow: --buttonDefaultBevel, --buttonDefaultShadow +} + +Button:hover { + background: --inheritedBackground; + shadow: --buttonDefaultHoverGlow, --buttonDefaultBevel, --buttonDefaultShadow +} + +Button:toggled { + background: $blend(--inheritedBackground 0.3 --accent) +} + +Button:pressed { + background: $blend(--inheritedBackground 0.8 --accent) +} + +Button:pressed:toggled { + background: $blend(--inheritedBackground 0.2 --accent) +} + +Button:toggled:hover { + background: $blend(--inheritedBackground 0.3 --accent) +} + +Input { + shadow: --defaultInputBevel; + background: $mod(--bg -10); +} + +PanelHeader { + shadow: inset 0 30 30 -30 #ffffff / 0.25 +} + +Tab:hover { + shadow: --buttonDefaultHoverGlow, --buttonDefaultBevel, --buttonDefaultShadow +} + +Tab { + background: --bg; +} diff --git a/public/static/styles/Redmond DX.iss b/public/static/styles/Redmond DX.iss new file mode 100644 index 000000000..919be056b --- /dev/null +++ b/public/static/styles/Redmond DX.iss @@ -0,0 +1,201 @@ +@meta { + name: Redmond DX; + author: HJ; + license: WTFPL; + website: ebin.club; +} + +@palette.Modern { + bg: #D3CFC7; + fg: #092369; + text: #000000; + link: #0000FF; + accent: #A5C9F0; + cRed: #FF3000; + cBlue: #009EFF; + cGreen: #309E00; + cOrange: #FFCE00; +} + +@palette.Classic { + bg: #BFBFBF; + fg: #000180; + text: #000000; + link: #0000FF; + accent: #A5C9F0; + cRed: #FF0000; + cBlue: #2E2ECE; + cGreen: #007E00; + cOrange: #CE8F5F; +} + +@palette.Vapor { + bg: #F0ADCD; + fg: #bca4ee; + text: #602040; + link: #064745; + accent: #9DF7C8; + cRed: #86004a; + cBlue: #0e5663; + cGreen: #0a8b51; + cOrange: #787424; +} + +Root { + --gradientColor: color | --accent; + --inputColor: color | #FFFFFF; + --bevelLight: color | $brightness(--bg 50); + --bevelDark: color | $brightness(--bg -20); + --bevelExtraDark: color | #404040; + --buttonDefaultBevel: shadow | $borderSide(--bevelExtraDark bottom-right 1 1), $borderSide(--bevelLight top-left 1 1), $borderSide(--bevelDark bottom-right 1 2); + --buttonPressedFocusedBevel: shadow | inset 0 0 0 1 #000000 / 1 #Outer , inset 0 0 0 2 --bevelExtraDark / 1 #inner; + --buttonPressedBevel: shadow | $borderSide(--bevelDark top-left 1 1), $borderSide(--bevelLight bottom-right 1 1), $borderSide(--bevelExtraDark top-left 1 2); + --defaultInputBevel: shadow | $borderSide(--bevelDark top-left 1 1), $borderSide(--bevelLight bottom-right 1 1), $borderSide(--bevelExtraDark top-left 1 2), $borderSide(--bg bottom-right 1 2); +} + +Button:toggled { + background: --bg; + shadow: --buttonPressedBevel +} + +Button:focused { + shadow: --buttonDefaultBevel, 0 0 0 1 #000000 / 1 +} + +Button:pressed { + shadow: --buttonPressedBevel +} + +Button:hover { + shadow: --buttonDefaultBevel; + background: --bg +} + +Button { + shadow: --buttonDefaultBevel; + background: --bg; + roundness: 0 +} + +Button:pressed:hover { + shadow: --buttonPressedBevel +} + +Button:hover:pressed:focused { + shadow: --buttonPressedFocusedBevel +} + +Button:pressed:focused { + shadow: --buttonPressedFocusedBevel +} + +Button:toggled:pressed { + shadow: --buttonPressedFocusedBevel +} + +Input { + background: $boost(--bg 20); + shadow: --defaultInputBevel; + roundness: 0 +} + +Input:focused { + shadow: inset 0 0 0 1 #000000 / 1, --defaultInputBevel +} + +Input:focused:hover { + shadow: --defaultInputBevel +} + +Input:focused:hover:disabled { + shadow: --defaultInputBevel +} + +Input:hover { + shadow: --defaultInputBevel +} + +Input:disabled { + shadow: --defaultInputBevel +} + +Panel { + shadow: --buttonDefaultBevel; + roundness: 0 +} + +PanelHeader { + shadow: inset -1100 0 1000 -1000 --gradientColor / 1 #Gradient ; + background: --fg +} + +PanelHeader ButtonUnstyled Icon { + textColor: --text; + textAuto: 'no-preserve' +} + +PanelHeader Button Icon { + textColor: --text; + textAuto: 'no-preserve' +} + +PanelHeader Button Text { + textColor: --text; + textAuto: 'no-preserve' +} + +Tab:hover { + background: --bg; + shadow: --buttonDefaultBevel +} + +Tab:active { + background: --bg +} + +Tab:active:hover { + background: --bg; + shadow: --defaultButtonBevel +} + +Tab:active:hover:disabled { + background: --bg +} + +Tab:hover:disabled { + background: --bg +} + +Tab:disabled { + background: --bg +} + +Tab { + background: --bg; + shadow: --buttonDefaultBevel +} + +Tab:hover:active { + shadow: --buttonDefaultBevel +} + +TopBar Link { + textColor: #ffffff +} + +MenuItem:hover { + background: --fg +} + +MenuItem:active { + background: --fg +} + +MenuItem:active:hover { + background: --fg +} + +Popover { + shadow: --buttonDefaultBevel, 5 5 0 0 #000000 / 0.2; + roundness: 0 +} diff --git a/public/static/styles/index.json b/public/static/styles/index.json new file mode 100644 index 000000000..6c1dd1676 --- /dev/null +++ b/public/static/styles/index.json @@ -0,0 +1,4 @@ +{ + "RedmondDX": "/static/styles/Redmond DX.iss", + "BreezyDX": "/static/styles/Breezy DX.iss" +} diff --git a/static/terms-of-service.html b/public/static/terms-of-service.html similarity index 100% rename from static/terms-of-service.html rename to public/static/terms-of-service.html diff --git a/static/themes/breezy-dark.json b/public/static/themes/breezy-dark.json similarity index 100% rename from static/themes/breezy-dark.json rename to public/static/themes/breezy-dark.json diff --git a/static/themes/breezy-light.json b/public/static/themes/breezy-light.json similarity index 100% rename from static/themes/breezy-light.json rename to public/static/themes/breezy-light.json diff --git a/static/themes/mammal.json b/public/static/themes/mammal.json similarity index 100% rename from static/themes/mammal.json rename to public/static/themes/mammal.json diff --git a/static/themes/paper.json b/public/static/themes/paper.json similarity index 100% rename from static/themes/paper.json rename to public/static/themes/paper.json diff --git a/static/themes/pleroma-dark.json b/public/static/themes/pleroma-dark.json similarity index 100% rename from static/themes/pleroma-dark.json rename to public/static/themes/pleroma-dark.json diff --git a/static/themes/pleroma-light.json b/public/static/themes/pleroma-light.json similarity index 100% rename from static/themes/pleroma-light.json rename to public/static/themes/pleroma-light.json diff --git a/static/themes/redmond-xx-se.json b/public/static/themes/redmond-xx-se.json similarity index 100% rename from static/themes/redmond-xx-se.json rename to public/static/themes/redmond-xx-se.json diff --git a/static/themes/redmond-xx.json b/public/static/themes/redmond-xx.json similarity index 100% rename from static/themes/redmond-xx.json rename to public/static/themes/redmond-xx.json diff --git a/static/themes/redmond-xxi.json b/public/static/themes/redmond-xxi.json similarity index 100% rename from static/themes/redmond-xxi.json rename to public/static/themes/redmond-xxi.json diff --git a/src/App.js b/src/App.js index e87108dd9..0027d908a 100644 --- a/src/App.js +++ b/src/App.js @@ -14,9 +14,14 @@ import EditStatusModal from './components/edit_status_modal/edit_status_modal.vu import PostStatusModal from './components/post_status_modal/post_status_modal.vue' import StatusHistoryModal from './components/status_history_modal/status_history_modal.vue' import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' +import { getOrCreateServiceWorker } from './services/sw/sw' import { windowWidth, windowHeight } from './services/window_utils/window_utils' import { mapGetters } from 'vuex' import { defineAsyncComponent } from 'vue' +import { useShoutStore } from './stores/shout' +import { useInterfaceStore } from './stores/interface' + +import { throttle } from 'lodash' export default { name: 'app', @@ -45,27 +50,57 @@ export default { mobileActivePanel: 'timeline' }), watch: { - themeApplied (value) { + themeApplied () { this.removeSplash() + }, + currentTheme () { + this.setThemeBodyClass() + }, + layoutType () { + document.getElementById('modal').classList = ['-' + this.layoutType] } }, created () { // Load the locale from the storage const val = this.$store.getters.mergedConfig.interfaceLanguage this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) - window.addEventListener('resize', this.updateMobileState) + document.getElementById('modal').classList = ['-' + this.layoutType] + + // Create bound handlers + this.updateScrollState = throttle(this.scrollHandler, 200) + this.updateMobileState = throttle(this.resizeHandler, 200) }, mounted () { - if (this.$store.state.interface.themeApplied) { + window.addEventListener('resize', this.updateMobileState) + this.scrollParent.addEventListener('scroll', this.updateScrollState) + + if (useInterfaceStore().themeApplied) { + this.setThemeBodyClass() this.removeSplash() } + getOrCreateServiceWorker() }, unmounted () { window.removeEventListener('resize', this.updateMobileState) + this.scrollParent.removeEventListener('scroll', this.updateScrollState) }, computed: { themeApplied () { - return this.$store.state.interface.themeApplied + return useInterfaceStore().themeApplied + }, + currentTheme () { + if (useInterfaceStore().styleDataUsed) { + const styleMeta = useInterfaceStore().styleDataUsed.find(x => x.component === '@meta') + + if (styleMeta !== undefined) { + return styleMeta.directives.name.replaceAll(" ", "-").toLowerCase() + } + } + + return 'stock' + }, + layoutModalClass () { + return '-' + this.layoutType }, classes () { return [ @@ -99,7 +134,7 @@ export default { } } }, - shout () { return this.$store.state.shout.joined }, + shout () { return useShoutStore().joined }, suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled }, showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel && @@ -125,7 +160,7 @@ export default { hideShoutbox () { return this.$store.getters.mergedConfig.hideShoutbox }, - layoutType () { return this.$store.state.interface.layoutType }, + layoutType () { return useInterfaceStore().layoutType }, privateMode () { return this.$store.state.instance.private }, reverseLayout () { const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig @@ -137,12 +172,41 @@ export default { }, noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders }, showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars }, + scrollParent () { return window; /* this.$refs.appContentRef */ }, ...mapGetters(['mergedConfig']) }, methods: { - updateMobileState () { - this.$store.dispatch('setLayoutWidth', windowWidth()) - this.$store.dispatch('setLayoutHeight', windowHeight()) + resizeHandler () { + useInterfaceStore().setLayoutWidth(windowWidth()) + useInterfaceStore().setLayoutHeight(windowHeight()) + }, + scrollHandler () { + const scrollPosition = this.scrollParent === window ? window.scrollY : this.scrollParent.scrollTop + + if (scrollPosition != 0) { + this.$refs.appContentRef.classList.add(['-scrolled']) + } else { + this.$refs.appContentRef.classList.remove(['-scrolled']) + } + }, + setThemeBodyClass () { + const themeName = this.currentTheme + const classList = Array.from(document.body.classList) + const oldTheme = classList.filter(c => c.startsWith('theme-')) + + if (themeName !== null && themeName !== '') { + const newTheme = `theme-${themeName.toLowerCase()}` + + // remove old theme reference if there are any + if (oldTheme.length) { + document.body.classList.replace(oldTheme[0], newTheme) + } else { + document.body.classList.add(newTheme) + } + } else { + // remove theme reference if non-V3 theme is used + document.body.classList.remove(...oldTheme) + } }, removeSplash () { document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4)) @@ -150,6 +214,9 @@ export default { splashscreenRoot.addEventListener('transitionend', () => { splashscreenRoot.remove() }) + setTimeout(() => { + splashscreenRoot.remove() // forcibly remove it, should fix my plasma browser widget t. HJ + }, 600) splashscreenRoot.classList.add('hidden') document.querySelector('#app').classList.remove('hidden') } diff --git a/src/App.scss b/src/App.scss index f52ba06b9..1eee63a7e 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1,6 +1,9 @@ // stylelint-disable rscss/class-format /* stylelint-disable no-descending-specificity */ -@import "./panel"; +@use "panel"; + +@import '@fortawesome/fontawesome-svg-core/styles.css'; +@import '@kazvmoe-infra/pinch-zoom-element/dist/pinch-zoom.css'; :root { --status-margin: 0.75em; @@ -18,7 +21,7 @@ } html { - font-size: var(--textSize, 14px); + font-size: var(--textSize, 1rem); --navbar-height: var(--navbarSize, 3.5rem); --emoji-size: var(--emojiSize, 32px); @@ -30,12 +33,12 @@ body { font-family: sans-serif; font-family: var(--font); margin: 0; + padding: 0; color: var(--text); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overscroll-behavior-y: none; - overflow-x: clip; - overflow-y: scroll; + overflow: clip scroll; &.hidden { display: none; @@ -224,9 +227,8 @@ nav { grid-template-rows: 1fr; box-sizing: border-box; margin: 0 auto; - align-content: flex-start; + place-content: flex-start center; flex-wrap: wrap; - justify-content: center; min-height: 100vh; overflow-x: clip; @@ -262,8 +264,7 @@ nav { position: sticky; top: var(--navbar-height); max-height: calc(100vh - var(--navbar-height)); - overflow-y: auto; - overflow-x: hidden; + overflow: hidden auto; margin-left: calc(var(--___paddingIncrease) * -1); padding-left: calc(var(--___paddingIncrease) + var(--___columnMargin) / 2); @@ -381,6 +382,10 @@ nav { font-family: sans-serif; font-family: var(--font); + &.-transparent { + backdrop-filter: blur(0.125em) contrast(60%); + } + &::-moz-focus-inner { border: none; } @@ -388,39 +393,35 @@ nav { &:disabled { cursor: not-allowed; } + + &:active { + transform: translate(1px, 1px); + } } -.menu-item, -.list-item { - display: block; - box-sizing: border-box; - border: none; - outline: none; - text-align: initial; - font-size: inherit; +.menu-item { + line-height: var(--__line-height); font-family: inherit; font-weight: 400; + font-size: 100%; cursor: pointer; - color: inherit; - clear: both; - position: relative; - white-space: nowrap; + + a, + button:not(.button-default) { + color: var(--text); + font-size: 100%; + } + + &.disabled { + cursor: not-allowed; + } +} + +.list-item { border-color: var(--border); border-style: solid; border-width: 0; border-top-width: 1px; - width: 100%; - line-height: var(--__line-height); - padding: var(--__vertical-gap) var(--__horizontal-gap); - background: transparent; - - --__line-height: 1.5em; - --__horizontal-gap: 0.75em; - --__vertical-gap: 0.5em; - - &.-non-interactive { - cursor: auto; - } &.-active, &:hover { @@ -442,20 +443,6 @@ nav { border-bottom-width: 1px; } - a, - button:not(.button-default) { - text-align: initial; - padding: 0; - background: none; - border: none; - outline: none; - display: inline; - font-size: 100%; - font-family: inherit; - line-height: unset; - color: var(--text); - } - &:first-child { border-top-right-radius: var(--roundness); border-top-left-radius: var(--roundness); @@ -469,6 +456,42 @@ nav { } } +.menu-item, +.list-item { + display: block; + box-sizing: border-box; + border: none; + outline: none; + text-align: initial; + color: inherit; + clear: both; + position: relative; + white-space: nowrap; + width: 100%; + padding: var(--__vertical-gap) var(--__horizontal-gap); + background: transparent; + + --__line-height: 1.5em; + --__horizontal-gap: 0.75em; + --__vertical-gap: 0.5em; + + &.-non-interactive { + cursor: auto; + } + + a, + button:not(.button-default) { + text-align: initial; + padding: 0; + background: none; + border: none; + outline: none; + display: inline; + font-family: inherit; + line-height: unset; + } +} + .button-unstyled { border: none; outline: none; @@ -490,6 +513,12 @@ nav { } } +label { + &.-disabled { + color: var(--textFaint); + } +} + input, textarea { border: none; @@ -506,6 +535,10 @@ textarea { height: unset; } + &::placeholder { + color: var(--textFaint) + } + --_padding: 0.5em; border: none; @@ -526,6 +559,10 @@ textarea { &[disabled="disabled"], &.disabled { cursor: not-allowed; + color: var(--textFaint); + + /* stylelint-disable-next-line declaration-no-important */ + background-color: transparent !important; } &[type="range"] { @@ -551,6 +588,8 @@ textarea { & + label::before { opacity: 0.5; } + + background-color: var(--background); } + label::before { @@ -650,7 +689,8 @@ option { list-style: none; display: grid; grid-auto-flow: row dense; - grid-template-columns: 1fr 1fr; + grid-template-columns: repeat(auto-fit, minmax(20em, 1fr)); + grid-gap: 0.5em; li { border: 1px solid var(--border); @@ -660,11 +700,6 @@ option { } } -.btn-block { - display: block; - width: 100%; -} - .btn-group { position: relative; display: inline-flex; @@ -676,7 +711,6 @@ option { --_roundness-right: 0; position: relative; - flex: 1 1 auto; } > *:first-child, @@ -723,17 +757,15 @@ option { } &.-dot { - min-height: 8px; - max-height: 8px; - min-width: 8px; - max-width: 8px; - padding: 0; + min-height: 0.6em; + max-height: 0.6em; + min-width: 0.6em; + max-width: 0.6em; + left: calc(50% + 0.5em); + top: calc(50% - 1em); line-height: 0; - font-size: 0; - left: calc(50% - 4px); - top: calc(50% - 4px); - margin-left: 6px; - margin-top: -6px; + padding: 0; + margin: 0; } &.-counter { @@ -764,12 +796,6 @@ option { color: var(--text); } -.visibility-notice { - padding: 0.5em; - border: 1px solid var(--textFaint); - border-radius: var(--roundness); -} - .notice-dismissible { padding-right: 4rem; position: relative; @@ -814,7 +840,7 @@ option { .login-hint { text-align: center; - @media all and (min-width: 801px) { + @media all and (width >= 801px) { display: none; } @@ -836,7 +862,7 @@ option { flex: 1; } -@media all and (max-width: 800px) { +@media all and (width <= 800px) { .mobile-hidden { display: none; } @@ -917,12 +943,7 @@ option { #splash { pointer-events: none; - transition: opacity 2s; - opacity: 1; - - &.hidden { - opacity: 0; - } + // transition: opacity 0.5s; #status { &.css-ok { @@ -946,7 +967,7 @@ option { &.dead { animation-name: dead; - animation-duration: 2s; + animation-duration: 0.5s; animation-iteration-count: 1; transform: rotateX(90deg) rotateY(0) rotateZ(-45deg); } @@ -1061,7 +1082,7 @@ option { scale: 1.0063 0.9938; translate: 0 -10%; transform: rotateZ(var(--defaultZ)); - animation-timing-function: ease-in-ou; + animation-timing-function: ease-in-out; } 90% { @@ -1080,3 +1101,8 @@ option { } } } + +@property --shadow { + syntax: "*"; + inherits: false; +} diff --git a/src/App.vue b/src/App.vue index 9d7ad9129..e5e088bc3 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@