diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 000000000..df2d47160 --- /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/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c5b9ea10e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/build/webpack.prod.conf.js export-subst diff --git a/.gitignore b/.gitignore index 4df5ec838..0d5befd28 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ selenium-debug.log .idea/ config/local.json static/emoji.json +logs/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 305155d84..de3beccca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,23 +1,51 @@ # 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 - lint - build - test - deploy +# https://git.pleroma.social/help/ci/yaml/workflow.md#switch-between-branch-pipelines-and-merge-request-pipelines +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS + when: never + - if: $CI_COMMIT_BRANCH + +check-changelog: + stage: check-changelog + image: alpine + rules: + - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^renovate/ + when: never + - if: $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == 'pleroma/pleroma-fe' && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == 'weblate' + when: never + - if: $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" + before_script: '' + after_script: '' + cache: {} + script: + - apk add git + - sh ./tools/check-changelog + lint: stage: lint script: - yarn - - npm run lint - - npm run stylelint + - yarn lint + - yarn stylelint test: stage: test + tags: + - amd64 + - himem variables: APT_CACHE_DIR: apt-cache script: @@ -29,9 +57,12 @@ test: build: stage: build + tags: + - amd64 + - himem script: - yarn - - npm run build + - yarn build artifacts: paths: - dist/ diff --git a/.node-version b/.node-version index 5397c87fa..1fc51668f 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16.18.1 +18.20.6 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fb729315..9844319e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,105 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.7.1 +Bugfix release. Added small optimizations to emoji picker that should make it a bit more responsive, however it needs rather large change to make it more performant which might come in a major release. + +### Fixed +- Instance default theme not respected +- Nested panel header having wrong sticky position if navbar height != panel header height +- Toggled buttons having bad contrast (when using v2 theme) + +### Changed +- Simplify the OAuth client_name to 'PleromaFE' +- Small optimizations to emoji picker + + +## 2.7.0 + +### Known issues +We got some reports related to emoji picker performance, this hopefully will be fixed in 2.7.1. + +### Notes +This release overhauls how themes work, themes now need to be "compiled", which can cause some delay when loading for the first time and temporarily look "wrong" in some places (popups, menus, dialogs). Please do report any issues, especially if your theme looks wrong or breaks interface when loading. Also report issues if you're experiencing constant performance issues. + +To admins: remember that you can update PleromaFE to recent `master` or `develop` in admin dashboard in "Front-ends" tab, scroll down to find PleromaFE box and click "Reinstall `master`" or dropdown and then "Reinstall `develop`". Currently there is no mechanism to check if there is an update or not. + +### Changed +- Overhauled the way themes work, migrating to new Pleroma Interface Style Sheets system aka "Themes 3". +- Notifications are no longer sorted by "seen" status since interacting with them can change their read status and makes UI jumpy. Old behavior can be restored in settings. +- Notifications are now shown through a ServiceWorker (since mobile chrome does not allow them otherwise), it's always enabled, even if previously we only enabled it for WebPush notifications only. If you don't like websites "running" while closed, check how to disable them in your browser. Old way to show notifications will be used as a fallback but might not have all the new features. +- Reorganized Settings modal to move out visual stuff into Appearance tab + +### Added +- Emoji pack management to the admin panel +- Support `status` notification type (subscriptions/bell, fixes PleromaFE on newer PleromaBE versions) +- Poll end notifications. +- Added option to not mark all notifications when closing notifications drawer on mobile, this creates a new button to mark all as seen. +- Option to always "show" notifications when using web push for better compatibility with some browsers (chrome, edge, safari) +- Option to toggle what notification types appear in native notifications, by default less important ones (likes, repeats, etc) will no longer show up in native notifications. +- Option to treat non-interactive notifications (likes, repeats et all) as seen for visual purposes (no read mark, ignored in counters, still can show in native notifications) +- Ability to resize UI (and certain components) scale independent of browser/text scale +- Ability to override certain aspects of UI style independent of theme used (UI roundness, fonts, underlay) +- Theme selector with visual previews of the theme +- Display loading and error indicator for conversation page +- Option to only show scrobbles that are recent enough +- Interacting (opening reply box etc) or simply clicking on non-interactive notifications now marks them as read. Clicking on native notifications for non-interactive ones also marks them as seen. +- Support group actors +- Focusing into a tab clears all current desktop notifications +- Ability to change size of emoji +- Ability to view APNG (Animated PNG) attachments. +- Support showing extra notifications in the notifications column +- Create a link to the URL of the scrobble when it's present +- Allow hiding custom emojis in picker. +- Ability to mute sensitive posts (ported from eintei). +- Native notifications now also have "badge" property that matches instance's favicon (visible in Android Chromium at least) +- Display public favorites on user profiles +- Display quotes count on posts and add quotes list page +- Show a dedicated registration notice page when further action is required after registering + +### Fixed +- Synchronized requested notification types with backend, hopefully should fix missing notifications for polls and follow requests +- Error that appeared on mobile Chromium (and derivatives) when native notifications are allowed +- Being unable to set notification visibility for reports and follow requests +- Native notifications appearing as many times as there are open tabs. Clicking on notification will focus last focused tab. +- The expiry date indication won't be shown if the poll never expires +- Profile mentions causing a 422 error on newer PleromaBE versions. +- Color inputs are less ugly now +- Unread notifications should now properly catch up between sessions (eventually) in polling mode +- Video posters on Safari + + +## 2.6.1 +### Fixed +- fix admin dashboard not having any feedback on frontend installation +- Fix frontend admin tab crashing when no primary frontend is set +- Add aria attributes to react and extra buttons + +## 2.6.0 +### Added +- add the initial i18n translation file for Taiwanese (Hokkien), and modify some related files. +- Implemented a very basic instance administration screen +- Implement quoting + +### Fixed +- Keep aspect ratio of custom emoji reaction in notification +- Fix openSettingsModalTab so that it correctly opens Settings modal instead of Admin modal +- Add alt text to emoji picker buttons +- Use export-subst gitattribute to allow tarball builds +- fix reports now showing reason/content +- Fix HTML attribute parsing, discard attributes not strating with a letter +- Make MentionsLine aware of line breaking by non-br elements +- Fix a bug where mentioning a user twice will not fill the mention into the textarea +- Fix parsing non-ascii tags +- Fix OAuth2 token lingering after revocation +- fix regex issue in HTML parser/renderer +- don't display quoted status twice +- fix typo in code that prevented cards from showing at all +- Fix react button not working if reaction accounts are not loaded +- Fix react button misalignment on safari ios +- Fix pinned statuses gone when reloading user timeline +- Fix scrolling emoji selector in modal in safari ios + ## 2.5.1 ### Fixed - Checkboxes in settings can now work with screenreaders diff --git a/build/build.js b/build/build.js index 8242bc5f6..99ca49c06 100644 --- a/build/build.js +++ b/build/build.js @@ -9,7 +9,7 @@ var ora = require('ora') var webpack = require('webpack') var webpackConfig = require('./webpack.prod.conf') -console.log( +console.info( ' Tip:\n' + ' Built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n' diff --git a/build/check-versions.js b/build/check-versions.js index e2b6cf74c..ed6256b3a 100644 --- a/build/check-versions.js +++ b/build/check-versions.js @@ -11,11 +11,6 @@ var versionRequirements = [ name: 'node', currentVersion: semver.clean(process.version), versionRequirement: packageConfig.engines.node - }, - { - name: 'npm', - currentVersion: exec('npm --version'), - versionRequirement: packageConfig.engines.npm } ] @@ -32,14 +27,12 @@ module.exports = function () { } if (warnings.length) { - console.log('') - console.log(chalk.yellow('To use this template, you must update following to modules:')) - console.log() + console.warn(chalk.yellow('\nTo use this template, you must update following to modules:\n')) for (var i = 0; i < warnings.length; i++) { var warning = warnings[i] - console.log(' ' + warning) + console.warn(' ' + warning) } - console.log() + console.warn() process.exit(1) } } diff --git a/build/dev-server.js b/build/dev-server.js index e51ba9484..145072e70 100644 --- a/build/dev-server.js +++ b/build/dev-server.js @@ -72,10 +72,10 @@ app.use(staticPath, express.static('./static')) module.exports = app.listen(port, function (err) { if (err) { - console.log(err) + console.error(err) return } var uri = 'http://localhost:' + port - console.log('Listening at ' + uri + '\n') + console.info('Listening at ' + uri + '\n') // opn(uri) }) diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 97799f828..2369e0e87 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -23,7 +23,8 @@ module.exports = merge(baseWebpackConfig, { 'COMMIT_HASH': JSON.stringify('DEV'), 'DEV_OVERRIDES': JSON.stringify(config.dev.settings), '__VUE_OPTIONS_API__': true, - '__VUE_PROD_DEVTOOLS__': false + '__VUE_PROD_DEVTOOLS__': false, + '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': false }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.HotModuleReplacementPlugin(), diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index 7de937213..4282e4bd0 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -11,9 +11,16 @@ var env = process.env.NODE_ENV === 'testing' ? require('../config/test.env') : config.build.env -let commitHash = require('child_process') - .execSync('git rev-parse --short HEAD') - .toString(); +let commitHash = (() => { + const subst = "$Format:%h$"; + if(!subst.match(/Format:/)) { + return subst; + } else { + return require('child_process') + .execSync('git rev-parse --short HEAD') + .toString(); + } +})(); var webpackConfig = merge(baseWebpackConfig, { mode: 'production', @@ -43,7 +50,8 @@ var webpackConfig = merge(baseWebpackConfig, { 'COMMIT_HASH': JSON.stringify(commitHash), 'DEV_OVERRIDES': JSON.stringify(undefined), '__VUE_OPTIONS_API__': true, - '__VUE_PROD_DEVTOOLS__': false + '__VUE_PROD_DEVTOOLS__': false, + '__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': false }), // extract css into its own file new MiniCssExtractPlugin({ diff --git a/changelog.d/backend-repo-url.skip b/changelog.d/backend-repo-url.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/batch2.skip b/changelog.d/batch2.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/better-shadow-control.fix b/changelog.d/better-shadow-control.fix new file mode 100644 index 000000000..585ef6d26 --- /dev/null +++ b/changelog.d/better-shadow-control.fix @@ -0,0 +1 @@ +Updated shadow editor, hopefully fixed long-standing bugs, added ability to specify shadow's name. diff --git a/changelog.d/bookmark-folders.add b/changelog.d/bookmark-folders.add new file mode 100644 index 000000000..f22966602 --- /dev/null +++ b/changelog.d/bookmark-folders.add @@ -0,0 +1 @@ +Support bookmark folders diff --git a/changelog.d/browsers-support.change b/changelog.d/browsers-support.change new file mode 100644 index 000000000..a62e50240 --- /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/changelog.d/checkbox.fix b/changelog.d/checkbox.fix new file mode 100644 index 000000000..6a947ec8e --- /dev/null +++ b/changelog.d/checkbox.fix @@ -0,0 +1 @@ +checkbox vertical alignment has been fixed diff --git a/changelog.d/color-schemes.add b/changelog.d/color-schemes.add new file mode 100644 index 000000000..5410730e1 --- /dev/null +++ b/changelog.d/color-schemes.add @@ -0,0 +1 @@ +Some new default color schemes diff --git a/changelog.d/colorfuncs.fix b/changelog.d/colorfuncs.fix new file mode 100644 index 000000000..18c49e2fc --- /dev/null +++ b/changelog.d/colorfuncs.fix @@ -0,0 +1 @@ +Fix some of the color manipulation functions diff --git a/changelog.d/custom.add b/changelog.d/custom.add new file mode 100644 index 000000000..97848d7e4 --- /dev/null +++ b/changelog.d/custom.add @@ -0,0 +1 @@ +Added support for fetching /{resource}.custom.ext to allow adding instance-specific themes without altering sourcetree diff --git a/changelog.d/customizable-actions.add b/changelog.d/customizable-actions.add new file mode 100644 index 000000000..5ce6a5180 --- /dev/null +++ b/changelog.d/customizable-actions.add @@ -0,0 +1 @@ +Post actions can be customized diff --git a/changelog.d/date-absolute.add b/changelog.d/date-absolute.add new file mode 100644 index 000000000..d9365f464 --- /dev/null +++ b/changelog.d/date-absolute.add @@ -0,0 +1 @@ +Support displaying time in absolute format diff --git a/changelog.d/denpmify-gitlab-ci.skip b/changelog.d/denpmify-gitlab-ci.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/deprecate-subscribe.change b/changelog.d/deprecate-subscribe.change new file mode 100644 index 000000000..10fb34f46 --- /dev/null +++ b/changelog.d/deprecate-subscribe.change @@ -0,0 +1 @@ +Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes \ No newline at end of file diff --git a/changelog.d/drafts-imp.skip b/changelog.d/drafts-imp.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/drafts.add b/changelog.d/drafts.add new file mode 100644 index 000000000..1147016e3 --- /dev/null +++ b/changelog.d/drafts.add @@ -0,0 +1 @@ +Add draft management system diff --git a/changelog.d/emoji-picker.add b/changelog.d/emoji-picker.add new file mode 100644 index 000000000..d0ddb18eb --- /dev/null +++ b/changelog.d/emoji-picker.add @@ -0,0 +1 @@ +fixed occasional overflows in emoji picker and made header scrollable diff --git a/changelog.d/emoji-size.fix b/changelog.d/emoji-size.fix new file mode 100644 index 000000000..a1189b833 --- /dev/null +++ b/changelog.d/emoji-size.fix @@ -0,0 +1 @@ +fix emoji inconsistencies in notifications, fix some emoji not scaling with interface diff --git a/changelog.d/image-compression.add b/changelog.d/image-compression.add new file mode 100644 index 000000000..d1f5a4fa4 --- /dev/null +++ b/changelog.d/image-compression.add @@ -0,0 +1 @@ +Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload. \ No newline at end of file diff --git a/changelog.d/misc-markup.fix b/changelog.d/misc-markup.fix new file mode 100644 index 000000000..7af934a29 --- /dev/null +++ b/changelog.d/misc-markup.fix @@ -0,0 +1 @@ +Fix small markup inconsistencies diff --git a/changelog.d/modals-mobile.change b/changelog.d/modals-mobile.change new file mode 100644 index 000000000..e6a768c57 --- /dev/null +++ b/changelog.d/modals-mobile.change @@ -0,0 +1 @@ +modal layout for mobile has new layout to make it easy to use diff --git a/changelog.d/modals.fix b/changelog.d/modals.fix new file mode 100644 index 000000000..68278bfc0 --- /dev/null +++ b/changelog.d/modals.fix @@ -0,0 +1 @@ +fixed modals buttons overflow diff --git a/changelog.d/multiple-status-mute-reasons.fix b/changelog.d/multiple-status-mute-reasons.fix new file mode 100644 index 000000000..952ccea82 --- /dev/null +++ b/changelog.d/multiple-status-mute-reasons.fix @@ -0,0 +1 @@ +Fix whitespaces for multiple status mute reasons, display bot status reason diff --git a/changelog.d/muted_user_en_translation.skip b/changelog.d/muted_user_en_translation.skip new file mode 100644 index 000000000..1d39e49d1 --- /dev/null +++ b/changelog.d/muted_user_en_translation.skip @@ -0,0 +1 @@ +Added missing EN translation key for status.muted_user diff --git a/changelog.d/mutes.change b/changelog.d/mutes.change new file mode 100644 index 000000000..fa13609bb --- /dev/null +++ b/changelog.d/mutes.change @@ -0,0 +1 @@ +better display of mute reason on posts diff --git a/changelog.d/no-check-npm.skip b/changelog.d/no-check-npm.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/non-anonymous-polls.add b/changelog.d/non-anonymous-polls.add new file mode 100644 index 000000000..9ff7f3adc --- /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/changelog.d/oauth-app-name.change b/changelog.d/oauth-app-name.change new file mode 100644 index 000000000..15d6f87ee --- /dev/null +++ b/changelog.d/oauth-app-name.change @@ -0,0 +1 @@ +Simplify the OAuth client_name to 'PleromaFE' diff --git a/changelog.d/panel-stack.fix b/changelog.d/panel-stack.fix new file mode 100644 index 000000000..518ff32fe --- /dev/null +++ b/changelog.d/panel-stack.fix @@ -0,0 +1 @@ +proper sticky header for conversations on user page diff --git a/changelog.d/piss-fix.skip b/changelog.d/piss-fix.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/piss-serialization.skip b/changelog.d/piss-serialization.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/quote-buttons.fix b/changelog.d/quote-buttons.fix new file mode 100644 index 000000000..859e5d6c5 --- /dev/null +++ b/changelog.d/quote-buttons.fix @@ -0,0 +1 @@ +reply-or-quote buttons now take less space diff --git a/changelog.d/roundup3.skip b/changelog.d/roundup3.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/show-bookmarks-on-mobile.fix b/changelog.d/show-bookmarks-on-mobile.fix new file mode 100644 index 000000000..3b5db4834 --- /dev/null +++ b/changelog.d/show-bookmarks-on-mobile.fix @@ -0,0 +1 @@ +Bookmarks visible again on mobile diff --git a/changelog.d/splashfix.skip b/changelog.d/splashfix.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/splashscreen.add b/changelog.d/splashscreen.add new file mode 100644 index 000000000..f1f56551a --- /dev/null +++ b/changelog.d/splashscreen.add @@ -0,0 +1 @@ +Splash screen + loading indicator to make process of identifying initialization issues and load performance diff --git a/changelog.d/streaming-op-after-conn.change b/changelog.d/streaming-op-after-conn.change new file mode 100644 index 000000000..73a79d843 --- /dev/null +++ b/changelog.d/streaming-op-after-conn.change @@ -0,0 +1 @@ +Authenticate and subscribe to streaming after connection diff --git a/changelog.d/tabs.change b/changelog.d/tabs.change new file mode 100644 index 000000000..e716ad427 --- /dev/null +++ b/changelog.d/tabs.change @@ -0,0 +1 @@ +Tabs now have indentation for better visibility of which tab is currently active diff --git a/changelog.d/themes3.add b/changelog.d/themes3.add new file mode 100644 index 000000000..040957ced --- /dev/null +++ b/changelog.d/themes3.add @@ -0,0 +1 @@ +UI for making v3 themes and palettes, support for bundling v3 themes diff --git a/changelog.d/upload-resizing.add b/changelog.d/upload-resizing.add new file mode 100644 index 000000000..355a1d898 --- /dev/null +++ b/changelog.d/upload-resizing.add @@ -0,0 +1 @@ +Resize most kinds of images on upload. diff --git a/changelog.d/user-link.add b/changelog.d/user-link.add new file mode 100644 index 000000000..ca65aa5fa --- /dev/null +++ b/changelog.d/user-link.add @@ -0,0 +1 @@ +Make UserLink wrappable diff --git a/changelog.d/vue.change b/changelog.d/vue.change new file mode 100644 index 000000000..a8fc21720 --- /dev/null +++ b/changelog.d/vue.change @@ -0,0 +1 @@ +Upgraded Vue to version 3.5 diff --git a/changelog.d/vuex-devtools.skip b/changelog.d/vuex-devtools.skip new file mode 100644 index 000000000..e69de29bb diff --git a/changelog.d/weird-absolute-time-format.fix b/changelog.d/weird-absolute-time-format.fix new file mode 100644 index 000000000..727d58764 --- /dev/null +++ b/changelog.d/weird-absolute-time-format.fix @@ -0,0 +1 @@ +Show only month and day instead of weird "day, hour" format. While at it, fixed typo "defualt" in a comment. \ No newline at end of file diff --git a/config/index.js b/config/index.js index 023d4c9bc..ff89274ad 100644 --- a/config/index.js +++ b/config/index.js @@ -8,10 +8,10 @@ try { // and that's how actual BE reports its url settings.target = settings.target.replace(/\/$/, '') } - console.log('Using local dev server settings (/config/local.json):') - console.log(JSON.stringify(settings, null, 2)) + console.info('Using local dev server settings (/config/local.json):') + console.info(JSON.stringify(settings, null, 2)) } catch (e) { - console.log('Local dev server settings not found (/config/local.json)') + console.info('Local dev server settings not found (/config/local.json)') } const target = settings.target || 'http://localhost:4000/' diff --git a/index.html b/index.html index a02939f7e..63f071aac 100644 --- a/index.html +++ b/index.html @@ -3,12 +3,163 @@ + + + + - - + -
+
+ + +
+ +
+ + + +
+ +

