summaryrefslogtreecommitdiff
path: root/src/client/app.vue
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2020-10-17 20:12:00 +0900
committerGitHub <noreply@github.com>2020-10-17 20:12:00 +0900
commit7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a (patch)
tree2263a06acec7fa21882366bae26d1a983ce21135 /src/client/app.vue
parentCW の input でも投稿ショートカットが動作するように (#6690) (diff)
downloadmisskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.tar.gz
misskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.tar.bz2
misskey-7199e6f4e0b3a2c2bc198e689c3e0cd0d0f0354a.zip
Migrate to Vue3 (#6587)
* Update reaction.vue * fix bug * wip * wip * wjio * wip * Revert "wip" This reverts commit e427f2160adf4e8a4147006e25a89854edab0033. * wip * wip * wip * Update init.ts * Update drive-window.vue * wip * wip * Use PascalCase for components * Use PascalCase for components * update dep * wip * wip * wip * Update init.ts * wip * Update paging.ts * Update test.vue * watch deep * wip * lint * wip * wip * wip * wip * wiop * wip * Update webpack.config.ts * alllow null poll * wip * wip * wip * wiop * UI redesign & refactor (#6714) * wip * wip * wip * wip * wip * Update drive.vue * Update word-mute.vue * wip * wip * wip * clean up * wip * Update default.vue * wip * Update notes.vue * Update mfm.ts * Update index.home.vue * Update post-form.vue * Update post-form-attaches.vue * wip * Update post-form.vue * Update sidebar.vue * wip * wip * Update index.vue * wip * Update default.vue * Update index.vue * Update index.vue * wip * Update post-form-attaches.vue * Update note.vue * wip * clean up * Update notes.vue * wip * wip * Update ja-JP.yml * wip * wip * Update index.vue * wip * wip * wip * wip * wip * wip * wip * wip * Update default.vue * wip * Update _dark.json5 * wip * wip * wip * clean up * wip * wip * Update index.vue * Update test.vue * wip * wip * fix * wip * wip * wip * wip * clena yop * wip * wip * Update store.ts * Update messaging-room.vue * Update default.widgets.vue * fix * wip * wip * Update modal.vue * wip * Update os.ts * Update os.ts * Update deck.vue * Update init.ts * wip * Update ja-JP.yml * v-sizeは単にwindowのresizeを監視するだけで良いかもしれない * Update modal.vue * wip * Update tooltip.ts * wip * wip * wip * wip * wip * Update image-viewer.vue * wip * wip * Update style.scss * Update style.scss * Update visitor.vue * wip * Update init.ts * Update init.ts * wip * wip * Update visitor.vue * Update visitor.vue * Update visitor.vue * Update visitor.vue * wip * wip * Update modal.vue * Update header.vue * Update menu.vue * Update about.vue * Update about-misskey.vue * wip * wip * Update visitor.vue * Update tooltip.ts * wip * Update drive.vue * wip * Update style.scss * Update header.vue * wip * wip * Update users.user.vue * Update announcements.vue * wip * wip * wip * Update emojis.vue * wip * Update emojis.vue * Update style.scss * Update users.vue * wip * Update style.scss * wip * Update welcome.entrance.vue * Update radio.vue * Update size.ts * Update emoji-edit-dialog.vue * wip * Update emojis.vue * wip * Update emojis.vue * Update emojis.vue * Update emojis.vue * wip * wip * wip * wip * Update file-dialog.vue * wip * wip * Update token-generate-window.vue * Update notification-setting-window.vue * wip * wip * Update _error_.vue * Update ja-JP.yml * wip * wip * Update store.ts * Update emojis.vue * Update emojis.vue * Update emojis.vue * Update announcements.vue * Update store.ts * wip * Update page-editor.vue * wip * wip * Update modal.vue * wip * Update select-file.ts * Update timeline.vue * Update emojis.vue * Update os.ts * wip * Update user-select.vue * Update mfm.ts * Update get-file-info.ts * Update drive.vue * Update init.ts * Update mfm.ts * wip * wip * Update window.vue * Update note.vue * wip * wip * Update user-info.vue * wip * wip * wip * wip * wip * Update header.vue * Update header.vue * wip * Update explore.vue * wip * wip * wip * Update webpack.config.ts * wip * wip * wip * wip * wip * wip * Update autocomplete.ts * wip * wip * wip * Update toast.vue * wip * Update post-form-dialog.vue * wip * wip * wip * wip * wip * Update users.vue * wip * Update explore.vue * wip * wip * wip * Update package.json * wip * Update icon-dialog.vue * wip * wip * Update user-preview.ts * wip * wip * wip * wip * wip * Update instance.vue * Update user-name.vue * Update federation.vue * Update instance.vue * wip * wip * Update tag.vue * wip * wip * wip * wip * wip * Update instance.vue * wip * Update os.ts * Update os.ts * wip * wip * wip * Update router.ts * wip * Update init.ts * Update note.vue * Update messages.vue * wip * wip * wip * wip * wip * google * wip * wip * wip * wip * Update theme-editor.vue * wip * wip * Update room.vue * Update channel-editor.vue * wip * Update window.vue * Update window.vue * wip * Update window.vue * Update window.vue * wip * Update menu.vue * wip * wip * wip * wip * Update messaging-room.vue * wip * Update post-form.vue * Update default.widgets.vue * Update window.vue * wip
Diffstat (limited to 'src/client/app.vue')
-rw-r--r--src/client/app.vue788
1 files changed, 0 insertions, 788 deletions
diff --git a/src/client/app.vue b/src/client/app.vue
deleted file mode 100644
index 3453baa280..0000000000
--- a/src/client/app.vue
+++ /dev/null
@@ -1,788 +0,0 @@
-<template>
-<div class="mk-app" v-hotkey.global="keymap">
- <header class="header" ref="header">
- <div class="title" ref="title">
- <transition :name="$store.state.device.animation ? 'header' : ''" mode="out-in" appear>
- <button class="_button back" v-if="canBack" @click="back()"><fa :icon="faChevronLeft"/></button>
- </transition>
- <transition :name="$store.state.device.animation ? 'header' : ''" mode="out-in" appear>
- <div class="body" :key="pageKey">
- <div class="default">
- <portal-target name="avatar" slim/>
- <h1 class="title"><portal-target name="icon" slim/><portal-target name="title" slim/></h1>
- </div>
- <div class="custom">
- <portal-target name="header" slim/>
- </div>
- </div>
- </transition>
- </div>
- <div class="sub">
- <template v-if="$store.getters.isSignedIn">
- <button v-if="widgetsEditMode" class="_button edit active" @click="widgetsEditMode = false"><fa :icon="faGripVertical"/></button>
- <button v-else class="_button edit" @click="widgetsEditMode = true"><fa :icon="faGripVertical"/></button>
- </template>
- <div class="search">
- <fa :icon="faSearch"/>
- <input type="search" :placeholder="$t('search')" v-model="searchQuery" v-autocomplete="{ model: 'searchQuery' }" :disabled="searchWait" @keypress="searchKeypress"/>
- </div>
- <button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>
- <x-clock v-if="isDesktop" class="clock"/>
- </div>
- </header>
-
- <x-sidebar ref="nav" @change-view-mode="calcHeaderWidth"/>
-
- <div class="contents" ref="contents" :class="{ wallpaper, full: $store.state.fullView }">
- <main ref="main">
- <div class="content">
- <transition :name="$store.state.device.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
- <keep-alive :include="['index']">
- <router-view></router-view>
- </keep-alive>
- </transition>
- </div>
- <div class="powerd-by" :class="{ visible: !$store.getters.isSignedIn }">
- <b><router-link to="/">{{ host }}</router-link></b>
- <small>Powered by <a href="https://github.com/syuilo/misskey" target="_blank">Misskey</a></small>
- </div>
- </main>
-
- <template v-if="isDesktop">
- <div v-for="place in ['left', 'right']" ref="widgets" class="widgets" :class="{ edit: widgetsEditMode, fixed: $store.state.device.fixedWidgetsPosition, empty: widgets[place].length === 0 && !widgetsEditMode }" :key="place">
- <div class="spacer"></div>
- <div class="container" v-if="widgetsEditMode">
- <mk-button primary @click="addWidget(place)" class="add"><fa :icon="faPlus"/></mk-button>
- <x-draggable
- :list="widgets[place]"
- handle=".handle"
- animation="150"
- class="sortable"
- @sort="onWidgetSort"
- >
- <div v-for="widget in widgets[place]" class="customize-container _panel" :key="widget.id">
- <header>
- <span class="handle"><fa :icon="faBars"/></span>{{ $t('_widgets.' + widget.name) }}<button class="remove _button" @click="removeWidget(widget)"><fa :icon="faTimes"/></button>
- </header>
- <div @click="widgetFunc(widget.id)">
- <component class="_close_ _forceContainerFull_" :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-customize-mode="true"/>
- </div>
- </div>
- </x-draggable>
- </div>
- <div class="container" v-else>
- <component v-for="widget in widgets[place]" class="_close_ _forceContainerFull_" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget"/>
- </div>
- </div>
- </template>
- </div>
-
- <div class="buttons" :class="{ navHidden }">
- <button class="button nav _button" @click="showNav" ref="navButton"><fa :icon="faBars"/><i v-if="navIndicated"><fa :icon="faCircle"/></i></button>
- <button v-if="$route.name === 'index'" class="button home _button" @click="top()"><fa :icon="faHome"/></button>
- <button v-else class="button home _button" @click="$router.push('/')"><fa :icon="faHome"/></button>
- <button v-if="$store.getters.isSignedIn" class="button notifications _button" @click="$router.push('/my/notifications')"><fa :icon="faBell"/><i v-if="$store.state.i.hasUnreadNotification"><fa :icon="faCircle"/></i></button>
- <button v-if="$store.getters.isSignedIn" class="button post _buttonPrimary" @click="post()"><fa :icon="faPencilAlt"/></button>
- </div>
-
- <button v-if="$store.getters.isSignedIn" class="post _buttonPrimary" :class="{ navHidden }" @click="post()"><fa :icon="faPencilAlt"/></button>
-
- <stream-indicator v-if="$store.getters.isSignedIn"/>
-</div>
-</template>
-
-<script lang="ts">
-import Vue from 'vue';
-import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
-import { v4 as uuid } from 'uuid';
-import { host } from './config';
-import { search } from './scripts/search';
-import { StickySidebar } from './scripts/sticky-sidebar';
-import { widgets } from './widgets';
-import XSidebar from './components/sidebar.vue';
-
-const DESKTOP_THRESHOLD = 1100;
-
-export default Vue.extend({
- components: {
- XSidebar,
- XClock: () => import('./components/header-clock.vue').then(m => m.default),
- MkButton: () => import('./components/ui/button.vue').then(m => m.default),
- XDraggable: () => import('vuedraggable'),
- },
-
- data() {
- return {
- host: host,
- pageKey: 0,
- searching: false,
- connection: null,
- searchQuery: '',
- searchWait: false,
- widgetsEditMode: false,
- isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
- canBack: false,
- menuDef: this.$store.getters.nav({}),
- navHidden: false,
- wallpaper: localStorage.getItem('wallpaper') != null,
- faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
- };
- },
-
- computed: {
- keymap(): any {
- return {
- 'd': () => {
- if (this.$store.state.device.syncDeviceDarkMode) return;
- this.$store.commit('device/set', { key: 'darkMode', value: !this.$store.state.device.darkMode });
- },
- 'p': this.post,
- 'n': this.post,
- 's': this.search,
- 'h|/': this.help
- };
- },
-
- widgets(): any {
- if (this.$store.getters.isSignedIn) {
- const widgets = this.$store.state.deviceUser.widgets;
- return {
- left: widgets.filter(x => x.place === 'left'),
- right: widgets.filter(x => x.place == null || x.place === 'right'),
- mobile: widgets.filter(x => x.place === 'mobile'),
- };
- } else {
- const right = [{
- name: 'calendar',
- id: 'b', place: 'right', data: {}
- }, {
- name: 'trends',
- id: 'c', place: 'right', data: {}
- }];
-
- if (this.$route.name !== 'index') {
- right.unshift({
- name: 'welcome',
- id: 'a', place: 'right', data: {}
- });
- }
-
- return {
- left: [],
- right,
- mobile: [],
- };
- }
- },
-
- menu(): string[] {
- return this.$store.state.deviceUser.menu;
- },
-
- navIndicated(): boolean {
- if (!this.$store.getters.isSignedIn) return false;
- for (const def in this.menuDef) {
- if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから
- if (this.menuDef[def].indicated) return true;
- }
- return false;
- }
- },
-
- watch: {
- $route(to, from) {
- this.pageKey++;
- this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
- },
-
- isDesktop() {
- this.$nextTick(() => {
- this.attachSticky();
- });
- }
- },
-
- created() {
- document.documentElement.style.overflowY = 'scroll';
-
- if (this.$store.getters.isSignedIn) {
- this.connection = this.$root.stream.useSharedConnection('main');
- this.connection.on('notification', this.onNotification);
-
- if (this.$store.state.deviceUser.widgets.length === 0) {
- this.$store.commit('deviceUser/setWidgets', [{
- name: 'calendar',
- id: 'a', place: 'right', data: {}
- }, {
- name: 'notifications',
- id: 'b', place: 'right', data: {}
- }, {
- name: 'trends',
- id: 'c', place: 'right', data: {}
- }]);
- }
- }
- },
-
- mounted() {
- this.adjustTitlePosition();
-
- const ro = new ResizeObserver((entries, observer) => {
- this.adjustTitlePosition();
- });
-
- ro.observe(this.$refs.contents);
-
- window.addEventListener('resize', this.adjustTitlePosition, { passive: true });
-
- if (!this.isDesktop) {
- window.addEventListener('resize', () => {
- if (window.innerWidth >= DESKTOP_THRESHOLD) this.isDesktop = true;
- }, { passive: true });
- }
-
- // widget follow
- this.attachSticky();
-
- this.$nextTick(() => {
- this.calcHeaderWidth();
- });
- },
-
- methods: {
- adjustTitlePosition() {
- const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.$el.offsetWidth;
- if (left >= 0) {
- this.$refs.title.style.left = left + 'px';
- }
- },
-
- calcHeaderWidth() {
- const navWidth = this.$refs.nav.$el.offsetWidth;
- this.navHidden = navWidth === 0;
- this.$refs.header.style.width = `calc(100% - ${navWidth}px)`;
- this.adjustTitlePosition();
- },
-
- showNav() {
- this.$refs.nav.show();
- },
-
- attachSticky() {
- if (!this.isDesktop) return;
- if (this.$store.state.device.fixedWidgetsPosition) return;
-
- const stickyWidgetColumns = this.$refs.widgets.map(w => new StickySidebar(w.children[1], w.children[0], w.offsetTop));
- window.addEventListener('scroll', () => {
- for (const stickyWidgetColumn of stickyWidgetColumns) {
- stickyWidgetColumn.calc(window.scrollY);
- }
- }, { passive: true });
- },
-
- top() {
- window.scroll({ top: 0, behavior: 'smooth' });
- },
-
- help() {
- this.$router.push('/docs/keyboard-shortcut');
- },
-
- back() {
- if (this.canBack) window.history.back();
- },
-
- onTransition() {
- if (window._scroll) window._scroll();
- },
-
- post() {
- this.$root.post();
- },
-
- search() {
- if (this.searching) return;
-
- this.$root.dialog({
- title: this.$t('search'),
- input: true
- }).then(async ({ canceled, result: query }) => {
- if (canceled || query == null || query === '') return;
-
- this.searching = true;
- search(this, query).finally(() => {
- this.searching = false;
- });
- });
- },
-
- searchKeypress(e) {
- if (e.keyCode === 13) {
- this.searchWait = true;
- search(this, this.searchQuery).finally(() => {
- this.searchWait = false;
- this.searchQuery = '';
- });
- }
- },
-
- async onNotification(notification) {
- if (this.$store.state.i.mutingNotificationTypes.includes(notification.type)) {
- return;
- }
- if (document.visibilityState === 'visible') {
- this.$root.stream.send('readNotification', {
- id: notification.id
- });
-
- this.$root.new(await import('./components/toast.vue').then(m => m.default), {
- notification
- });
- }
-
- this.$root.sound('notification');
- },
-
- widgetFunc(id) {
- this.$refs[id][0].setting();
- },
-
- onWidgetSort() {
- this.saveHome();
- },
-
- async addWidget(place) {
- const { canceled, result: widget } = await this.$root.dialog({
- type: null,
- title: this.$t('chooseWidget'),
- select: {
- items: widgets.map(widget => ({
- value: widget,
- text: this.$t('_widgets.' + widget),
- }))
- },
- showCancelButton: true
- });
- if (canceled) return;
-
- this.$store.commit('deviceUser/addWidget', {
- name: widget,
- id: uuid(),
- place: place,
- data: {}
- });
- },
-
- removeWidget(widget) {
- this.$store.commit('deviceUser/removeWidget', widget);
- },
-
- saveHome() {
- this.$store.commit('deviceUser/setWidgets', [...this.widgets.left, ...this.widgets.right, ...this.widgets.mobile]);
- }
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.mk-app {
- $header-height: 60px;
- $main-width: 670px;
- $ui-font-size: 1em; // TODO: どこかに集約したい
- $header-sub-hide-threshold: 1090px;
- $left-widgets-hide-threshold: 1600px;
- $right-widgets-hide-threshold: 1090px;
-
- // ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
- min-height: calc(var(--vh, 1vh) * 100);
- box-sizing: border-box;
- padding-top: $header-height;
-
- &, > .header > .body {
- display: flex;
- margin: 0 auto;
- }
-
- > .header {
- position: fixed;
- z-index: 1000;
- top: 0;
- right: 0;
- height: $header-height;
- width: 100%;
- //background-color: var(--panel);
- -webkit-backdrop-filter: blur(32px);
- backdrop-filter: blur(32px);
- background-color: var(--header);
- border-bottom: solid 1px var(--divider);
-
- > .title {
- position: relative;
- line-height: $header-height;
- height: $header-height;
- max-width: $main-width;
- text-align: center;
-
- > .back {
- position: absolute;
- z-index: 1;
- top: 0;
- left: 0;
- height: $header-height;
- width: $header-height;
- }
-
- > .body {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- height: $header-height;
-
- > .default {
- padding: 0 $header-height;
-
- > .avatar {
- $size: 32px;
- display: inline-block;
- width: $size;
- height: $size;
- vertical-align: bottom;
- margin: (($header-height - $size) / 2) 8px (($header-height - $size) / 2) 0;
- }
-
- > .title {
- display: inline-block;
- font-size: $ui-font-size;
- margin: 0;
- line-height: $header-height;
-
- > [data-icon] {
- margin-right: 8px;
- }
- }
- }
-
- > .custom {
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- width: 100%;
- }
- }
- }
-
- > .sub {
- $post-button-size: 42px;
- $post-button-margin: (($header-height - $post-button-size) / 2);
- display: flex;
- align-items: center;
- position: absolute;
- top: 0;
- right: 16px;
- height: $header-height;
-
- @media (max-width: $header-sub-hide-threshold) {
- display: none;
- }
-
- > .edit {
- padding: 16px;
-
- &.active {
- color: var(--accent);
- }
- }
-
- > .search {
- position: relative;
-
- > input {
- width: 220px;
- box-sizing: border-box;
- margin-right: 8px;
- padding: 0 12px 0 42px;
- font-size: 1rem;
- line-height: 38px;
- border: none;
- border-radius: 38px;
- color: var(--fg);
- background: var(--bg);
- -webkit-appearance: textfield;
-
- &:focus {
- outline: none;
- }
- }
-
- > [data-icon] {
- position: absolute;
- top: 0;
- left: 16px;
- height: 100%;
- pointer-events: none;
- font-size: 16px;
- }
- }
-
- > .post {
- width: $post-button-size;
- height: $post-button-size;
- margin-left: $post-button-margin;
- border-radius: 100%;
- font-size: 16px;
- }
-
- > .clock {
- margin-left: 8px;
- }
- }
- }
-
- > .contents {
- display: flex;
- margin: 0 auto;
- min-width: 0;
-
- &.wallpaper {
- background: var(--wallpaperOverlay);
- backdrop-filter: blur(4px);
- }
-
- &.full {
- width: 100%;
-
- > main {
- width: 100%;
- }
-
- > .widgets {
- display: none;
- }
- }
-
- > main {
- width: $main-width;
- min-width: 0;
-
- > .content {
- > * {
- // ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
- min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
- box-sizing: border-box;
- padding: var(--margin);
-
- &.full {
- padding: 0 var(--margin);
- }
- }
- }
-
- > .powerd-by {
- font-size: 14px;
- text-align: center;
- margin: 32px 0;
- visibility: hidden;
-
- &.visible {
- visibility: visible;
- }
-
- &:not(.visible) {
- @media (min-width: 850px) {
- display: none;
- }
- }
-
- @media (max-width: 500px) {
- margin-top: 16px;
- }
-
- > small {
- display: block;
- margin-top: 8px;
- opacity: 0.5;
-
- @media (max-width: 500px) {
- margin-top: 4px;
- }
- }
- }
- }
-
- > .widgets {
- padding: 0 var(--margin);
- box-shadow: 1px 0 0 0 var(--divider), -1px 0 0 0 var(--divider);
-
- &.fixed {
- position: sticky;
- overflow: auto;
- // ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
- height: calc((var(--vh, 1vh) * 100) - #{$header-height});
- top: $header-height;
- }
-
- &:first-of-type {
- order: -1;
-
- @media (max-width: $left-widgets-hide-threshold) {
- display: none;
- }
- }
-
- &.empty {
- display: none;
- }
-
- @media (max-width: $right-widgets-hide-threshold) {
- display: none;
- }
-
- > .container {
- position: sticky;
- height: min-content;
- // ほんとは単に calc(100vh - #{$header-height}) と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
- min-height: calc((var(--vh, 1vh) * 100) - #{$header-height});
- padding: var(--margin) 0;
- box-sizing: border-box;
-
- > * {
- margin: var(--margin) 0;
- width: 300px;
-
- &:first-child {
- margin-top: 0;
- }
-
- &:last-child {
- margin-bottom: 0;
- }
- }
- }
-
- > .add {
- margin: 0 auto;
- }
-
- .customize-container {
- margin: 8px 0;
-
- > header {
- position: relative;
- line-height: 32px;
-
- > .handle {
- padding: 0 8px;
- cursor: move;
- }
-
- > .remove {
- position: absolute;
- top: 0;
- right: 0;
- padding: 0 8px;
- line-height: 32px;
- }
- }
-
- > div {
- padding: 8px;
-
- > * {
- pointer-events: none;
- }
- }
- }
- }
- }
-
- > .post {
- display: block;
- position: fixed;
- z-index: 1000;
- bottom: 32px;
- right: 32px;
- width: 64px;
- height: 64px;
- border-radius: 100%;
- box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
- font-size: 22px;
-
- &.navHidden {
- display: none;
- }
-
- @media (min-width: ($header-sub-hide-threshold + 1px)) {
- display: none;
- }
- }
-
- > .buttons {
- position: fixed;
- z-index: 1000;
- bottom: 0;
- padding: 0 32px 32px 32px;
- display: flex;
- width: 100%;
- box-sizing: border-box;
- background: linear-gradient(0deg, var(--bg), var(--X1));
-
- @media (max-width: 500px) {
- padding: 0 16px 16px 16px;
- }
-
- &:not(.navHidden) {
- display: none;
- }
-
- > .button {
- position: relative;
- padding: 0;
- margin: auto;
- width: 64px;
- height: 64px;
- border-radius: 100%;
- box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
-
- &:first-child {
- margin-left: 0;
- }
-
- &:last-child {
- margin-right: 0;
- }
-
- > * {
- font-size: 22px;
- }
-
- &:disabled {
- cursor: default;
-
- > * {
- opacity: 0.5;
- }
- }
-
- &:not(.post) {
- background: var(--panel);
- color: var(--fg);
-
- &:hover {
- background: var(--X2);
- }
-
- > i {
- position: absolute;
- top: 0;
- left: 0;
- color: var(--indicator);
- font-size: 16px;
- animation: blink 1s infinite;
- }
- }
- }
- }
-}
-</style>