diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-04-14 16:39:53 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-04-14 16:39:53 +0900 |
| commit | 449dc17df8fe3b6cc220aaabd576b0f04f6028da (patch) | |
| tree | 33e5c4da1b43f1bba0a02501150c760623fc9798 /src/client/components | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.76.0 (diff) | |
| download | misskey-449dc17df8fe3b6cc220aaabd576b0f04f6028da.tar.gz misskey-449dc17df8fe3b6cc220aaabd576b0f04f6028da.tar.bz2 misskey-449dc17df8fe3b6cc220aaabd576b0f04f6028da.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/client/components')
55 files changed, 560 insertions, 675 deletions
diff --git a/src/client/components/abuse-report-window.vue b/src/client/components/abuse-report-window.vue index 7dbb9657bd..df5b594c0b 100644 --- a/src/client/components/abuse-report-window.vue +++ b/src/client/components/abuse-report-window.vue @@ -8,19 +8,15 @@ </template> </I18n> </template> - <div class="dpvffvvy"> + <div class="dpvffvvy _monolithic_"> <div class="_section"> - <div class="_content"> - <MkTextarea v-model:value="comment"> - <span>{{ $ts.details }}</span> - <template #desc>{{ $ts.fillAbuseReportDescription }}</template> - </MkTextarea> - </div> + <MkTextarea v-model:value="comment"> + <span>{{ $ts.details }}</span> + <template #desc>{{ $ts.fillAbuseReportDescription }}</template> + </MkTextarea> </div> <div class="_section"> - <div class="_content"> - <MkButton @click="send" primary full :disabled="comment.length === 0">{{ $ts.send }}</MkButton> - </div> + <MkButton @click="send" primary full :disabled="comment.length === 0">{{ $ts.send }}</MkButton> </div> </div> </XWindow> @@ -80,6 +76,6 @@ export default defineComponent({ <style lang="scss" scoped> .dpvffvvy { - --section-padding: 16px; + --root-margin: 16px; } </style> diff --git a/src/client/components/channel-preview.vue b/src/client/components/channel-preview.vue index e222ad7ae7..4dc633bcb7 100644 --- a/src/client/components/channel-preview.vue +++ b/src/client/components/channel-preview.vue @@ -123,7 +123,7 @@ export default defineComponent({ > footer { padding: 12px 16px; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); > span { opacity: 0.7; diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue index be9f01ca1f..433655d6ed 100644 --- a/src/client/components/date-separated-list.vue +++ b/src/client/components/date-separated-list.vue @@ -37,14 +37,16 @@ export default defineComponent({ }); } + const noGap = [...document.querySelectorAll('._noGap_')].some(el => el.contains(this.$parent.$el)); + return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? { - class: 'sqadhkmv _list_', + class: 'sqadhkmv' + (noGap ? ' _block' : ''), name: 'list', tag: 'div', 'data-direction': this.direction, 'data-reversed': this.reversed ? 'true' : 'false', } : { - class: 'sqadhkmv _list_', + class: 'sqadhkmv', }, this.items.map((item, i) => { const el = this.$slots.default({ item: item @@ -117,11 +119,7 @@ export default defineComponent({ transform: translateY(-64px); } } -} -</style> -<style lang="scss"> -.sqadhkmv { > .separator { text-align: center; @@ -155,4 +153,25 @@ export default defineComponent({ } } } + +._noGap_ .sqadhkmv { + > * { + margin: 0 !important; + border: none; + border-radius: 0; + box-shadow: none; + + &:not(:last-child) { + border-bottom: solid 0.5px var(--divider); + } + } +} + +._inContainer_ .sqadhkmv > * { + margin: 0 !important; + border: none; + border-bottom: solid 0.5px var(--divider); + border-radius: 0; + box-shadow: none; +} </style> diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue index 03f2da008d..fb8b50d25a 100644 --- a/src/client/components/drive.file.vue +++ b/src/client/components/drive.file.vue @@ -330,8 +330,8 @@ export default defineComponent({ } > .thumbnail { - width: 128px; - height: 128px; + width: 110px; + height: 110px; margin: auto; } diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue index 150d0d8774..103ae9c11e 100644 --- a/src/client/components/drive.vue +++ b/src/client/components/drive.vue @@ -11,7 +11,7 @@ <span class="folder current" v-if="folder != null">{{ folder.name }}</span> </div> </nav> - <div class="main _section" :class="{ uploading: uploadings.length > 0, fetching }" + <div class="main" :class="{ uploading: uploadings.length > 0, fetching }" ref="main" @dragover.prevent.stop="onDragover" @dragenter="onDragenter" @@ -704,6 +704,7 @@ export default defineComponent({ > .main { flex: 1; overflow: auto; + padding: var(--margin); &, * { user-select: none; @@ -735,7 +736,7 @@ export default defineComponent({ > .folder, > .file { flex-grow: 1; - width: 144px; + width: 128px; margin: 4px; box-sizing: border-box; } @@ -743,7 +744,7 @@ export default defineComponent({ > .padding { flex-grow: 1; pointer-events: none; - width: 144px + 8px; + width: 128px + 8px; } } diff --git a/src/client/components/emoji-picker-dialog.vue b/src/client/components/emoji-picker-dialog.vue index 5bdbc330ad..c4b12e2f61 100644 --- a/src/client/components/emoji-picker-dialog.vue +++ b/src/client/components/emoji-picker-dialog.vue @@ -123,7 +123,7 @@ export default defineComponent({ > .index { min-height: var(--height); position: relative; - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); > .arrow { position: absolute; @@ -181,7 +181,7 @@ export default defineComponent({ } &.result { - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); &:empty { display: none; diff --git a/src/client/components/emoji-picker-window.vue b/src/client/components/emoji-picker-window.vue index 5504eaecd6..53b6ae6b32 100644 --- a/src/client/components/emoji-picker-window.vue +++ b/src/client/components/emoji-picker-window.vue @@ -119,7 +119,7 @@ export default defineComponent({ > .index { min-height: var(--height); position: relative; - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); > .arrow { position: absolute; @@ -177,7 +177,7 @@ export default defineComponent({ } &.result { - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); &:empty { display: none; diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue index 573833b9d3..a212c15049 100644 --- a/src/client/components/emoji-picker.vue +++ b/src/client/components/emoji-picker.vue @@ -402,7 +402,7 @@ export default defineComponent({ > .tab { flex: 1; height: 38px; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); &.active { border-top: solid 1px var(--accent); @@ -425,7 +425,7 @@ export default defineComponent({ > div { &:not(.index) { padding: 4px 0 8px 0; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } > header { @@ -492,7 +492,7 @@ export default defineComponent({ } &.result { - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); &:empty { display: none; diff --git a/src/client/components/form/base.vue b/src/client/components/form/base.vue index 249b49c675..84438a5b32 100644 --- a/src/client/components/form/base.vue +++ b/src/client/components/form/base.vue @@ -20,12 +20,16 @@ export default defineComponent({ <style lang="scss" scoped> .rbusrurv { - line-height: 1.4em; + // 他のCSSからも参照されるので消さないように + --formXPadding: 32px; + --formYPadding: 32px; + + line-height: 1.3em; background: var(--bg); - padding: 32px; + padding: var(--formYPadding) var(--formXPadding); &:not(.wide).max-width_400px { - padding: 32px 0; + --formXPadding: 0px; > ::v-deep(*) { ._formPanel { diff --git a/src/client/components/form/form.scss b/src/client/components/form/form.scss index c7f4373544..8c01fad727 100644 --- a/src/client/components/form/form.scss +++ b/src/client/components/form/form.scss @@ -1,32 +1,48 @@ ._formPanel { background: var(--panel); border-radius: var(--radius); + transition: background 0.2s ease; &._formClickable { &:hover { //background: var(--panelHighlight); } + + &:active { + background: var(--panelHighlight); + transition: background 0s; + } } } -._formLabel { +._formLabel, +._formCaption { font-size: 80%; - padding: 0 16px 8px 16px; - opacity: 0.8; + color: var(--fgTransparentWeak); &:empty { display: none; } } +._formLabel { + position: sticky; + top: var(--stickyTop, 0px); + z-index: 2; + margin: -8px calc(var(--formXPadding) * -1) 0 calc(var(--formXPadding) * -1); + padding: 8px calc(16px + var(--formXPadding)) 8px calc(16px + var(--formXPadding)); + background: var(--X17); + -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); +} + +._themeChanging_ ._formLabel { + transition: none !important; + background: transparent; +} + ._formCaption { - font-size: 80%; padding: 8px 16px 0 16px; - opacity: 0.8; - - &:empty { - display: none; - } } ._formItem { diff --git a/src/client/components/form/info.vue b/src/client/components/form/info.vue new file mode 100644 index 0000000000..a9224c7e65 --- /dev/null +++ b/src/client/components/form/info.vue @@ -0,0 +1,49 @@ +<template> +<div class="fzenkabp _formItem"> + <div class="_formPanel" :class="{ warn }"> + <i v-if="warn"><Fa :icon="faExclamationTriangle"/></i> + <i v-else><Fa :icon="faInfoCircle"/></i> + <slot></slot> + </div> +</div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons'; + +export default defineComponent({ + props: { + warn: { + type: Boolean, + required: false, + default: false + }, + }, + data() { + return { + faInfoCircle, faExclamationTriangle + }; + } +}); +</script> + +<style lang="scss" scoped> +.fzenkabp { + > div { + padding: 14px 16px; + font-size: 90%; + background: var(--infoBg); + color: var(--infoFg); + + &.warn { + background: var(--infoWarnBg); + color: var(--infoWarnFg); + } + + > i { + margin-right: 4px; + } + } +} +</style> diff --git a/src/client/components/form/input.vue b/src/client/components/form/input.vue index f0aa6b0534..c0fa3e716e 100644 --- a/src/client/components/form/input.vue +++ b/src/client/components/form/input.vue @@ -215,7 +215,7 @@ export default defineComponent({ } > .input { - $height: 52px; + $height: 48px; position: relative; > input { diff --git a/src/client/components/form/link.vue b/src/client/components/form/link.vue index 2efc6b58c9..af36bcf22c 100644 --- a/src/client/components/form/link.vue +++ b/src/client/components/form/link.vue @@ -66,6 +66,7 @@ export default defineComponent({ &.active { color: var(--accent); + background: var(--panelHighlight); } > .icon { diff --git a/src/client/components/form/radios.vue b/src/client/components/form/radios.vue index 4561df32e1..3daa7e5bbd 100644 --- a/src/client/components/form/radios.vue +++ b/src/client/components/form/radios.vue @@ -69,8 +69,8 @@ export default defineComponent({ display: inline-block; vertical-align: bottom; position: relative; - width: 20px; - height: 20px; + width: 16px; + height: 16px; margin-right: 8px; background: none; border: 2px solid var(--inputBorder); diff --git a/src/client/components/form/range.vue b/src/client/components/form/range.vue index 3452184c55..65d665c70a 100644 --- a/src/client/components/form/range.vue +++ b/src/client/components/form/range.vue @@ -69,7 +69,7 @@ export default defineComponent({ position: relative; > .main { - padding: 24px 16px; + padding: 22px 16px; > input { display: block; diff --git a/src/client/components/form/select.vue b/src/client/components/form/select.vue index b865372f56..01f28587dc 100644 --- a/src/client/components/form/select.vue +++ b/src/client/components/form/select.vue @@ -97,7 +97,7 @@ export default defineComponent({ font: inherit; font-weight: normal; font-size: 1em; - height: 52px; + height: 48px; background: none; border: none; border-radius: 0; diff --git a/src/client/components/form/switch.vue b/src/client/components/form/switch.vue index a2941c5996..e7ef714c49 100644 --- a/src/client/components/form/switch.vue +++ b/src/client/components/form/switch.vue @@ -57,7 +57,7 @@ export default defineComponent({ > .main { position: relative; display: flex; - padding: 16px; + padding: 14px 16px; cursor: pointer; > * { diff --git a/src/client/components/global/a.vue b/src/client/components/global/a.vue index a8a597b2bb..7ad62a7310 100644 --- a/src/client/components/global/a.vue +++ b/src/client/components/global/a.vue @@ -93,6 +93,10 @@ export default defineComponent({ os.pageWindow(this.to); }, + modalWindow() { + os.modalPageWindow(this.to); + }, + popout() { popout(this.to); }, @@ -111,6 +115,8 @@ export default defineComponent({ if (this.behavior) { if (this.behavior === 'window') { return this.window(); + } else if (this.behavior === 'modalWindow') { + return this.modalWindow(); } } diff --git a/src/client/components/global/acct.vue b/src/client/components/global/acct.vue index a969636a7e..70f2954cb0 100644 --- a/src/client/components/global/acct.vue +++ b/src/client/components/global/acct.vue @@ -1,5 +1,5 @@ <template> -<span class="mk-acct" v-once> +<span class="mk-acct"> <span class="name">@{{ user.username }}</span> <span class="host" v-if="user.host || detail || $store.state.showFullAcct">@{{ user.host || host }}</span> </span> @@ -7,11 +7,20 @@ <script lang="ts"> import { defineComponent } from 'vue'; -import { toUnicode } from 'punycode'; +import { toUnicode } from 'punycode/'; import { host } from '@client/config'; export default defineComponent({ - props: ['user', 'detail'], + props: { + user: { + type: Object, + required: true + }, + detail: { + type: Boolean, + default: false + }, + }, data() { return { host: toUnicode(host), diff --git a/src/client/components/global/url.vue b/src/client/components/global/url.vue index c89536ebdb..f68a3c00be 100644 --- a/src/client/components/global/url.vue +++ b/src/client/components/global/url.vue @@ -22,7 +22,7 @@ <script lang="ts"> import { defineComponent } from 'vue'; import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons'; -import { toUnicode as decodePunycode } from 'punycode'; +import { toUnicode as decodePunycode } from 'punycode/'; import { url as local } from '@client/config'; import { isDeviceTouch } from '@client/scripts/is-device-touch'; import * as os from '@client/os'; diff --git a/src/client/components/launch-pad.vue b/src/client/components/launch-pad.vue index a81320954c..7610b44eb5 100644 --- a/src/client/components/launch-pad.vue +++ b/src/client/components/launch-pad.vue @@ -146,7 +146,7 @@ export default defineComponent({ > .sub { margin-top: 8px; padding-top: 8px; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } } </style> diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue index 41760d98d7..4de5daa84f 100644 --- a/src/client/components/media-image.vue +++ b/src/client/components/media-image.vue @@ -123,7 +123,7 @@ export default defineComponent({ .gqnyydlz { position: relative; - border: solid 1px var(--divider); + border: solid 0.5px var(--divider); > i { display: block; diff --git a/src/client/components/mention.vue b/src/client/components/mention.vue index 322e56d957..b9bd6b320b 100644 --- a/src/client/components/mention.vue +++ b/src/client/components/mention.vue @@ -16,7 +16,7 @@ <script lang="ts"> import { defineComponent } from 'vue'; -import { toUnicode } from 'punycode'; +import { toUnicode } from 'punycode/'; import { host as localHost } from '@client/config'; import { wellKnownServices } from '../../well-known-services'; import * as os from '@client/os'; diff --git a/src/client/components/mfm.ts b/src/client/components/mfm.ts index 28ac9b8942..b8e948a188 100644 --- a/src/client/components/mfm.ts +++ b/src/client/components/mfm.ts @@ -1,6 +1,5 @@ import { VNode, defineComponent, h } from 'vue'; -import { MfmForest } from '@client/../mfm/prelude'; -import { parse, parsePlain } from '@client/../mfm/parse'; +import * as mfm from 'mfm-js'; import MkUrl from '@client/components/global/url.vue'; import MkLink from '@client/components/link.vue'; import MkMention from '@client/components/mention.vue'; @@ -46,17 +45,17 @@ export default defineComponent({ render() { if (this.text == null || this.text == '') return; - const ast = (this.plain ? parsePlain : parse)(this.text); + const ast = (this.plain ? mfm.parsePlain : mfm.parse)(this.text); const validTime = (t: string | null | undefined) => { if (t == null) return null; return t.match(/^[0-9.]+s$/) ? t : null; }; - const genEl = (ast: MfmForest) => concat(ast.map((token): VNode[] => { - switch (token.node.type) { + const genEl = (ast: mfm.MfmNode[]) => concat(ast.map((token): VNode[] => { + switch (token.type) { case 'text': { - const text = token.node.props.text.replace(/(\r\n|\n|\r)/g, '\n'); + const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n'); if (!this.plain) { const x = text.split('\n') @@ -83,38 +82,38 @@ export default defineComponent({ } case 'fn': { - // TODO: CSSを文字列で組み立てていくと token.node.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる + // TODO: CSSを文字列で組み立てていくと token.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる let style; - switch (token.node.props.name) { + switch (token.props.name) { case 'tada': { style = `font-size: 150%;` + (this.$store.state.animatedMfm ? 'animation: tada 1s linear infinite both;' : ''); break; } case 'jelly': { - const speed = validTime(token.node.props.args.speed) || '1s'; + const speed = validTime(token.props.args.speed) || '1s'; style = (this.$store.state.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : ''); break; } case 'twitch': { - const speed = validTime(token.node.props.args.speed) || '0.5s'; + const speed = validTime(token.props.args.speed) || '0.5s'; style = this.$store.state.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : ''; break; } case 'shake': { - const speed = validTime(token.node.props.args.speed) || '0.5s'; + const speed = validTime(token.props.args.speed) || '0.5s'; style = this.$store.state.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : ''; break; } case 'spin': { const direction = - token.node.props.args.left ? 'reverse' : - token.node.props.args.alternate ? 'alternate' : + token.props.args.left ? 'reverse' : + token.props.args.alternate ? 'alternate' : 'normal'; const anime = - token.node.props.args.x ? 'mfm-spinX' : - token.node.props.args.y ? 'mfm-spinY' : + token.props.args.x ? 'mfm-spinX' : + token.props.args.y ? 'mfm-spinY' : 'mfm-spin'; - const speed = validTime(token.node.props.args.speed) || '1.5s'; + const speed = validTime(token.props.args.speed) || '1.5s'; style = this.$store.state.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : ''; break; } @@ -128,8 +127,8 @@ export default defineComponent({ } case 'flip': { const transform = - (token.node.props.args.h && token.node.props.args.v) ? 'scale(-1, -1)' : - token.node.props.args.v ? 'scaleY(-1)' : + (token.props.args.h && token.props.args.v) ? 'scale(-1, -1)' : + token.props.args.v ? 'scaleY(-1)' : 'scaleX(-1)'; style = `transform: ${transform};`; break; @@ -148,12 +147,12 @@ export default defineComponent({ } case 'font': { const family = - token.node.props.args.serif ? 'serif' : - token.node.props.args.monospace ? 'monospace' : - token.node.props.args.cursive ? 'cursive' : - token.node.props.args.fantasy ? 'fantasy' : - token.node.props.args.emoji ? 'emoji' : - token.node.props.args.math ? 'math' : + token.props.args.serif ? 'serif' : + token.props.args.monospace ? 'monospace' : + token.props.args.cursive ? 'cursive' : + token.props.args.fantasy ? 'fantasy' : + token.props.args.emoji ? 'emoji' : + token.props.args.math ? 'math' : null; if (family) style = `font-family: ${family};`; break; @@ -165,7 +164,7 @@ export default defineComponent({ } } if (style == null) { - return h('span', {}, ['[', token.node.props.name, ...genEl(token.children), ']']); + return h('span', {}, ['[', token.props.name, ...genEl(token.children), ']']); } else { return h('span', { style: 'display: inline-block;' + style, @@ -188,7 +187,7 @@ export default defineComponent({ case 'url': { return [h(MkUrl, { key: Math.random(), - url: token.node.props.url, + url: token.props.url, rel: 'nofollow noopener', })]; } @@ -196,7 +195,7 @@ export default defineComponent({ case 'link': { return [h(MkLink, { key: Math.random(), - url: token.node.props.url, + url: token.props.url, rel: 'nofollow noopener', }, genEl(token.children))]; } @@ -204,32 +203,31 @@ export default defineComponent({ case 'mention': { return [h(MkMention, { key: Math.random(), - host: (token.node.props.host == null && this.author && this.author.host != null ? this.author.host : token.node.props.host) || host, - username: token.node.props.username + host: (token.props.host == null && this.author && this.author.host != null ? this.author.host : token.props.host) || host, + username: token.props.username })]; } case 'hashtag': { return [h(MkA, { key: Math.random(), - to: this.isNote ? `/tags/${encodeURIComponent(token.node.props.hashtag)}` : `/explore/tags/${encodeURIComponent(token.node.props.hashtag)}`, + to: this.isNote ? `/tags/${encodeURIComponent(token.props.hashtag)}` : `/explore/tags/${encodeURIComponent(token.props.hashtag)}`, style: 'color:var(--hashtag);' - }, `#${token.node.props.hashtag}`)]; + }, `#${token.props.hashtag}`)]; } case 'blockCode': { return [h(MkCode, { key: Math.random(), - code: token.node.props.code, - lang: token.node.props.lang, + code: token.props.code, + lang: token.props.lang, })]; } case 'inlineCode': { return [h(MkCode, { key: Math.random(), - code: token.node.props.code, - lang: token.node.props.lang, + code: token.props.code, inline: true })]; } @@ -246,10 +244,19 @@ export default defineComponent({ } } - case 'emoji': { + case 'emojiCode': { return [h(MkEmoji, { key: Math.random(), - emoji: token.node.props.name ? `:${token.node.props.name}:` : token.node.props.emoji, + emoji: `:${token.props.name}:`, + customEmojis: this.customEmojis, + normal: this.plain + })]; + } + + case 'unicodeEmoji': { + return [h(MkEmoji, { + key: Math.random(), + emoji: token.props.emoji, customEmojis: this.customEmojis, normal: this.plain })]; @@ -258,7 +265,7 @@ export default defineComponent({ case 'mathInline': { return [h(MkFormula, { key: Math.random(), - formula: token.node.props.formula, + formula: token.props.formula, block: false })]; } @@ -266,7 +273,7 @@ export default defineComponent({ case 'mathBlock': { return [h(MkFormula, { key: Math.random(), - formula: token.node.props.formula, + formula: token.props.formula, block: true })]; } @@ -274,12 +281,12 @@ export default defineComponent({ case 'search': { return [h(MkGoogle, { key: Math.random(), - q: token.node.props.query + q: token.props.query })]; } default: { - console.error('unrecognized ast type:', token.node.type); + console.error('unrecognized ast type:', token.type); return []; } diff --git a/src/client/components/modal-page-window.vue b/src/client/components/modal-page-window.vue new file mode 100644 index 0000000000..474a67f985 --- /dev/null +++ b/src/client/components/modal-page-window.vue @@ -0,0 +1,213 @@ +<template> +<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')"> + <div class="hrmcaedk _popup _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }"> + <div class="header"> + <button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button> + <button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button> + <span class="title"> + <XHeader :info="pageInfo" :with-back="false"/> + </span> + <button class="_button" @click="$refs.modal.close()"><Fa :icon="faTimes"/></button> + </div> + <div class="body _flat_"> + <keep-alive> + <component :is="component" v-bind="props" :ref="changePage"/> + </keep-alive> + </div> + </div> +</MkModal> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { faExternalLinkAlt, faExpandAlt, faLink, faChevronLeft, faColumns, faTimes } from '@fortawesome/free-solid-svg-icons'; +import MkModal from '@client/components/ui/modal.vue'; +import XHeader from '@client/ui/_common_/header.vue'; +import { popout } from '@client/scripts/popout'; +import copyToClipboard from '@client/scripts/copy-to-clipboard'; +import { resolve } from '@client/router'; +import { url } from '@client/config'; +import * as symbols from '@client/symbols'; + +export default defineComponent({ + components: { + MkModal, + XHeader, + }, + + inject: { + sideViewHook: { + default: null + } + }, + + provide() { + return { + navHook: (path) => { + this.navigate(path); + } + }; + }, + + props: { + initialPath: { + type: String, + required: true, + }, + initialComponent: { + type: Object, + required: true, + }, + initialProps: { + type: Object, + required: false, + default: () => {}, + }, + }, + + emits: ['closed'], + + data() { + return { + width: 860, + height: 660, + pageInfo: null, + path: this.initialPath, + component: this.initialComponent, + props: this.initialProps, + history: [], + faChevronLeft, faTimes, + }; + }, + + computed: { + url(): string { + return url + this.path; + }, + + contextmenu() { + return [{ + type: 'label', + text: this.path, + }, { + icon: faExpandAlt, + text: this.$ts.showInPage, + action: this.expand + }, this.sideViewHook ? { + icon: faColumns, + text: this.$ts.openInSideView, + action: () => { + this.sideViewHook(this.path); + this.$refs.window.close(); + } + } : undefined, { + icon: faExternalLinkAlt, + text: this.$ts.popout, + action: this.popout + }, null, { + icon: faExternalLinkAlt, + text: this.$ts.openInNewTab, + action: () => { + window.open(this.url, '_blank'); + this.$refs.window.close(); + } + }, { + icon: faLink, + text: this.$ts.copyLink, + action: () => { + copyToClipboard(this.url); + } + }]; + }, + }, + + methods: { + changePage(page) { + if (page == null) return; + if (page[symbols.PAGE_INFO]) { + this.pageInfo = page[symbols.PAGE_INFO]; + } + }, + + navigate(path, record = true) { + if (record) this.history.push(this.path); + this.path = path; + const { component, props } = resolve(path); + this.component = component; + this.props = props; + }, + + back() { + this.navigate(this.history.pop(), false); + }, + + expand() { + this.$router.push(this.path); + this.$refs.window.close(); + }, + + popout() { + popout(this.path, this.$el); + this.$refs.window.close(); + }, + }, +}); +</script> + +<style lang="scss" scoped> +.hrmcaedk { + overflow: hidden; + display: flex; + flex-direction: column; + contain: content; + + --root-margin: 24px; + + @media (max-width: 500px) { + --root-margin: 16px; + } + + > .header { + $height: 52px; + $height-narrow: 42px; + display: flex; + flex-shrink: 0; + box-shadow: 0px 1px var(--divider); + + > button { + height: $height; + width: $height; + + @media (max-width: 500px) { + height: $height-narrow; + width: $height-narrow; + } + } + + > .title { + flex: 1; + line-height: $height; + padding-left: 32px; + font-weight: bold; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + pointer-events: none; + + @media (max-width: 500px) { + line-height: $height-narrow; + padding-left: 16px; + } + } + + > button + .title { + padding-left: 0; + } + } + + > .body { + overflow: auto; + background: var(--bg); + } +} +</style> diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue index fb4f9502b3..b25c97543b 100644 --- a/src/client/components/note-detailed.vue +++ b/src/client/components/note-detailed.vue @@ -1,6 +1,6 @@ <template> <div - class="note _panel" + class="note _block" v-if="!muted" v-show="!isDeleted" :tabindex="!isDeleted ? '-1' : null" @@ -120,11 +120,11 @@ </template> <script lang="ts"> -import { computed, defineAsyncComponent, defineComponent, markRaw, ref } from 'vue'; -import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip } from '@fortawesome/free-solid-svg-icons'; +import { defineAsyncComponent, defineComponent, markRaw } from 'vue'; +import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip, faShareAlt } from '@fortawesome/free-solid-svg-icons'; import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; -import { parse } from '../../mfm/parse'; -import { sum, unique } from '../../prelude/array'; +import * as mfm from 'mfm-js'; +import { sum } from '../../prelude/array'; import XSub from './note.sub.vue'; import XNoteHeader from './note-header.vue'; import XNotePreview from './note-preview.vue'; @@ -141,6 +141,7 @@ import { userPage } from '@client/filters/user'; import * as os from '@client/os'; import { noteActions, noteViewInterruptors } from '@client/store'; import { reactionPicker } from '@client/scripts/reaction-picker'; +import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm'; function markRawAll(...xs) { for (const x of xs) { @@ -252,21 +253,7 @@ export default defineComponent({ urls(): string[] { if (this.appearNote.text) { - const ast = parse(this.appearNote.text); - // TODO: 再帰的にURL要素がないか調べる - const urls = unique(ast - .filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) - .map(t => t.node.props.url)); - - // unique without hash - // [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ] - const removeHash = x => x.replace(/#[^#]*$/, ''); - - return urls.reduce((array, url) => { - const removed = removeHash(url); - if (!array.map(x => removeHash(x)).includes(removed)) array.push(url); - return array; - }, []); + return extractUrlFromMfm(mfm.parse(this.appearNote.text)); } else { return null; } @@ -638,6 +625,11 @@ export default defineComponent({ window.open(this.appearNote.url || this.appearNote.uri, '_blank'); } } : undefined, + { + icon: faShareAlt, + text: this.$ts.share, + action: this.share + }, null, statePromise.then(state => state.isFavorited ? { icon: faStar, @@ -863,6 +855,14 @@ export default defineComponent({ }); }, + share() { + navigator.share({ + title: this.$t('noteOf', { user: this.appearNote.user.name }), + text: this.appearNote.text, + url: `${url}/notes/${this.appearNote.id}` + }); + }, + focus() { this.$el.focus(); }, @@ -1020,7 +1020,7 @@ export default defineComponent({ margin: 0 0.5em; padding: 4px 6px; font-size: 80%; - border: solid 1px var(--divider); + border: solid 0.5px var(--divider); border-radius: 4px; } @@ -1123,7 +1123,7 @@ export default defineComponent({ } > .reply { - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } &.max-width_500px { diff --git a/src/client/components/note-header.vue b/src/client/components/note-header.vue index a6e9b6fe56..ab40c5fd4a 100644 --- a/src/client/components/note-header.vue +++ b/src/client/components/note-header.vue @@ -78,7 +78,7 @@ export default defineComponent({ margin: 0 .5em 0 0; padding: 1px 6px; font-size: 80%; - border: solid 1px var(--divider); + border: solid 0.5px var(--divider); border-radius: 3px; } diff --git a/src/client/components/note.sub.vue b/src/client/components/note.sub.vue index 853d481406..899c4b2f16 100644 --- a/src/client/components/note.sub.vue +++ b/src/client/components/note.sub.vue @@ -139,7 +139,7 @@ export default defineComponent({ } > .reply { - border-left: solid 1px var(--divider); + border-left: solid 0.5px var(--divider); margin-top: 10px; } } diff --git a/src/client/components/note.vue b/src/client/components/note.vue index b54cadfc80..0e153033ca 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -1,6 +1,6 @@ <template> <div - class="tkcbzcuz _panel" + class="tkcbzcuz" v-if="!muted" v-show="!isDeleted" :tabindex="!isDeleted ? '-1' : null" @@ -90,7 +90,7 @@ </div> </article> </div> -<div v-else class="_panel muted" @click="muted = false"> +<div v-else class="muted" @click="muted = false"> <I18n :src="$ts.userSaysSomething" tag="small"> <template #name> <MkA class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId"> @@ -102,11 +102,11 @@ </template> <script lang="ts"> -import { computed, defineAsyncComponent, defineComponent, markRaw, ref } from 'vue'; -import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip } from '@fortawesome/free-solid-svg-icons'; +import { defineAsyncComponent, defineComponent, markRaw } from 'vue'; +import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip, faShareAlt } from '@fortawesome/free-solid-svg-icons'; import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons'; -import { parse } from '../../mfm/parse'; -import { sum, unique } from '../../prelude/array'; +import * as mfm from 'mfm-js'; +import { sum } from '../../prelude/array'; import XSub from './note.sub.vue'; import XNoteHeader from './note-header.vue'; import XNotePreview from './note-preview.vue'; @@ -123,6 +123,7 @@ import { userPage } from '@client/filters/user'; import * as os from '@client/os'; import { noteActions, noteViewInterruptors } from '@client/store'; import { reactionPicker } from '@client/scripts/reaction-picker'; +import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm'; function markRawAll(...xs) { for (const x of xs) { @@ -238,21 +239,7 @@ export default defineComponent({ urls(): string[] { if (this.appearNote.text) { - const ast = parse(this.appearNote.text); - // TODO: 再帰的にURL要素がないか調べる - const urls = unique(ast - .filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) - .map(t => t.node.props.url)); - - // unique without hash - // [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ] - const removeHash = x => x.replace(/#[^#]*$/, ''); - - return urls.reduce((array, url) => { - const removed = removeHash(url); - if (!array.map(x => removeHash(x)).includes(removed)) array.push(url); - return array; - }, []); + return extractUrlFromMfm(mfm.parse(this.appearNote.text)); } else { return null; } @@ -613,6 +600,11 @@ export default defineComponent({ window.open(this.appearNote.url || this.appearNote.uri, '_blank'); } } : undefined, + { + icon: faShareAlt, + text: this.$ts.share, + action: this.share + }, null, statePromise.then(state => state.isFavorited ? { icon: faStar, @@ -838,6 +830,14 @@ export default defineComponent({ }); }, + share() { + navigator.share({ + title: this.$t('noteOf', { user: this.appearNote.user.name }), + text: this.appearNote.text, + url: `${url}/notes/${this.appearNote.id}` + }); + }, + focus() { this.$el.focus(); }, @@ -863,7 +863,7 @@ export default defineComponent({ .tkcbzcuz { position: relative; transition: box-shadow 0.1s ease; - overflow: hidden; + overflow: clip; contain: content; // これらの指定はパフォーマンス向上には有効だが、ノートの高さは一定でないため、 @@ -994,11 +994,12 @@ export default defineComponent({ > .avatar { flex-shrink: 0; display: block; - //position: sticky; - //top: 72px; margin: 0 14px 8px 0; width: 58px; height: 58px; + position: sticky; + top: calc(22px + var(--stickyTop, 0px)); + left: 0; } > .main { @@ -1119,7 +1120,7 @@ export default defineComponent({ } > .reply { - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } &.max-width_500px { @@ -1142,6 +1143,7 @@ export default defineComponent({ margin: 0 10px 8px 0; width: 50px; height: 50px; + top: calc(14px + var(--stickyTop, 0px)); } } } diff --git a/src/client/components/notes.vue b/src/client/components/notes.vue index 80a9502d5f..aedf11bc40 100644 --- a/src/client/components/notes.vue +++ b/src/client/components/notes.vue @@ -1,5 +1,5 @@ <template> -<div class="_list_"> +<div> <div class="_fullinfo" v-if="empty"> <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/> <div>{{ $ts.noNotes }}</div> @@ -15,7 +15,7 @@ </div> <XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed"> - <XNote :note="note" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/> + <XNote :note="note" class="_block" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/> </XList> <div v-show="more && !reversed" style="margin-top: var(--margin);"> diff --git a/src/client/components/notification-setting-window.vue b/src/client/components/notification-setting-window.vue index a3e221f7b2..5f16c042bf 100644 --- a/src/client/components/notification-setting-window.vue +++ b/src/client/components/notification-setting-window.vue @@ -9,17 +9,19 @@ @closed="$emit('closed')" > <template #header>{{ $ts.notificationSetting }}</template> - <div v-if="showGlobalToggle" class="_section"> - <MkSwitch v-model:value="useGlobalSetting"> - {{ $ts.useGlobalSetting }} - <template #desc>{{ $ts.useGlobalSettingDesc }}</template> - </MkSwitch> - </div> - <div v-if="!useGlobalSetting" class="_section"> - <MkInfo>{{ $ts.notificationSettingDesc }}</MkInfo> - <MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton> - <MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton> - <MkSwitch v-for="type in notificationTypes" :key="type" v-model:value="typesMap[type]">{{ $t(`_notification._types.${type}`) }}</MkSwitch> + <div class="_monolithic_"> + <div v-if="showGlobalToggle" class="_section"> + <MkSwitch v-model:value="useGlobalSetting"> + {{ $ts.useGlobalSetting }} + <template #desc>{{ $ts.useGlobalSettingDesc }}</template> + </MkSwitch> + </div> + <div v-if="!useGlobalSetting" class="_section"> + <MkInfo>{{ $ts.notificationSettingDesc }}</MkInfo> + <MkButton inline @click="disableAll">{{ $ts.disableAll }}</MkButton> + <MkButton inline @click="enableAll">{{ $ts.enableAll }}</MkButton> + <MkSwitch v-for="type in notificationTypes" :key="type" v-model:value="typesMap[type]">{{ $t(`_notification._types.${type}`) }}</MkSwitch> + </div> </div> </XModalWindow> </template> diff --git a/src/client/components/notifications.vue b/src/client/components/notifications.vue index 01b3ae4396..baafa86f4d 100644 --- a/src/client/components/notifications.vue +++ b/src/client/components/notifications.vue @@ -1,5 +1,6 @@ <template> <div class="mfcuwfyp _noGap_"> + <div class="_magnet"></div> <XList class="notifications" :items="items" v-slot="{ item: notification }"> <XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :note="notification.note" @update:note="noteUpdated(notification.note, $event)" :key="notification.id"/> <XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/> diff --git a/src/client/components/page-preview.vue b/src/client/components/page-preview.vue index 2125ddc534..cd896445a7 100644 --- a/src/client/components/page-preview.vue +++ b/src/client/components/page-preview.vue @@ -1,5 +1,5 @@ <template> -<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj _panel" tabindex="-1"> +<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj _block _isolated" tabindex="-1"> <div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div> <article> <header> @@ -35,7 +35,6 @@ export default defineComponent({ <style lang="scss" scoped> .vhpxefrj { display: block; - width: 100%; &:hover { text-decoration: none; diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue index ca6f4dd73e..1afde25501 100644 --- a/src/client/components/page-window.vue +++ b/src/client/components/page-window.vue @@ -14,7 +14,7 @@ <button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button> <button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button> </template> - <div class="yrolvcoq" style="min-height: 100%; background: var(--bg);"> + <div class="yrolvcoq _flat_"> <component :is="component" v-bind="props" :ref="changePage"/> </div> </XWindow> @@ -29,6 +29,7 @@ import { popout } from '@client/scripts/popout'; import copyToClipboard from '@client/scripts/copy-to-clipboard'; import { resolve } from '@client/router'; import { url } from '@client/config'; +import * as symbols from '@client/symbols'; export default defineComponent({ components: { @@ -123,8 +124,8 @@ export default defineComponent({ methods: { changePage(page) { if (page == null) return; - if (page.INFO) { - this.pageInfo = page.INFO; + if (page[symbols.PAGE_INFO]) { + this.pageInfo = page[symbols.PAGE_INFO]; } }, @@ -155,6 +156,7 @@ export default defineComponent({ <style lang="scss" scoped> .yrolvcoq { - --section-padding: 16px; + min-height: 100%; + background: var(--bg); } </style> diff --git a/src/client/components/page/page.text.vue b/src/client/components/page/page.text.vue index 491c62be26..580c5a93bf 100644 --- a/src/client/components/page/page.text.vue +++ b/src/client/components/page/page.text.vue @@ -9,8 +9,8 @@ import { TextBlock } from '@client/scripts/hpml/block'; import { Hpml } from '@client/scripts/hpml/evaluator'; import { defineAsyncComponent, defineComponent, PropType } from 'vue'; -import { parse } from '../../../mfm/parse'; -import { unique } from '../../../prelude/array'; +import * as mfm from 'mfm-js'; +import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm'; export default defineComponent({ components: { @@ -34,11 +34,7 @@ export default defineComponent({ computed: { urls(): string[] { if (this.text) { - const ast = parse(this.text); - // TODO: 再帰的にURL要素がないか調べる - return unique(ast - .filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) - .map(t => t.node.props.url)); + return extractUrlFromMfm(mfm.parse(this.text)); } else { return []; } diff --git a/src/client/components/poll.vue b/src/client/components/poll.vue index af3b3804ab..6cf6a8e918 100644 --- a/src/client/components/poll.vue +++ b/src/client/components/poll.vue @@ -110,7 +110,7 @@ export default defineComponent({ position: relative; margin: 4px 0; padding: 4px 8px; - border: solid 1px var(--divider); + border: solid 0.5px var(--divider); border-radius: 4px; overflow: hidden; cursor: pointer; diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue index 7d2355c190..ce79f34d62 100644 --- a/src/client/components/post-form.vue +++ b/src/client/components/post-form.vue @@ -56,12 +56,12 @@ import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlob import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons'; import insertTextAtCursor from 'insert-text-at-cursor'; import { length } from 'stringz'; -import { toASCII } from 'punycode'; +import { toASCII } from 'punycode/'; import XNotePreview from './note-preview.vue'; -import { parse } from '../../mfm/parse'; +import * as mfm from 'mfm-js'; import { host, url } from '@client/config'; import { erase, unique } from '../../prelude/array'; -import extractMentions from '@/misc/extract-mentions'; +import { extractMentions } from '@/misc/extract-mentions'; import getAcct from '@/misc/acct/render'; import { formatTimeString } from '@/misc/format-time-string'; import { Autocomplete } from '@client/scripts/autocomplete'; @@ -229,7 +229,7 @@ export default defineComponent({ } if (this.reply && this.reply.text != null) { - const ast = parse(this.reply.text); + const ast = mfm.parse(this.reply.text); for (const x of extractMentions(ast)) { const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`; @@ -580,7 +580,7 @@ export default defineComponent({ this.deleteDraft(); this.$emit('posted'); if (this.text && this.text != '') { - const hashtags = parse(this.text).filter(x => x.node.type === 'hashtag').map(x => x.node.props.hashtag); + const hashtags = mfm.parse(this.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag); const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[]; localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history)))); } @@ -767,7 +767,7 @@ export default defineComponent({ > .cw { z-index: 1; padding-bottom: 8px; - border-bottom: solid 1px var(--divider); + border-bottom: solid 0.5px var(--divider); } > .text { diff --git a/src/client/components/remote-caution.vue b/src/client/components/remote-caution.vue index 98c7aaaa6e..c9c5ceea4c 100644 --- a/src/client/components/remote-caution.vue +++ b/src/client/components/remote-caution.vue @@ -1,5 +1,5 @@ <template> -<div class="jmgmzlwq _panel"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/>{{ $ts.remoteUserCaution }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div> +<div class="jmgmzlwq _block"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/>{{ $ts.remoteUserCaution }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div> </template> <script lang="ts"> diff --git a/src/client/components/sidebar.vue b/src/client/components/sidebar.vue deleted file mode 100644 index 61439781b4..0000000000 --- a/src/client/components/sidebar.vue +++ /dev/null @@ -1,458 +0,0 @@ -<template> -<div class="mvcprjjd"> - <transition name="nav-back"> - <div class="nav-back _modalBg" - v-if="showing" - @click="showing = false" - @touchstart.passive="showing = false" - ></div> - </transition> - - <transition name="nav"> - <nav class="nav" :class="{ iconOnly, hidden }" v-show="showing"> - <div> - <button class="item _button account" @click="openAccountMenu"> - <MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> - </button> - <MkA class="item index" active-class="active" to="/" exact> - <Fa :icon="faHome" fixed-width/><span class="text">{{ $ts.timeline }}</span> - </MkA> - <template v-for="item in menu"> - <div v-if="item === '-'" class="divider"></div> - <component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to"> - <Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $ts[menuDef[item].title] }}</span> - <i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i> - </component> - </template> - <div class="divider"></div> - <button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$i.isAdmin || $i.isModerator" @click="oepnInstanceMenu"> - <Fa :icon="faServer" fixed-width/><span class="text">{{ $ts.instance }}</span> - </button> - <button class="item _button" @click="more"> - <Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $ts.more }}</span> - <i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i> - </button> - <MkA class="item" active-class="active" to="/settings"> - <Fa :icon="faCog" fixed-width/><span class="text">{{ $ts.settings }}</span> - </MkA> - <button class="item _button post" @click="post"> - <Fa :icon="faPencilAlt" fixed-width/><span class="text">{{ $ts.note }}</span> - </button> - </div> - </nav> - </transition> -</div> -</template> - -<script lang="ts"> -import { defineComponent } 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, faStream, faExclamationCircle } from '@fortawesome/free-solid-svg-icons'; -import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons'; -import { host } from '@client/config'; -import { search } from '@client/scripts/search'; -import * as os from '@client/os'; -import { sidebarDef } from '@client/sidebar'; -import { getAccounts, addAccount, login } from '@client/account'; - -export default defineComponent({ - props: { - defaultHidden: { - type: Boolean, - required: false, - default: false, - } - }, - - data() { - return { - host: host, - showing: false, - accounts: [], - connection: null, - menuDef: sidebarDef, - iconOnly: false, - hidden: this.defaultHidden, - 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: { - menu(): string[] { - return this.$store.state.menu; - }, - - otherNavItemIndicated(): boolean { - for (const def in this.menuDef) { - if (this.menu.includes(def)) continue; - if (this.menuDef[def].indicated) return true; - } - return false; - }, - }, - - watch: { - $route(to, from) { - this.showing = false; - }, - - '$store.reactiveState.sidebarDisplay.value'() { - this.calcViewState(); - }, - - iconOnly() { - this.$nextTick(() => { - this.$emit('change-view-mode'); - }); - }, - - hidden() { - this.$nextTick(() => { - this.$emit('change-view-mode'); - }); - } - }, - - created() { - window.addEventListener('resize', this.calcViewState); - this.calcViewState(); - }, - - methods: { - calcViewState() { - this.iconOnly = (window.innerWidth <= 1279) || (this.$store.state.sidebarDisplay === 'icon'); - if (!this.defaultHidden) { - this.hidden = (window.innerWidth <= 650); - } - }, - - show() { - this.showing = true; - }, - - post() { - os.post(); - }, - - search() { - search(); - }, - - async openAccountMenu(ev) { - const storedAccounts = getAccounts().filter(x => x.id !== this.$i.id); - const accountsPromise = os.api('users/show', { userIds: storedAccounts.map(x => x.id) }); - - const accountItemPromises = storedAccounts.map(a => new Promise(res => { - accountsPromise.then(accounts => { - const account = accounts.find(x => x.id === a.id); - if (account == null) return res(null); - res({ - type: 'user', - user: account, - action: () => { this.switchAccount(account); } - }); - }); - })); - - os.modalMenu([...[{ - type: 'link', - text: this.$ts.profile, - to: `/@${ this.$i.username }`, - avatar: this.$i, - }, null, ...accountItemPromises, { - icon: faPlus, - text: this.$ts.addAcount, - action: () => { - os.modalMenu([{ - text: this.$ts.existingAcount, - action: () => { this.addAcount(); }, - }, { - text: this.$ts.createAccount, - action: () => { this.createAccount(); }, - }], ev.currentTarget || ev.target); - }, - }]], ev.currentTarget || ev.target, { - align: 'left' - }); - }, - - oepnInstanceMenu(ev) { - os.modalMenu([{ - type: 'link', - text: this.$ts.dashboard, - to: '/instance', - icon: faTachometerAlt, - }, null, this.$i.isAdmin ? { - type: 'link', - text: this.$ts.settings, - to: '/instance/settings', - icon: faCog, - } : undefined, { - type: 'link', - text: this.$ts.customEmojis, - to: '/instance/emojis', - icon: faLaugh, - }, { - type: 'link', - text: this.$ts.users, - to: '/instance/users', - icon: faUsers, - }, { - type: 'link', - text: this.$ts.files, - to: '/instance/files', - icon: faCloud, - }, { - type: 'link', - text: this.$ts.jobQueue, - to: '/instance/queue', - icon: faExchangeAlt, - }, { - type: 'link', - text: this.$ts.federation, - to: '/instance/federation', - icon: faGlobe, - }, { - type: 'link', - text: this.$ts.relays, - to: '/instance/relays', - icon: faProjectDiagram, - }, { - type: 'link', - text: this.$ts.announcements, - to: '/instance/announcements', - icon: faBroadcastTower, - }, { - type: 'link', - text: this.$ts.abuseReports, - to: '/instance/abuses', - icon: faExclamationCircle, - }, { - type: 'link', - text: this.$ts.logs, - to: '/instance/logs', - icon: faStream, - }], ev.currentTarget || ev.target); - }, - - more(ev) { - os.popup(import('./launch-pad.vue'), {}, { - }, 'closed'); - }, - - addAcount() { - os.popup(import('./signin-dialog.vue'), {}, { - done: res => { - addAccount(res.id, res.i); - os.success(); - }, - }, 'closed'); - }, - - createAccount() { - os.popup(import('./signup-dialog.vue'), {}, { - done: res => { - addAccount(res.id, res.i); - this.switchAccountWithToken(res.i); - }, - }, 'closed'); - }, - - switchAccount(account: any) { - const storedAccounts = getAccounts(); - const token = storedAccounts.find(x => x.id === account.id).token; - this.switchAccountWithToken(token); - }, - - switchAccountWithToken(token: string) { - login(token); - }, - } -}); -</script> - -<style lang="scss" scoped> -.nav-enter-active, -.nav-leave-active { - opacity: 1; - transform: translateX(0); - transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); -} -.nav-enter-from, -.nav-leave-active { - opacity: 0; - transform: translateX(-240px); -} - -.nav-back-enter-active, -.nav-back-leave-active { - opacity: 1; - transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1); -} -.nav-back-enter-from, -.nav-back-leave-active { - opacity: 0; -} - -.mvcprjjd { - $ui-font-size: 1em; // TODO: どこかに集約したい - $nav-width: 250px; - $nav-icon-only-width: 86px; - - > .nav-back { - z-index: 1001; - } - - > .nav { - $avatar-size: 32px; - $avatar-margin: 8px; - - flex: 0 0 $nav-width; - width: $nav-width; - box-sizing: border-box; - - &.iconOnly { - flex: 0 0 $nav-icon-only-width; - width: $nav-icon-only-width; - - &:not(.hidden) { - > div { - width: $nav-icon-only-width; - - > .divider { - margin: 8px auto; - width: calc(100% - 32px); - } - - > .item { - padding-left: 0; - width: 100%; - text-align: center; - font-size: $ui-font-size * 1.1; - line-height: 3.7rem; - - > [data-icon], - > .avatar { - margin-right: 0; - } - - > i { - left: 10px; - } - - > .text { - display: none; - } - - &:first-child { - margin-bottom: 8px; - } - - &:last-child { - margin-top: 8px; - } - } - } - } - } - - &.hidden { - position: fixed; - top: 0; - left: 0; - z-index: 1001; - } - - &:not(.hidden) { - display: block !important; - } - - > div { - position: fixed; - top: 0; - left: 0; - z-index: 1001; - width: $nav-width; - // ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ - height: calc(var(--vh, 1vh) * 100); - box-sizing: border-box; - overflow: auto; - background: var(--navBg); - - > .divider { - margin: 16px 0; - border-top: solid 1px var(--divider); - } - - > .item { - position: relative; - display: block; - padding-left: 24px; - font-size: $ui-font-size; - line-height: 3rem; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - width: 100%; - text-align: left; - box-sizing: border-box; - color: var(--navFg); - - > [data-icon] { - width: 32px; - } - - > [data-icon], - > .avatar { - margin-right: $avatar-margin; - } - - > .avatar { - width: $avatar-size; - height: $avatar-size; - vertical-align: middle; - } - - > i { - position: absolute; - top: 0; - left: 20px; - color: var(--navIndicator); - font-size: 8px; - animation: blink 1s infinite; - } - - &:hover { - text-decoration: none; - color: var(--navHoverFg); - } - - &.active { - color: var(--navActive); - } - - &:first-child, &:last-child { - position: sticky; - z-index: 1; - padding-top: 8px; - padding-bottom: 8px; - background: var(--X14); - -webkit-backdrop-filter: blur(8px); - backdrop-filter: blur(8px); - } - - &:first-child { - top: 0; - margin-bottom: 16px; - border-bottom: solid 1px var(--divider); - } - - &:last-child { - bottom: 0; - margin-top: 16px; - border-top: solid 1px var(--divider); - } - } - } - } -} -</style> diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue index 120da63f30..1cd79bac1d 100755 --- a/src/client/components/signin.vue +++ b/src/client/components/signin.vue @@ -1,5 +1,5 @@ <template> -<form class="eppvobhk" :class="{ signing, totpLogin }" @submit.prevent="onSubmit"> +<form class="eppvobhk _monolithic_" :class="{ signing, totpLogin }" @submit.prevent="onSubmit"> <div class="auth _section"> <div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> <div class="normal-signin" v-if="!totpLogin"> @@ -39,16 +39,16 @@ </div> </div> <div class="social _section"> - <a class="_borderButton _vMargin" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><Fa :icon="faTwitter" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Twitter' }) }}</a> - <a class="_borderButton _vMargin" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><Fa :icon="faGithub" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'GitHub' }) }}</a> - <a class="_borderButton _vMargin" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><Fa :icon="faDiscord" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Discord' }) }}</a> + <a class="_borderButton _gap" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><Fa :icon="faTwitter" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Twitter' }) }}</a> + <a class="_borderButton _gap" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><Fa :icon="faGithub" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'GitHub' }) }}</a> + <a class="_borderButton _gap" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><Fa :icon="faDiscord" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Discord' }) }}</a> </div> </form> </template> <script lang="ts"> import { defineComponent } from 'vue'; -import { toUnicode } from 'punycode'; +import { toUnicode } from 'punycode/'; import { faLock, faGavel } from '@fortawesome/free-solid-svg-icons'; import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'; import MkButton from './ui/button.vue'; diff --git a/src/client/components/signup-dialog.vue b/src/client/components/signup-dialog.vue index 072a5ac19f..df1a525055 100644 --- a/src/client/components/signup-dialog.vue +++ b/src/client/components/signup-dialog.vue @@ -7,8 +7,10 @@ > <template #header>{{ $ts.signup }}</template> - <div class="_section"> - <XSignup :auto-set="autoSet" @signup="onSignup"/> + <div class="_monolithic_"> + <div class="_section"> + <XSignup :auto-set="autoSet" @signup="onSignup"/> + </div> </div> </XModalWindow> </template> diff --git a/src/client/components/signup.vue b/src/client/components/signup.vue index 1ce9fc2789..66d01213bc 100644 --- a/src/client/components/signup.vue +++ b/src/client/components/signup.vue @@ -55,7 +55,7 @@ import { defineComponent, defineAsyncComponent } from 'vue'; import { faLock, faExclamationTriangle, faSpinner, faCheck, faKey } from '@fortawesome/free-solid-svg-icons'; const getPasswordStrength = require('syuilo-password-strength'); -import { toUnicode } from 'punycode'; +import { toUnicode } from 'punycode/'; import { host, url } from '@client/config'; import MkButton from './ui/button.vue'; import MkInput from './ui/input.vue'; diff --git a/src/client/components/taskmanager.api-window.vue b/src/client/components/taskmanager.api-window.vue index 9b6c3f16d0..c9b2c43413 100644 --- a/src/client/components/taskmanager.api-window.vue +++ b/src/client/components/taskmanager.api-window.vue @@ -9,7 +9,7 @@ <template #header>Req Viewer</template> <div class="rlkneywz"> - <MkTab v-model:value="tab" style="border-bottom: solid 1px var(--divider);"> + <MkTab v-model:value="tab" style="border-bottom: solid 0.5px var(--divider);"> <option value="req">Request</option> <option value="res">Response</option> </MkTab> diff --git a/src/client/components/taskmanager.vue b/src/client/components/taskmanager.vue index af9033178e..1339e2e352 100644 --- a/src/client/components/taskmanager.vue +++ b/src/client/components/taskmanager.vue @@ -4,7 +4,7 @@ <Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager </template> <div class="qljqmnzj _monospace"> - <MkTab v-model:value="tab" style="border-bottom: solid 1px var(--divider);"> + <MkTab v-model:value="tab" style="border-bottom: solid 0.5px var(--divider);"> <option value="windows">Windows</option> <option value="stream">Stream</option> <option value="streamPool">Stream (Pool)</option> @@ -215,7 +215,7 @@ export default defineComponent({ width: 100%; padding: 8px 16px; box-sizing: border-box; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); font-size: 0.9em; > div { diff --git a/src/client/components/timeline.vue b/src/client/components/timeline.vue index c2ab0b005d..faa3984638 100644 --- a/src/client/components/timeline.vue +++ b/src/client/components/timeline.vue @@ -56,6 +56,7 @@ export default defineComponent({ includeLocalRenotes: this.$store.state.showLocalRenotes }, query: {}, + date: null }; }, @@ -157,7 +158,7 @@ export default defineComponent({ endpoint: endpoint, limit: 10, params: init => ({ - untilDate: init ? undefined : (this.date ? this.date.getTime() : undefined), + untilDate: this.date?.getTime(), ...this.baseQuery, ...this.query }) }; @@ -171,6 +172,11 @@ export default defineComponent({ methods: { focus() { this.$refs.tl.focus(); + }, + + timetravel(date?: Date) { + this.date = date; + this.$refs.tl.reload(); } } }); diff --git a/src/client/components/ui/container.vue b/src/client/components/ui/container.vue index c3353cca89..427421af7d 100644 --- a/src/client/components/ui/container.vue +++ b/src/client/components/ui/container.vue @@ -1,5 +1,5 @@ <template> -<div class="ukygtjoj _panel" :class="{ naked, hideHeader: !showHeader, scrollable, closed: !showBody }" v-size="{ max: [380] }"> +<div class="ukygtjoj _block" :class="{ naked, hideHeader: !showHeader, scrollable, closed: !showBody }" v-size="{ max: [380] }"> <header v-if="showHeader" ref="header"> <div class="title"><slot name="header"></slot></div> <div class="sub"> @@ -116,7 +116,7 @@ export default defineComponent({ .ukygtjoj { position: relative; - overflow: hidden; + overflow: clip; &.naked { background: transparent !important; @@ -133,10 +133,12 @@ export default defineComponent({ } > header { - position: relative; + position: sticky; + top: var(--stickyTop, 0px); + left: 0; color: var(--panelHeaderFg); background: var(--panelHeaderBg); - box-shadow: 0 1px 0 0 var(--panelHeaderDivider); + border-bottom: solid 0.5px var(--panelHeaderDivider); z-index: 2; line-height: 1.4em; @@ -172,7 +174,7 @@ export default defineComponent({ padding: 24px; & + ._content { - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } } } diff --git a/src/client/components/ui/folder.vue b/src/client/components/ui/folder.vue index 1cd67c2521..aee3c0ccaa 100644 --- a/src/client/components/ui/folder.vue +++ b/src/client/components/ui/folder.vue @@ -98,11 +98,12 @@ export default defineComponent({ > header { display: flex; position: relative; - z-index: 2; - // TODO - // position: sticky; - // top: var(--stickyTopOffset); - // backdrop-filter: blur(20px); + z-index: 10; + position: sticky; + top: var(--stickyTop, 0px); + background: var(--X17); + -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(20px); > .title { margin: 0; @@ -137,4 +138,10 @@ export default defineComponent({ } } } + +._flat_ .ssazuxis { + > header { + padding: 0 16px; + } +} </style> diff --git a/src/client/components/ui/info.vue b/src/client/components/ui/info.vue index 12b3dbcfd1..ad1b9ebb58 100644 --- a/src/client/components/ui/info.vue +++ b/src/client/components/ui/info.vue @@ -53,4 +53,8 @@ export default defineComponent({ margin-right: 4px; } } + +._flat_ .fpezltsf { + border-radius: 0; +} </style> diff --git a/src/client/components/ui/modal-window.vue b/src/client/components/ui/modal-window.vue index 2cdf961379..90b803801d 100644 --- a/src/client/components/ui/modal-window.vue +++ b/src/client/components/ui/modal-window.vue @@ -1,6 +1,6 @@ <template> <MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')"> - <div class="ebkgoccj _popup _narrow_" @keydown="onKeydown" :style="{ width: `${width}px`, height: height ? `${height}px` : null }"> + <div class="ebkgoccj _popup _narrow_" @keydown="onKeydown" :style="{ width: `${width}px`, height: scroll ? (height ? `${height}px` : null) : (height ? `min(${height}px, 100%)` : '100%') }"> <div class="header"> <button class="_button" v-if="withOkButton" @click="$emit('close')"><Fa :icon="faTimes"/></button> <span class="title"> @@ -61,6 +61,11 @@ export default defineComponent({ required: false, default: true, }, + scroll: { + type: Boolean, + required: false, + default: true, + }, }, emits: ['click', 'close', 'closed', 'ok'], @@ -94,10 +99,10 @@ export default defineComponent({ flex-direction: column; contain: content; - --section-padding: 24px; + --root-margin: 24px; @media (max-width: 500px) { - --section-padding: 16px; + --root-margin: 16px; } > .header { diff --git a/src/client/components/ui/modal.vue b/src/client/components/ui/modal.vue index db6564bacc..3b11213426 100644 --- a/src/client/components/ui/modal.vue +++ b/src/client/components/ui/modal.vue @@ -1,5 +1,5 @@ <template> -<transition :name="$store.state.animation ? popup ? 'modal-popup' : 'modal' : ''" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered"> +<transition :name="$store.state.animation ? popup ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? popup ? 500 : 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered"> <div v-show="manualShowing != null ? manualShowing : showing" class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div class="bg _modalBg" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div> <div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content"> @@ -183,9 +183,6 @@ export default defineComponent({ <style lang="scss" scoped> .modal-enter-active, .modal-leave-active { - // CSS的には無意味だけどこれが無いとVueが認識しない - transition: opacity 0.3s, transform 0.3s !important; - > .bg { transition: opacity 0.3s !important; } @@ -207,9 +204,6 @@ export default defineComponent({ } .modal-popup-enter-active, .modal-popup-leave-active { - // CSS的には無意味だけどこれが無いとVueが認識しない - transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1) !important; - > .bg { transition: opacity 0.3s !important; } diff --git a/src/client/components/ui/window.vue b/src/client/components/ui/window.vue index 1613644c87..70676cdaf5 100644 --- a/src/client/components/ui/window.vue +++ b/src/client/components/ui/window.vue @@ -395,7 +395,7 @@ export default defineComponent({ position: fixed; top: 0; left: 0; - z-index: 5000; + z-index: 10000; // mk-modalのと同じでなければならない &.front { z-index: 11000; // front指定の時は、mk-modalのよりも大きくなければならない diff --git a/src/client/components/user-info.vue b/src/client/components/user-info.vue index 34ea38c3b4..ac2f9a75a6 100644 --- a/src/client/components/user-info.vue +++ b/src/client/components/user-info.vue @@ -104,7 +104,7 @@ export default defineComponent({ > .description { padding: 16px; font-size: 0.8em; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); > .mfm { display: -webkit-box; @@ -116,7 +116,7 @@ export default defineComponent({ > .status { padding: 10px 16px; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); > div { display: inline-block; diff --git a/src/client/components/user-list.vue b/src/client/components/user-list.vue index 418c4127d9..38d9df63bb 100644 --- a/src/client/components/user-list.vue +++ b/src/client/components/user-list.vue @@ -1,7 +1,7 @@ <template> <MkError v-if="error" @retry="init()"/> -<div v-else class="efvhhmdq"> +<div v-else class="efvhhmdq _isolated"> <div class="no-users" v-if="empty"> <p>{{ $ts.noUsers }}</p> </div> diff --git a/src/client/components/user-select-dialog.vue b/src/client/components/user-select-dialog.vue index e21deea178..05a43402a8 100644 --- a/src/client/components/user-select-dialog.vue +++ b/src/client/components/user-select-dialog.vue @@ -153,7 +153,7 @@ export default defineComponent({ > .user { display: flex; align-items: center; - padding: 8px var(--section-padding); + padding: 8px var(--root-margin); font-size: 14px; &:hover { diff --git a/src/client/components/visibility-picker.vue b/src/client/components/visibility-picker.vue index 0b98d30b9d..caa2b116a6 100644 --- a/src/client/components/visibility-picker.vue +++ b/src/client/components/visibility-picker.vue @@ -97,7 +97,7 @@ export default defineComponent({ > .divider { margin: 8px 0; - border-top: solid 1px var(--divider); + border-top: solid 0.5px var(--divider); } > button { |