+      
+
+
diff --git a/package.json b/package.json index 0cba43903..4f70f4fc1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pleroma_fe", - "version": "2.5.0", + "version": "2.7.1", "description": "Pleroma frontend, the default frontend of Pleroma social network server", "author": "Pleroma contributors ", "private": false, @@ -10,110 +10,110 @@ "unit": "karma start test/unit/karma.conf.js --single-run", "unit:watch": "karma start test/unit/karma.conf.js --single-run=false", "e2e": "node test/e2e/runner.js", - "test": "npm run unit && npm run e2e", - "stylelint": "npx stylelint '**/*.scss' '**/*.vue'", + "test": "yarn run unit && yarn run e2e", + "stylelint": "yarn exec 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" }, "dependencies": { - "@babel/runtime": "7.21.0", + "@babel/runtime": "7.26.7", "@chenfengyuan/vue-qrcode": "2.0.0", - "@fortawesome/fontawesome-svg-core": "6.3.0", - "@fortawesome/free-regular-svg-icons": "6.3.0", - "@fortawesome/free-solid-svg-icons": "6.3.0", - "@fortawesome/vue-fontawesome": "3.0.3", + "@fortawesome/fontawesome-svg-core": "6.7.2", + "@fortawesome/free-regular-svg-icons": "6.7.2", + "@fortawesome/free-solid-svg-icons": "6.7.2", + "@fortawesome/vue-fontawesome": "3.0.8", "@kazvmoe-infra/pinch-zoom-element": "1.2.0", "@kazvmoe-infra/unicode-emoji-json": "0.4.0", - "@ruffle-rs/ruffle": "0.1.0-nightly.2022.7.12", - "@vuelidate/core": "2.0.0", - "@vuelidate/validators": "2.0.0", + "@ruffle-rs/ruffle": "0.1.0-nightly.2025.1.13", + "@vuelidate/core": "2.0.3", + "@vuelidate/validators": "2.0.4", "body-scroll-lock": "3.1.5", "chromatism": "3.0.0", "click-outside-vue3": "4.0.1", - "cropperjs": "1.5.12", + "cropperjs": "1.6.2", "escape-html": "1.0.3", - "js-cookie": "3.0.1", + "hash-sum": "^2.0.0", + "js-cookie": "3.0.5", "localforage": "1.10.0", + "pako": "^2.1.0", "parse-link-header": "2.0.0", - "phoenix": "1.6.2", - "pinia": "^2.0.33", - "punycode.js": "2.3.0", - "qrcode": "1.5.0", + "phoenix": "1.7.18", + "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", + "vue": "3.5.13", + "vue-i18n": "10", + "vue-router": "4.5.0", "vue-virtual-scroller": "^2.0.0-beta.7", "vuex": "4.1.0" }, "devDependencies": { - "@babel/core": "7.21.0", - "@babel/eslint-parser": "7.19.1", - "@babel/plugin-transform-runtime": "7.21.0", - "@babel/preset-env": "7.20.2", - "@babel/register": "7.21.0", + "@babel/core": "7.26.7", + "@babel/eslint-parser": "7.26.5", + "@babel/plugin-transform-runtime": "7.25.9", + "@babel/preset-env": "7.26.7", + "@babel/register": "7.25.9", "@intlify/vue-i18n-loader": "5.0.1", - "@ungap/event-target": "0.2.3", + "@ungap/event-target": "0.2.4", "@vue/babel-helper-vue-jsx-merge-props": "1.4.0", - "@vue/babel-plugin-jsx": "1.1.1", - "@vue/compiler-sfc": "3.2.45", - "@vue/test-utils": "2.2.8", - "autoprefixer": "10.4.13", - "babel-loader": "9.1.2", + "@vue/babel-plugin-jsx": "1.2.5", + "@vue/compiler-sfc": "3.5.13", + "@vue/test-utils": "2.4.6", + "autoprefixer": "10.4.20", + "babel-loader": "9.2.1", "babel-plugin-lodash": "3.3.4", - "chai": "4.3.7", + "chai": "4.5.0", "chalk": "1.1.3", "chromedriver": "108.0.0", "connect-history-api-fallback": "2.0.0", "copy-webpack-plugin": "11.0.0", - "cross-spawn": "7.0.3", - "css-loader": "6.7.3", + "cross-spawn": "7.0.6", + "css-loader": "6.11.0", "css-minimizer-webpack-plugin": "4.2.2", "custom-event-polyfill": "1.0.7", - "eslint": "8.33.0", - "eslint-config-standard": "17.0.0", + "eslint": "8.57.1", + "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-plugin-import": "2.31.0", + "eslint-plugin-n": "15.7.0", + "eslint-plugin-promise": "6.6.0", + "eslint-plugin-vue": "9.32.0", "eslint-webpack-plugin": "3.2.0", "eventsource-polyfill": "0.9.6", - "express": "4.18.2", - "function-bind": "1.1.1", - "html-webpack-plugin": "5.5.0", - "http-proxy-middleware": "2.0.6", + "express": "4.21.2", + "function-bind": "1.1.2", + "html-webpack-plugin": "5.6.3", + "http-proxy-middleware": "2.0.7", "iso-639-1": "2.1.15", "json-loader": "0.5.7", - "karma": "6.4.1", - "karma-coverage": "2.2.0", - "karma-firefox-launcher": "2.1.2", + "karma": "6.4.4", + "karma-coverage": "2.2.1", + "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-sourcemap-loader": "0.4.0", "karma-spec-reporter": "0.0.36", - "karma-webpack": "5.0.0", + "karma-webpack": "5.0.1", "lodash": "4.17.21", - "mini-css-extract-plugin": "2.7.2", - "mocha": "10.2.0", - "nightwatch": "2.6.19", + "mini-css-extract-plugin": "2.9.2", + "mocha": "10.8.2", + "nightwatch": "2.6.25", "opn": "5.5.0", "ora": "0.4.1", - "postcss": "8.4.20", + "postcss": "8.5.1", "postcss-html": "^1.5.0", "postcss-loader": "7.0.2", "postcss-scss": "^4.0.6", "sass": "1.60.0", - "sass-loader": "13.2.0", - "selenium-server": "2.53.1", - "semver": "7.3.8", + "sass-loader": "13.3.3", + "selenium-server": "3.141.59", + "semver": "7.6.3", "serviceworker-webpack5-plugin": "2.0.0", "shelljs": "0.8.5", - "sinon": "15.0.1", + "sinon": "15.2.0", "sinon-chai": "3.7.0", "stylelint": "14.16.1", "stylelint-config-html": "^1.1.0", @@ -130,7 +130,7 @@ "webpack-merge": "0.20.0" }, "engines": { - "node": ">= 16.0.0", - "npm": ">= 3.0.0" - } + "node": ">= 16.0.0" + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/preview.style.js b/preview.style.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/App.js b/src/App.js index f283b3f14..87bf8319f 100644 --- a/src/App.js +++ b/src/App.js @@ -46,16 +46,36 @@ export default { data: () => ({ mobileActivePanel: 'timeline' }), + watch: { + themeApplied (value) { + this.removeSplash() + }, + layoutType (value) { + 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] + }, + mounted () { + if (this.$store.state.interface.themeApplied) { + this.removeSplash() + } }, unmounted () { window.removeEventListener('resize', this.updateMobileState) }, computed: { + themeApplied () { + return this.$store.state.interface.themeApplied + }, + layoutModalClass () { + return '-' + this.layoutType + }, classes () { return [ { @@ -132,6 +152,15 @@ export default { updateMobileState () { useInterfaceStore().setLayoutWidth(windowWidth()) useInterfaceStore().setLayoutHeight(windowHeight()) + }, + removeSplash () { + document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4)) + const splashscreenRoot = document.querySelector('#splash') + splashscreenRoot.addEventListener('transitionend', () => { + splashscreenRoot.remove() + }) + splashscreenRoot.classList.add('hidden') + document.querySelector('#app').classList.remove('hidden') } } } diff --git a/src/App.scss b/src/App.scss index 3f352e8d9..c0f2e3fec 100644 --- a/src/App.scss +++ b/src/App.scss @@ -1,10 +1,9 @@ // stylelint-disable rscss/class-format /* stylelint-disable no-descending-specificity */ -@import "./variables"; @import "./panel"; :root { - --navbar-height: 3.5rem; + --status-margin: 0.75em; --post-line-height: 1.4; // Z-Index stuff --ZI_media_modal: 9000; @@ -13,19 +12,25 @@ --ZI_navbar_popovers: 7500; --ZI_navbar: 7000; --ZI_popovers: 6000; + + // Fallback for when stuff is loading + --background: var(--bg); } html { - font-size: 14px; + font-size: var(--textSize, 14px); + + --navbar-height: var(--navbarSize, 3.5rem); + --emoji-size: var(--emojiSize, 32px); + --panel-header-height: var(--panelHeaderSize, 3.2rem); // overflow-x: clip causes my browser's tab to crash with SIGILL lul } body { font-family: sans-serif; - font-family: var(--interfaceFont, sans-serif); + font-family: var(--font); margin: 0; - color: $fallback--text; - color: var(--text, $fallback--text); + color: var(--text); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overscroll-behavior-y: none; @@ -42,17 +47,35 @@ body { // have a cursor/pointer to operate them @media (any-pointer: fine) { * { - scrollbar-color: var(--btn) transparent; + scrollbar-color: var(--fg) transparent; &::-webkit-scrollbar { background: transparent; } + &::-webkit-scrollbar-corner { + background: transparent; + } + + &::-webkit-resizer { + /* stylelint-disable-next-line declaration-no-important */ + background-color: transparent !important; + background-image: + linear-gradient( + 135deg, + transparent calc(50% - 1px), + var(--textFaint) 50%, + transparent calc(50% + 1px), + transparent calc(75% - 1px), + var(--textFaint) 75%, + transparent calc(75% + 1px), + ); + } + &::-webkit-scrollbar-button, &::-webkit-scrollbar-thumb { - background-color: var(--btn); - box-shadow: var(--buttonShadow); - border-radius: var(--btnRadius); + box-shadow: var(--shadow); + border-radius: var(--roundness); } // horizontal/vertical/increment/decrement are webkit-specific stuff @@ -61,7 +84,7 @@ body { &::-webkit-scrollbar-button { --___bgPadding: 2px; - color: var(--btnText); + color: var(--text); background-repeat: no-repeat, no-repeat; &:horizontal { @@ -69,15 +92,15 @@ body { &:increment { background-image: - linear-gradient(45deg, var(--btnText) 50%, transparent 51%), - linear-gradient(-45deg, transparent 50%, var(--btnText) 51%); + linear-gradient(45deg, var(--text) 50%, transparent 51%), + linear-gradient(-45deg, transparent 50%, var(--text) 51%); background-position: top var(--___bgPadding) left 50%, right 50% bottom var(--___bgPadding); } &:decrement { background-image: - linear-gradient(45deg, transparent 50%, var(--btnText) 51%), - linear-gradient(-45deg, var(--btnText) 50%, transparent 51%); + linear-gradient(45deg, transparent 50%, var(--text) calc(50% + 1px)), + linear-gradient(-45deg, var(--text) 50%, transparent 51%); background-position: bottom var(--___bgPadding) right 50%, left 50% top var(--___bgPadding); } } @@ -87,15 +110,15 @@ body { &:increment { background-image: - linear-gradient(-45deg, transparent 50%, var(--btnText) 51%), - linear-gradient(45deg, transparent 50%, var(--btnText) 51%); + linear-gradient(-45deg, transparent 50%, var(--text) 51%), + linear-gradient(45deg, transparent 50%, var(--text) 51%); background-position: right var(--___bgPadding) top 50%, left var(--___bgPadding) top 50%; } &:decrement { background-image: - linear-gradient(-45deg, var(--btnText) 50%, transparent 51%), - linear-gradient(45deg, var(--btnText) 50%, transparent 51%); + linear-gradient(-45deg, var(--text) 50%, transparent 51%), + linear-gradient(45deg, var(--text) 50%, transparent 51%); background-position: left var(--___bgPadding) top 50%, right var(--___bgPadding) top 50%; } } @@ -104,15 +127,14 @@ body { } // Body should have background to scrollbar otherwise it will use white (body color?) html { - scrollbar-color: var(--selectedMenu) var(--wallpaper); + scrollbar-color: var(--fg) var(--wallpaper); background: var(--wallpaper); } } a { text-decoration: none; - color: $fallback--link; - color: var(--link, $fallback--link); + color: var(--link); } h4 { @@ -128,29 +150,15 @@ h4 { i[class*="icon-"], .svg-inline--fa, .iconLetter { - color: $fallback--icon; - color: var(--icon, $fallback--icon); -} - -.button-unstyled:hover, -a:hover { - > i[class*="icon-"], - > .svg-inline--fa, - > .iconLetter { - color: var(--text); - } + color: var(--icon); } nav { z-index: var(--ZI_navbar); - background-color: $fallback--fg; - background-color: var(--topBar, $fallback--fg); - color: $fallback--faint; - color: var(--faint, $fallback--faint); - box-shadow: 0 0 4px rgb(0 0 0 / 60%); - box-shadow: var(--topBarShadow); + box-shadow: var(--shadow); box-sizing: border-box; height: var(--navbar-height); + font-size: calc(var(--navbar-height) / 3.5); position: fixed; } @@ -195,16 +203,14 @@ nav { grid-column: 1 / span 3; grid-row: 1 / 1; pointer-events: none; - background-color: rgb(0 0 0 / 15%); - background-color: var(--underlay, rgb(0 0 0 / 15%)); + background-color: var(--underlay); z-index: -1000; } .app-layout { --miniColumn: 25rem; --maxiColumn: 45rem; - --columnGap: 1em; - --status-margin: 0.75em; + --columnGap: 1rem; --effectiveSidebarColumnWidth: minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn))); --effectiveNotifsColumnWidth: minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn))); --effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn))); @@ -366,106 +372,126 @@ nav { .button-default { user-select: none; - color: $fallback--text; - color: var(--btnText, $fallback--text); - background-color: $fallback--fg; - background-color: var(--btn, $fallback--fg); + color: var(--text); border: none; - border-radius: $fallback--btnRadius; - border-radius: var(--btnRadius, $fallback--btnRadius); cursor: pointer; - box-shadow: $fallback--buttonShadow; - box-shadow: var(--buttonShadow); + background-color: var(--background); + box-shadow: var(--shadow); font-size: 1em; font-family: sans-serif; - font-family: var(--interfaceFont, sans-serif); - - &.-sublime { - background: transparent; - } - - i[class*="icon-"], - .svg-inline--fa { - color: $fallback--text; - color: var(--btnText, $fallback--text); - } + font-family: var(--font); &::-moz-focus-inner { border: none; } - &:hover { - box-shadow: 0 0 4px rgb(255 255 255 / 30%); - box-shadow: var(--buttonHoverShadow); - } - - &:active { - box-shadow: - 0 0 4px 0 rgb(255 255 255 / 30%), - 0 1px 0 0 rgb(0 0 0 / 20%) inset, - 0 -1px 0 0 rgb(255 255 255 / 20%) inset; - box-shadow: var(--buttonPressedShadow); - color: $fallback--text; - color: var(--btnPressedText, $fallback--text); - background-color: $fallback--fg; - background-color: var(--btnPressed, $fallback--fg); - - svg, - i { - color: $fallback--text; - color: var(--btnPressedText, $fallback--text); - } - } - &:disabled { cursor: not-allowed; - color: $fallback--text; - color: var(--btnDisabledText, $fallback--text); - background-color: $fallback--fg; - background-color: var(--btnDisabled, $fallback--fg); + } +} - svg, - i { - color: $fallback--text; - color: var(--btnDisabledText, $fallback--text); - } +.menu-item { + line-height: var(--__line-height); + font-family: inherit; + font-weight: 400; + font-size: 100%; + cursor: pointer; + + a, + button:not(.button-default) { + color: var(--text); + font-size: 100%; } - &.toggled { - color: $fallback--text; - color: var(--btnToggledText, $fallback--text); - background-color: $fallback--fg; - background-color: var(--btnToggled, $fallback--fg); - box-shadow: - 0 0 4px 0 rgb(255 255 255 / 30%), - 0 1px 0 0 rgb(0 0 0 / 20%) inset, - 0 -1px 0 0 rgb(255 255 255 / 20%) inset; - box-shadow: var(--buttonPressedShadow); + &.disabled { + cursor: not-allowed; + } +} - svg, - i { - color: $fallback--text; - color: var(--btnToggledText, $fallback--text); - } +.list-item { + border-color: var(--border); + border-style: solid; + border-width: 0; + border-top-width: 1px; + + &.-active, + &:hover { + border-top-width: 1px; + border-bottom-width: 1px; } - &.danger { - // TODO: add better color variable - color: $fallback--text; - color: var(--alertErrorPanelText, $fallback--text); - background-color: $fallback--alertError; - background-color: var(--alertError, $fallback--alertError); + &.-active + &, + &:hover + & { + border-top-width: 0; + } + + &:hover + .menu-item-collapsible:not(.-expanded) + &, + &.-active + .menu-item-collapsible:not(.-expanded) + & { + border-top-width: 0; + } + + &[aria-expanded="true"] { + border-bottom-width: 1px; + } + + &:first-child { + border-top-right-radius: var(--roundness); + border-top-left-radius: var(--roundness); + border-top-width: 0; + } + + &:last-child { + border-bottom-right-radius: var(--roundness); + border-bottom-left-radius: var(--roundness); + border-bottom-width: 0; + } +} + +.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 { - background: none; border: none; outline: none; display: inline; text-align: initial; font-size: 100%; font-family: inherit; + box-shadow: var(--shadow); + background-color: transparent; padding: 0; line-height: unset; cursor: pointer; @@ -473,28 +499,23 @@ nav { color: inherit; &.-link { - color: $fallback--link; - color: var(--link, $fallback--link); - } - - &.-fullwidth { - width: 100%; - } - - &.-hover-highlight { - &:hover svg { - color: $fallback--lightText; - color: var(--lightText, $fallback--lightText); - } + /* stylelint-disable-next-line declaration-no-important */ + color: var(--link) !important; } } input, -textarea, +textarea { + border: none; + display: inline-block; + outline: none; +} + .input { &.unstyled { border-radius: 0; - background: none; + /* stylelint-disable-next-line declaration-no-important */ + background: none !important; box-shadow: none; height: unset; } @@ -502,19 +523,10 @@ textarea, --_padding: 0.5em; border: none; - border-radius: $fallback--inputRadius; - border-radius: var(--inputRadius, $fallback--inputRadius); - box-shadow: - 0 1px 0 0 rgb(0 0 0 / 20%) inset, - 0 -1px 0 0 rgb(255 255 255 / 20%) inset, - 0 0 2px 0 rgb(0 0 0 / 100%) inset; - box-shadow: var(--inputShadow); - background-color: $fallback--fg; - background-color: var(--input, $fallback--fg); - color: $fallback--lightText; - color: var(--inputText, $fallback--lightText); - font-family: sans-serif; - font-family: var(--inputFont, sans-serif); + background-color: var(--background); + color: var(--text); + box-shadow: var(--shadow); + font-family: var(--font); font-size: 1em; margin: 0; box-sizing: border-box; @@ -528,7 +540,6 @@ textarea, &[disabled="disabled"], &.disabled { cursor: not-allowed; - opacity: 0.5; } &[type="range"] { @@ -543,9 +554,9 @@ textarea, display: none; &:checked + label::before { - box-shadow: 0 0 2px black inset, 0 0 0 4px $fallback--fg inset; - box-shadow: var(--inputShadow), 0 0 0 4px var(--fg, $fallback--fg) inset; - background-color: var(--accent, $fallback--link); + box-shadow: var(--shadow); + background-color: var(--background); + color: var(--text); } &:disabled { @@ -559,16 +570,14 @@ textarea, + label::before { flex-shrink: 0; display: inline-block; - content: ""; + content: "•"; transition: box-shadow 200ms; width: 1.1em; height: 1.1em; border-radius: 100%; // Radio buttons should always be circle - box-shadow: 0 0 2px black inset; - box-shadow: var(--inputShadow); + background-color: var(--background); + box-shadow: var(--shadow); margin-right: 0.5em; - background-color: $fallback--fg; - background-color: var(--input, $fallback--fg); vertical-align: top; text-align: center; line-height: 1.1; @@ -581,8 +590,9 @@ textarea, &[type="checkbox"] { &:checked + label::before { - color: $fallback--text; - color: var(--inputText, $fallback--text); + color: var(--text); + background-color: var(--background); + box-shadow: var(--shadow); } &:disabled { @@ -600,13 +610,9 @@ textarea, transition: color 200ms; width: 1.1em; height: 1.1em; - border-radius: $fallback--checkboxRadius; - border-radius: var(--checkboxRadius, $fallback--checkboxRadius); - box-shadow: 0 0 2px black inset; - box-shadow: var(--inputShadow); + border-radius: var(--roundness); + box-shadow: var(--shadow); margin-right: 0.5em; - background-color: $fallback--fg; - background-color: var(--input, $fallback--fg); vertical-align: top; text-align: center; line-height: 1.1; @@ -622,17 +628,26 @@ textarea, } } +.input, +.button-default { + --_roundness-left: var(--roundness); + --_roundness-right: var(--roundness); + + border-top-left-radius: var(--_roundness-left); + border-bottom-left-radius: var(--_roundness-left); + border-top-right-radius: var(--_roundness-right); + border-bottom-right-radius: var(--_roundness-right); +} + // Textareas should have stock line-height + vertical padding instead of huge line-height -textarea { +textarea.input { padding: var(--_padding); line-height: var(--post-line-height); } option { - color: $fallback--text; - color: var(--text, $fallback--text); - background-color: $fallback--bg; - background-color: var(--bg, $fallback--bg); + color: var(--text); + background-color: var(--background); } .hide-number-spinner { @@ -645,6 +660,20 @@ option { } } +.cards-list { + list-style: none; + display: grid; + grid-auto-flow: row dense; + grid-template-columns: 1fr 1fr; + + li { + border: 1px solid var(--border); + border-radius: var(--roundness); + padding: 0.5em; + margin: 0.25em; + } +} + .btn-block { display: block; width: 100%; @@ -655,19 +684,23 @@ option { display: inline-flex; vertical-align: middle; - button { + > *, + > * .button-default { + --_roundness-left: 0; + --_roundness-right: 0; + position: relative; flex: 1 1 auto; + } - &:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - } + > *:first-child, + > *:first-child .button-default { + --_roundness-left: var(--roundness); + } - &:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - } + > *:last-child, + > *:last-child .button-default { + --_roundness-right: var(--roundness); } } @@ -697,74 +730,64 @@ option { overflow: hidden; text-overflow: ellipsis; - &.badge-notification { - background-color: $fallback--cRed; - background-color: var(--badgeNotification, $fallback--cRed); + &.-dot, + &.-counter { + margin: 0; + position: absolute; + } + + &.-dot { + min-height: 8px; + max-height: 8px; + min-width: 8px; + max-width: 8px; + padding: 0; + line-height: 0; + font-size: 0; + left: calc(50% - 4px); + top: calc(50% - 4px); + margin-left: 6px; + margin-top: -6px; + } + + &.-counter { + border-radius: var(--roundness); + font-size: 0.75em; + line-height: 1; + text-align: right; + padding: 0.2em; + min-width: 0; + left: calc(50% - 0.5em); + top: calc(50% - 0.4em); + margin-left: 0.7em; + margin-top: -1em; + } + + &.-neutral { + background-color: var(--badgeNeutral); color: white; - color: var(--badgeNotificationText, white); + color: var(--badgeNeutralText, white); } } .alert { margin: 0 0.35em; padding: 0 0.25em; - border-radius: $fallback--tooltipRadius; - border-radius: var(--tooltipRadius, $fallback--tooltipRadius); - - &.error { - background-color: $fallback--alertError; - background-color: var(--alertError, $fallback--alertError); - color: $fallback--text; - color: var(--alertErrorText, $fallback--text); - - .panel-heading & { - color: $fallback--text; - color: var(--alertErrorPanelText, $fallback--text); - } - } - - &.warning { - background-color: $fallback--alertWarning; - background-color: var(--alertWarning, $fallback--alertWarning); - color: $fallback--text; - color: var(--alertWarningText, $fallback--text); - - .panel-heading & { - color: $fallback--text; - color: var(--alertWarningPanelText, $fallback--text); - } - } - - &.success { - background-color: var(--alertSuccess, $fallback--alertWarning); - color: var(--alertSuccessText, $fallback--text); - - .panel-heading & { - color: var(--alertSuccessPanelText, $fallback--text); - } - } + border-radius: var(--roundness); + border: 1px solid var(--border); } .faint { - color: $fallback--faint; - color: var(--faint, $fallback--faint); -} + --text: var(--textFaint); + --link: var(--linkFaint); -.faint-link { - color: $fallback--faint; - color: var(--faint, $fallback--faint); - - &:hover { - text-decoration: underline; - } + color: var(--text); } .visibility-notice { padding: 0.5em; - border: 1px solid $fallback--faint; - border: 1px solid var(--faint, $fallback--faint); - border-radius: $fallback--inputRadius; - border-radius: var(--inputRadius, $fallback--inputRadius); + border: 1px solid var(--textFaint); + border-radius: var(--roundness); } .notice-dismissible { @@ -785,6 +808,10 @@ option { &.iconLetter { font-size: 1.1em; } + + &.svg-inline--fa { + vertical-align: -0.15em; + } } .fa-old-padding { @@ -799,6 +826,11 @@ option { opacity: 0.25; } +.timeago { + --link: var(--text); + --linkFaint: var(--textFaint); +} + .login-hint { text-align: center; @@ -897,3 +929,174 @@ option { padding: 0; position: absolute; } + +*::selection { + color: var(--selectionText); + background-color: var(--selectionBackground); +} + +#splash { + pointer-events: none; + transition: opacity 2s; + opacity: 1; + + &.hidden { + opacity: 0; + } + + #status { + &.css-ok { + &::before { + display: inline-block; + content: "CSS OK"; + } + } + + .initial-text { + display: none; + } + } + + #throbber { + animation-duration: 3s; + animation-name: bounce; + animation-iteration-count: infinite; + animation-direction: normal; + transform-origin: bottom center; + + &.dead { + animation-name: dead; + animation-duration: 2s; + animation-iteration-count: 1; + transform: rotateX(90deg) rotateY(0) rotateZ(-45deg); + } + + @keyframes dead { + 0% { + transform: rotateX(0) rotateY(0) rotateZ(0); + } + + 5% { + transform: rotateX(0) rotateY(0) rotateZ(1deg); + } + + 10% { + transform: rotateX(0) rotateY(0) rotateZ(-2deg); + } + + 15% { + transform: rotateX(0) rotateY(0) rotateZ(3deg); + } + + 20% { + transform: rotateX(0) rotateY(0) rotateZ(0); + } + + 25% { + transform: rotateX(0) rotateY(0) rotateZ(0); + } + + 30% { + transform: rotateX(10deg) rotateY(0) rotateZ(0); + } + + 35% { + transform: rotateX(-10deg) rotateY(0) rotateZ(0); + } + + 40% { + transform: rotateX(10deg) rotateY(0) rotateZ(0); + } + + 45% { + transform: rotateX(-10deg) rotateY(0) rotateZ(0); + } + + 50% { + transform: rotateX(10deg) rotateY(0) rotateZ(0); + } + + 100% { + transform: rotateX(90deg) rotateY(0) rotateZ(-45deg); + transition-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); /* easeInQuint */ + } + } + + @keyframes bounce { + 0% { + scale: 1 1; + translate: 0 0; + animation-timing-function: ease-out; + } + + 10% { + scale: 1.2 0.8; + translate: 0 0; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-out; + } + + 30% { + scale: 0.9 1.1; + translate: 0 -40%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in; + } + + 40% { + scale: 1.1 0.9; + translate: 0 -50%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in; + } + + 45% { + scale: 0.9 1.1; + translate: 0 -45%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in; + } + + 50% { + scale: 1.05 0.95; + translate: 0 -40%; + animation-timing-function: ease-in; + } + + 55% { + scale: 0.985 1.025; + translate: 0 -35%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in; + } + + 60% { + scale: 1.0125 0.9985; + translate: 0 -30%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in; + } + + 80% { + scale: 1.0063 0.9938; + translate: 0 -10%; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-in-ou; + } + + 90% { + scale: 1.2 0.8; + translate: 0 0; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-out; + } + + 100% { + scale: 1 1; + translate: 0 0; + transform: rotateZ(var(--defaultZ)); + animation-timing-function: ease-out; + } + } + } +} diff --git a/src/App.vue b/src/App.vue index fe214ce71..762e18515 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,6 @@