Merge branch 'develop' into swn
This commit is contained in:
commit
8899cda211
29 changed files with 484 additions and 218 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -14,17 +14,18 @@
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- アカウント登録にメールアドレスの設定を必須にするオプション
|
- アカウント登録にメールアドレスの設定を必須にするオプション
|
||||||
- クライアント: アニメーションを減らす設定をメニューのアニメーションにも適用するように
|
- クライアント: 全体的なUIのブラッシュアップ
|
||||||
- クライアント: MFM関数構文のサジェストを実装
|
- クライアント: MFM関数構文のサジェストを実装
|
||||||
|
- クライアント: ノート本文を投稿フォーム内でプレビューできるように
|
||||||
- クライアント: 未読の通知のみ表示する機能
|
- クライアント: 未読の通知のみ表示する機能
|
||||||
- クライアント: 通知ページで通知の種類によるフィルタ
|
- クライアント: 通知ページで通知の種類によるフィルタ
|
||||||
|
- クライアント: アニメーションを減らす設定の適用範囲を拡充
|
||||||
- クライアント: 新しいダークテーマを追加
|
- クライアント: 新しいダークテーマを追加
|
||||||
- クライアント: テーマコンパイラに hue と saturate 関数を追加
|
- クライアント: テーマコンパイラに hue と saturate 関数を追加
|
||||||
- ActivityPub: HTML -> MFMの変換を強化
|
- ActivityPub: HTML -> MFMの変換を強化
|
||||||
- API: i/notifications に unreadOnly オプションを追加
|
- API: i/notifications に unreadOnly オプションを追加
|
||||||
- API: ap系のエンドポイントをログイン必須化+レートリミット追加
|
- API: ap系のエンドポイントをログイン必須化+レートリミット追加
|
||||||
- Misskeyのコマンドラインオプションを廃止
|
- MFM: Add tag syntaxes of bold <b></b> and strikethrough <s></s>
|
||||||
- 代わりに環境変数で設定することができます
|
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- Fix createDeleteAccountJob
|
- Fix createDeleteAccountJob
|
||||||
|
@ -33,7 +34,17 @@
|
||||||
- クライアント: ヘッダーにタブが表示されている状態でタイトルをクリックしたときにタブ選択が表示されるのを修正
|
- クライアント: ヘッダーにタブが表示されている状態でタイトルをクリックしたときにタブ選択が表示されるのを修正
|
||||||
- クライアント: ユーザーページのタブが機能していない問題を修正
|
- クライアント: ユーザーページのタブが機能していない問題を修正
|
||||||
- クライアント: ピン留めユーザーの設定項目がない問題を修正
|
- クライアント: ピン留めユーザーの設定項目がない問題を修正
|
||||||
|
- クライアント: Deck UIにおいて、重ねたカラムの片方を畳んだ状態で右に出すと表示が壊れる問題を修正
|
||||||
- API: 管理者およびモデレーターをブロックできてしまう問題を修正
|
- API: 管理者およびモデレーターをブロックできてしまう問題を修正
|
||||||
|
- MFM: Mentions in the link label are parsed as text
|
||||||
|
- MFM: Add a property to the URL node indicating whether it was enclosed in <>
|
||||||
|
- MFM: Disallows < and > in hashtags
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- 保守性やユーザビリティの観点から、Misskeyのコマンドラインオプションが削除されました。
|
||||||
|
- 必要であれば、代わりに環境変数で設定することができます
|
||||||
|
- MFM: パフォーマンス、保守性、構文誤認識抑制の観点から、旧関数構文のサポートが削除されました。
|
||||||
|
- 旧構文(`[foo bar]`)を使用せず、現行の構文(`$[foo bar]`)を使用してください。
|
||||||
|
|
||||||
## 12.91.0 (2021/09/22)
|
## 12.91.0 (2021/09/22)
|
||||||
|
|
||||||
|
|
|
@ -766,6 +766,7 @@ middle: "中"
|
||||||
low: "低"
|
low: "低"
|
||||||
emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
|
emailNotConfiguredWarning: "メールアドレスの設定がされていません。"
|
||||||
ratio: "比率"
|
ratio: "比率"
|
||||||
|
previewNoteText: "本文をプレビュー"
|
||||||
customCss: "カスタムCSS"
|
customCss: "カスタムCSS"
|
||||||
customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。"
|
customCssWarn: "この設定は必ず知識のある方が行ってください。不適切な設定を行うとクライアントが正常に使用できなくなる恐れがあります。"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="fdidabkb" :class="{ slim: narrow, thin }" :style="{ background: bg }" @click="onClick" ref="el">
|
<div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el">
|
||||||
<template v-if="info">
|
<template v-if="info">
|
||||||
<div class="titleContainer" @click="showTabsPopup">
|
<div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle">
|
||||||
<i v-if="info.icon" class="icon" :class="info.icon"></i>
|
<i v-if="info.icon" class="icon" :class="info.icon"></i>
|
||||||
<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
|
<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs" v-if="!narrow">
|
<div class="tabs" v-if="!narrow || hideTitle">
|
||||||
<button class="tab _button" v-for="tab in info.tabs" :class="{ active: tab.active }" @click="tab.onClick" v-tooltip="tab.title">
|
<button class="tab _button" v-for="tab in info.tabs" :class="{ active: tab.active }" @click="tab.onClick" v-tooltip="tab.title">
|
||||||
<i v-if="tab.icon" class="icon" :class="tab.icon"></i>
|
<i v-if="tab.icon" class="icon" :class="tab.icon"></i>
|
||||||
<span v-if="!tab.iconOnly" class="title">{{ tab.title }}</span>
|
<span v-if="!tab.iconOnly" class="title">{{ tab.title }}</span>
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref } from 'vue';
|
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, inject } from 'vue';
|
||||||
import * as tinycolor from 'tinycolor2';
|
import * as tinycolor from 'tinycolor2';
|
||||||
import { popupMenu } from '@client/os';
|
import { popupMenu } from '@client/os';
|
||||||
import { url } from '@client/config';
|
import { url } from '@client/config';
|
||||||
|
@ -182,6 +182,8 @@ export default defineComponent({
|
||||||
showTabsPopup,
|
showTabsPopup,
|
||||||
preventDrag,
|
preventDrag,
|
||||||
onClick,
|
onClick,
|
||||||
|
hideTitle: inject('shouldOmitHeaderTitle', false),
|
||||||
|
thin_: props.thin || inject('shouldHeaderThin', false)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -207,12 +209,16 @@ export default defineComponent({
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
> .titleContainer {
|
> .titleContainer {
|
||||||
|
flex: 1;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
margin-left: var(--height);
|
||||||
|
|
||||||
> .buttons {
|
> *:first-child {
|
||||||
&.right {
|
margin-left: auto;
|
||||||
margin-left: 0;
|
}
|
||||||
|
|
||||||
|
> *:last-child {
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
70
src/client/components/global/spacer.vue
Normal file
70
src/client/components/global/spacer.vue
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<template>
|
||||||
|
<div ref="root" :class="$style.root" :style="{ padding: margin + 'px' }">
|
||||||
|
<div ref="content" :class="$style.content">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
contentMax: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, context) {
|
||||||
|
let ro: ResizeObserver;
|
||||||
|
const root = ref<HTMLElement>(null);
|
||||||
|
const content = ref<HTMLElement>(null);
|
||||||
|
const margin = ref(0);
|
||||||
|
const adjust = (rect: { width: number; height: number; }) => {
|
||||||
|
if (rect.width > (props.contentMax || 500)) {
|
||||||
|
margin.value = 32;
|
||||||
|
} else {
|
||||||
|
margin.value = 12;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
ro = new ResizeObserver((entries) => {
|
||||||
|
adjust({
|
||||||
|
width: entries[0].borderBoxSize[0].inlineSize,
|
||||||
|
height: entries[0].borderBoxSize[0].blockSize,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ro.observe(root.value);
|
||||||
|
|
||||||
|
if (props.contentMax) {
|
||||||
|
content.value.style.maxWidth = `${props.contentMax}px`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
ro.disconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
root,
|
||||||
|
content,
|
||||||
|
margin,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -14,6 +14,7 @@ import loading from './global/loading.vue';
|
||||||
import error from './global/error.vue';
|
import error from './global/error.vue';
|
||||||
import ad from './global/ad.vue';
|
import ad from './global/ad.vue';
|
||||||
import header from './global/header.vue';
|
import header from './global/header.vue';
|
||||||
|
import spacer from './global/spacer.vue';
|
||||||
|
|
||||||
export default function(app: App) {
|
export default function(app: App) {
|
||||||
app.component('I18n', i18n);
|
app.component('I18n', i18n);
|
||||||
|
@ -30,4 +31,5 @@ export default function(app: App) {
|
||||||
app.component('MkError', error);
|
app.component('MkError', error);
|
||||||
app.component('MkAd', ad);
|
app.component('MkAd', ad);
|
||||||
app.component('MkHeader', header);
|
app.component('MkHeader', header);
|
||||||
|
app.component('MkSpacer', spacer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
|
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
|
||||||
<div class="hrmcaedk _window _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
|
<div class="hrmcaedk _window _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
|
||||||
<div class="header" @contextmenu="onContextmenu">
|
<div class="header" @contextmenu="onContextmenu">
|
||||||
<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
|
<button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button>
|
||||||
<span v-else style="display: inline-block; width: 20px"></span>
|
<span v-else style="display: inline-block; width: 20px"></span>
|
||||||
<span v-if="pageInfo" class="title">
|
<span v-if="pageInfo" class="title">
|
||||||
<i v-if="pageInfo.icon" class="icon" :class="pageInfo.icon"></i>
|
<i v-if="pageInfo.icon" class="icon" :class="pageInfo.icon"></i>
|
||||||
|
@ -44,7 +44,8 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
navHook: (path) => {
|
navHook: (path) => {
|
||||||
this.navigate(path);
|
this.navigate(path);
|
||||||
}
|
},
|
||||||
|
shouldHeaderThin: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
||||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="true" class="url-preview"/>
|
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="true" class="url-preview"/>
|
||||||
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
|
<div class="renote" v-if="appearNote.renote"><XNoteSimple :note="appearNote.renote"/></div>
|
||||||
</div>
|
</div>
|
||||||
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
|
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +132,7 @@ import * as mfm from 'mfm-js';
|
||||||
import { sum } from '../../prelude/array';
|
import { sum } from '../../prelude/array';
|
||||||
import XSub from './note.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import XNoteHeader from './note-header.vue';
|
import XNoteHeader from './note-header.vue';
|
||||||
import XNotePreview from './note-preview.vue';
|
import XNoteSimple from './note-simple.vue';
|
||||||
import XReactionsViewer from './reactions-viewer.vue';
|
import XReactionsViewer from './reactions-viewer.vue';
|
||||||
import XMediaList from './media-list.vue';
|
import XMediaList from './media-list.vue';
|
||||||
import XCwButton from './cw-button.vue';
|
import XCwButton from './cw-button.vue';
|
||||||
|
@ -153,7 +153,7 @@ export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XSub,
|
XSub,
|
||||||
XNoteHeader,
|
XNoteHeader,
|
||||||
XNotePreview,
|
XNoteSimple,
|
||||||
XReactionsViewer,
|
XReactionsViewer,
|
||||||
XMediaList,
|
XMediaList,
|
||||||
XCwButton,
|
XCwButton,
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="yohlumlk" v-size="{ min: [350, 500] }">
|
<div class="fefdfafb" v-size="{ min: [350, 500] }">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar class="avatar" :user="$i"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<XNoteHeader class="header" :note="note" :mini="true"/>
|
<div class="header">
|
||||||
|
<MkUserName :user="$i"/>
|
||||||
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="note.cw != null" class="cw">
|
<div class="content">
|
||||||
<span class="text" v-if="note.cw != ''">{{ note.cw }}</span>
|
<Mfm :text="text" :author="$i" :i="$i"/>
|
||||||
<XCwButton v-model="showContent" :note="note"/>
|
|
||||||
</p>
|
|
||||||
<div class="content" v-show="note.cw == null || showContent">
|
|
||||||
<XSubNote-content class="text" :note="note"/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,35 +16,22 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import XNoteHeader from './note-header.vue';
|
|
||||||
import XSubNoteContent from './sub-note-content.vue';
|
|
||||||
import XCwButton from './cw-button.vue';
|
|
||||||
import * as os from '@client/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XNoteHeader,
|
|
||||||
XSubNoteContent,
|
|
||||||
XCwButton,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
note: {
|
text: {
|
||||||
type: Object,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
showContent: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.yohlumlk {
|
.fefdfafb {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
113
src/client/components/note-simple.vue
Normal file
113
src/client/components/note-simple.vue
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
<template>
|
||||||
|
<div class="yohlumlk" v-size="{ min: [350, 500] }">
|
||||||
|
<MkAvatar class="avatar" :user="note.user"/>
|
||||||
|
<div class="main">
|
||||||
|
<XNoteHeader class="header" :note="note" :mini="true"/>
|
||||||
|
<div class="body">
|
||||||
|
<p v-if="note.cw != null" class="cw">
|
||||||
|
<span class="text" v-if="note.cw != ''">{{ note.cw }}</span>
|
||||||
|
<XCwButton v-model="showContent" :note="note"/>
|
||||||
|
</p>
|
||||||
|
<div class="content" v-show="note.cw == null || showContent">
|
||||||
|
<XSubNote-content class="text" :note="note"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import XNoteHeader from './note-header.vue';
|
||||||
|
import XSubNoteContent from './sub-note-content.vue';
|
||||||
|
import XCwButton from './cw-button.vue';
|
||||||
|
import * as os from '@client/os';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XNoteHeader,
|
||||||
|
XSubNoteContent,
|
||||||
|
XCwButton,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
note: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showContent: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.yohlumlk {
|
||||||
|
display: flex;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: clip;
|
||||||
|
font-size: 0.95em;
|
||||||
|
|
||||||
|
&.min-width_350px {
|
||||||
|
> .avatar {
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.min-width_500px {
|
||||||
|
> .avatar {
|
||||||
|
margin: 0 12px 0 0;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: block;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
> .header {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .body {
|
||||||
|
|
||||||
|
> .cw {
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
|
||||||
|
> .text {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .content {
|
||||||
|
> .text {
|
||||||
|
cursor: default;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -64,7 +64,7 @@
|
||||||
</div>
|
</div>
|
||||||
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
||||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="false" class="url-preview"/>
|
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="false" class="url-preview"/>
|
||||||
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
|
<div class="renote" v-if="appearNote.renote"><XNoteSimple :note="appearNote.renote"/></div>
|
||||||
<button v-if="collapsed" class="fade _button" @click="collapsed = false">
|
<button v-if="collapsed" class="fade _button" @click="collapsed = false">
|
||||||
<span>{{ $ts.showMore }}</span>
|
<span>{{ $ts.showMore }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -114,7 +114,7 @@ import * as mfm from 'mfm-js';
|
||||||
import { sum } from '../../prelude/array';
|
import { sum } from '../../prelude/array';
|
||||||
import XSub from './note.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import XNoteHeader from './note-header.vue';
|
import XNoteHeader from './note-header.vue';
|
||||||
import XNotePreview from './note-preview.vue';
|
import XNoteSimple from './note-simple.vue';
|
||||||
import XReactionsViewer from './reactions-viewer.vue';
|
import XReactionsViewer from './reactions-viewer.vue';
|
||||||
import XMediaList from './media-list.vue';
|
import XMediaList from './media-list.vue';
|
||||||
import XCwButton from './cw-button.vue';
|
import XCwButton from './cw-button.vue';
|
||||||
|
@ -134,7 +134,7 @@ export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XSub,
|
XSub,
|
||||||
XNoteHeader,
|
XNoteHeader,
|
||||||
XNotePreview,
|
XNoteSimple,
|
||||||
XReactionsViewer,
|
XReactionsViewer,
|
||||||
XMediaList,
|
XMediaList,
|
||||||
XCwButton,
|
XCwButton,
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #headerLeft>
|
<template #headerLeft>
|
||||||
<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
|
<button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button>
|
||||||
</template>
|
</template>
|
||||||
<div class="yrolvcoq _flat_">
|
<div class="yrolvcoq _flat_">
|
||||||
<component :is="component" v-bind="props" :ref="changePage"/>
|
<component :is="component" v-bind="props" :ref="changePage"/>
|
||||||
|
@ -46,7 +46,8 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
navHook: (path) => {
|
navHook: (path) => {
|
||||||
this.navigate(path);
|
this.navigate(path);
|
||||||
}
|
},
|
||||||
|
shouldHeaderThin: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="gafaadew" :class="{ modal, _popup: modal }"
|
<div class="gafaadew" :class="{ modal, _popup: modal }"
|
||||||
v-size="{ max: [500] }"
|
v-size="{ max: [310, 500] }"
|
||||||
@dragover.stop="onDragover"
|
@dragover.stop="onDragover"
|
||||||
@dragenter="onDragenter"
|
@dragenter="onDragenter"
|
||||||
@dragleave="onDragleave"
|
@dragleave="onDragleave"
|
||||||
|
@ -17,12 +17,13 @@
|
||||||
<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
|
<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
|
||||||
<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
|
<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button class="submit _buttonPrimary" :disabled="!canPost" @click="post" data-cy-open-post-form-submit>{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
|
<button class="_button preview" @click="showPreview = !showPreview" :class="{ active: showPreview }" v-tooltip="$ts.previewNoteText"><i class="fas fa-file-code"></i></button>
|
||||||
|
<button class="submit _buttonGradate" :disabled="!canPost" @click="post" data-cy-open-post-form-submit>{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="form" :class="{ fixed }">
|
<div class="form" :class="{ fixed }">
|
||||||
<XNotePreview class="preview" v-if="reply" :note="reply"/>
|
<XNoteSimple class="preview" v-if="reply" :note="reply"/>
|
||||||
<XNotePreview class="preview" v-if="renote" :note="renote"/>
|
<XNoteSimple class="preview" v-if="renote" :note="renote"/>
|
||||||
<div class="with-quote" v-if="quoteId"><i class="fas fa-quote-left"></i> {{ $ts.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div>
|
<div class="with-quote" v-if="quoteId"><i class="fas fa-quote-left"></i> {{ $ts.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div>
|
||||||
<div v-if="visibility === 'specified'" class="to-specified">
|
<div v-if="visibility === 'specified'" class="to-specified">
|
||||||
<span style="margin-right: 8px;">{{ $ts.recipient }}</span>
|
<span style="margin-right: 8px;">{{ $ts.recipient }}</span>
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
|
<input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags">
|
||||||
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
|
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
|
||||||
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
|
<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
|
||||||
|
<XNotePreview class="preview" v-if="showPreview" :text="text"/>
|
||||||
<footer>
|
<footer>
|
||||||
<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><i class="fas fa-photo-video"></i></button>
|
<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><i class="fas fa-photo-video"></i></button>
|
||||||
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
|
<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
|
||||||
|
@ -61,6 +63,7 @@ import { defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
import { toASCII } from 'punycode/';
|
import { toASCII } from 'punycode/';
|
||||||
|
import XNoteSimple from './note-simple.vue';
|
||||||
import XNotePreview from './note-preview.vue';
|
import XNotePreview from './note-preview.vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import { host, url } from '@client/config';
|
import { host, url } from '@client/config';
|
||||||
|
@ -80,6 +83,7 @@ import { defaultStore } from '@client/store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
XNoteSimple,
|
||||||
XNotePreview,
|
XNotePreview,
|
||||||
XPostFormAttaches: defineAsyncComponent(() => import('./post-form-attaches.vue')),
|
XPostFormAttaches: defineAsyncComponent(() => import('./post-form-attaches.vue')),
|
||||||
XPollEditor: defineAsyncComponent(() => import('./poll-editor.vue')),
|
XPollEditor: defineAsyncComponent(() => import('./poll-editor.vue')),
|
||||||
|
@ -160,6 +164,7 @@ export default defineComponent({
|
||||||
files: [],
|
files: [],
|
||||||
poll: null,
|
poll: null,
|
||||||
useCw: false,
|
useCw: false,
|
||||||
|
showPreview: false,
|
||||||
cw: null,
|
cw: null,
|
||||||
localOnly: this.$store.state.rememberNoteVisibility ? this.$store.state.localOnly : this.$store.state.defaultNoteLocalOnly,
|
localOnly: this.$store.state.rememberNoteVisibility ? this.$store.state.localOnly : this.$store.state.defaultNoteLocalOnly,
|
||||||
visibility: (this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility) as typeof noteVisibilities[number],
|
visibility: (this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility) as typeof noteVisibilities[number],
|
||||||
|
@ -743,7 +748,7 @@ export default defineComponent({
|
||||||
> .visibility {
|
> .visibility {
|
||||||
height: 34px;
|
height: 34px;
|
||||||
width: 34px;
|
width: 34px;
|
||||||
margin: 0 8px;
|
margin: 0 0 0 8px;
|
||||||
|
|
||||||
& + .localOnly {
|
& + .localOnly {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
|
@ -755,6 +760,24 @@ export default defineComponent({
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .preview {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 8px 0 0;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--X5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .submit {
|
> .submit {
|
||||||
margin: 16px 16px 16px 0;
|
margin: 16px 16px 16px 0;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
|
@ -762,6 +785,7 @@ export default defineComponent({
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
@ -940,5 +964,17 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.max-width_310px {
|
||||||
|
> .form {
|
||||||
|
> footer {
|
||||||
|
> button {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -188,11 +188,11 @@ export default defineComponent({
|
||||||
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
||||||
|
|
||||||
&:not(:disabled):hover {
|
&:not(:disabled):hover {
|
||||||
background: var(--X8);
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:disabled):active {
|
&:not(:disabled):active {
|
||||||
background: var(--X8);
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default defineComponent({
|
||||||
> .item {
|
> .item {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 8px 16px;
|
padding: 8px 18px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -170,10 +170,9 @@ export default defineComponent({
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
//width: calc(100% - 16px);
|
width: calc(100% - 16px);
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
//border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
|
@ -243,12 +242,12 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
> i {
|
> i {
|
||||||
margin-right: 4px;
|
margin-right: 5px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .avatar {
|
> .avatar {
|
||||||
margin-right: 4px;
|
margin-right: 5px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,8 +65,8 @@ export default defineComponent({
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 10px 16px 10px 14px;
|
padding: 10px 16px 10px 8px;
|
||||||
border-radius: 999px;
|
border-radius: 9px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
|
|
@ -23,12 +23,14 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
VanillaTilt.init(this.$el, {
|
if (this.$store.animation) {
|
||||||
reverse: true,
|
VanillaTilt.init(this.$el, {
|
||||||
gyroscope: false,
|
reverse: true,
|
||||||
scale: 1.1,
|
gyroscope: false,
|
||||||
speed: 500,
|
scale: 1.1,
|
||||||
});
|
speed: 500,
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -2,77 +2,79 @@
|
||||||
<div>
|
<div>
|
||||||
<MkHeader :info="header"/>
|
<MkHeader :info="header"/>
|
||||||
|
|
||||||
<div class="lznhrdub _root">
|
<MkSpacer :content-max="1200">
|
||||||
<div v-if="tab === 'local'">
|
<div class="lznhrdub">
|
||||||
<div class="localfedi7 _block _isolated" v-if="meta && stats && tag == null" :style="{ backgroundImage: meta.bannerUrl ? `url(${meta.bannerUrl})` : null }">
|
<div v-if="tab === 'local'">
|
||||||
<header><span>{{ $t('explore', { host: meta.name || 'Misskey' }) }}</span></header>
|
<div class="localfedi7 _block _isolated" v-if="meta && stats && tag == null" :style="{ backgroundImage: meta.bannerUrl ? `url(${meta.bannerUrl})` : null }">
|
||||||
<div><span>{{ $t('exploreUsersCount', { count: num(stats.originalUsersCount) }) }}</span></div>
|
<header><span>{{ $t('explore', { host: meta.name || 'Misskey' }) }}</span></header>
|
||||||
</div>
|
<div><span>{{ $t('exploreUsersCount', { count: num(stats.originalUsersCount) }) }}</span></div>
|
||||||
|
|
||||||
<template v-if="tag == null">
|
|
||||||
<MkFolder class="_gap" persist-key="explore-pinned-users">
|
|
||||||
<template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template>
|
|
||||||
<XUserList :pagination="pinnedUsers"/>
|
|
||||||
</MkFolder>
|
|
||||||
<MkFolder class="_gap" persist-key="explore-popular-users">
|
|
||||||
<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
|
|
||||||
<XUserList :pagination="popularUsers"/>
|
|
||||||
</MkFolder>
|
|
||||||
<MkFolder class="_gap" persist-key="explore-recently-updated-users">
|
|
||||||
<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
|
|
||||||
<XUserList :pagination="recentlyUpdatedUsers"/>
|
|
||||||
</MkFolder>
|
|
||||||
<MkFolder class="_gap" persist-key="explore-recently-registered-users">
|
|
||||||
<template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template>
|
|
||||||
<XUserList :pagination="recentlyRegisteredUsers"/>
|
|
||||||
</MkFolder>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="tab === 'remote'">
|
|
||||||
<div class="localfedi7 _block _isolated" v-if="tag == null" :style="{ backgroundImage: `url(/static-assets/client/fedi.jpg)` }">
|
|
||||||
<header><span>{{ $ts.exploreFediverse }}</span></header>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<MkFolder :foldable="true" :expanded="false" ref="tags" class="_gap">
|
|
||||||
<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template>
|
|
||||||
|
|
||||||
<div class="vxjfqztj">
|
|
||||||
<MkA v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</MkA>
|
|
||||||
<MkA v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</MkA>
|
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="tag != null" :key="`${tag}`" class="_gap">
|
<template v-if="tag == null">
|
||||||
<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template>
|
<MkFolder class="_gap" persist-key="explore-pinned-users">
|
||||||
<XUserList :pagination="tagUsers"/>
|
<template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template>
|
||||||
</MkFolder>
|
<XUserList :pagination="pinnedUsers"/>
|
||||||
|
</MkFolder>
|
||||||
<template v-if="tag == null">
|
<MkFolder class="_gap" persist-key="explore-popular-users">
|
||||||
<MkFolder class="_gap">
|
<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
|
||||||
<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
|
<XUserList :pagination="popularUsers"/>
|
||||||
<XUserList :pagination="popularUsersF"/>
|
</MkFolder>
|
||||||
</MkFolder>
|
<MkFolder class="_gap" persist-key="explore-recently-updated-users">
|
||||||
<MkFolder class="_gap">
|
<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
|
||||||
<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
|
<XUserList :pagination="recentlyUpdatedUsers"/>
|
||||||
<XUserList :pagination="recentlyUpdatedUsersF"/>
|
</MkFolder>
|
||||||
</MkFolder>
|
<MkFolder class="_gap" persist-key="explore-recently-registered-users">
|
||||||
<MkFolder class="_gap">
|
<template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template>
|
||||||
<template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template>
|
<XUserList :pagination="recentlyRegisteredUsers"/>
|
||||||
<XUserList :pagination="recentlyRegisteredUsersF"/>
|
</MkFolder>
|
||||||
</MkFolder>
|
</template>
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="tab === 'search'">
|
|
||||||
<div class="_isolated">
|
|
||||||
<MkInput v-model="query" :debounce="true" type="search">
|
|
||||||
<template #prefix><i class="fas fa-search"></i></template>
|
|
||||||
<template #label>{{ $ts.searchUser }}</template>
|
|
||||||
</MkInput>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="tab === 'remote'">
|
||||||
|
<div class="localfedi7 _block _isolated" v-if="tag == null" :style="{ backgroundImage: `url(/static-assets/client/fedi.jpg)` }">
|
||||||
|
<header><span>{{ $ts.exploreFediverse }}</span></header>
|
||||||
|
</div>
|
||||||
|
|
||||||
<XUserList v-if="query" class="_gap" :pagination="searchPagination" ref="search"/>
|
<MkFolder :foldable="true" :expanded="false" ref="tags" class="_gap">
|
||||||
|
<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template>
|
||||||
|
|
||||||
|
<div class="vxjfqztj">
|
||||||
|
<MkA v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</MkA>
|
||||||
|
<MkA v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</MkA>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkFolder v-if="tag != null" :key="`${tag}`" class="_gap">
|
||||||
|
<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template>
|
||||||
|
<XUserList :pagination="tagUsers"/>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
|
<template v-if="tag == null">
|
||||||
|
<MkFolder class="_gap">
|
||||||
|
<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
|
||||||
|
<XUserList :pagination="popularUsersF"/>
|
||||||
|
</MkFolder>
|
||||||
|
<MkFolder class="_gap">
|
||||||
|
<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
|
||||||
|
<XUserList :pagination="recentlyUpdatedUsersF"/>
|
||||||
|
</MkFolder>
|
||||||
|
<MkFolder class="_gap">
|
||||||
|
<template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template>
|
||||||
|
<XUserList :pagination="recentlyRegisteredUsersF"/>
|
||||||
|
</MkFolder>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="tab === 'search'">
|
||||||
|
<div class="_isolated">
|
||||||
|
<MkInput v-model="query" :debounce="true" type="search">
|
||||||
|
<template #prefix><i class="fas fa-search"></i></template>
|
||||||
|
<template #label>{{ $ts.searchUser }}</template>
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<XUserList v-if="query" class="_gap" :pagination="searchPagination" ref="search"/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</MkSpacer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -214,12 +216,6 @@ export default defineComponent({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.lznhrdub {
|
|
||||||
max-width: 1400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.localfedi7 {
|
.localfedi7 {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<MkHeader :info="header"/>
|
<MkHeader :info="header"/>
|
||||||
<div class="clupoqwt" v-size="{ min: [800] }">
|
<MkSpacer :content-max="800">
|
||||||
<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
|
<div class="clupoqwt">
|
||||||
</div>
|
<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
|
||||||
|
</div>
|
||||||
|
</MkSpacer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -90,14 +92,5 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.clupoqwt {
|
.clupoqwt {
|
||||||
&.min-width_800px {
|
|
||||||
background: var(--bg);
|
|
||||||
padding: 32px 0;
|
|
||||||
|
|
||||||
> .notifications {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,61 +1,65 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="_root">
|
<div>
|
||||||
<transition name="fade" mode="out-in">
|
<MkHeader :info="header"/>
|
||||||
<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
|
|
||||||
<div class="_block main">
|
<div class="_root">
|
||||||
<!--
|
<transition name="fade" mode="out-in">
|
||||||
<div class="header">
|
<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
|
||||||
<h1>{{ page.title }}</h1>
|
<div class="_block main">
|
||||||
</div>
|
<!--
|
||||||
-->
|
<div class="header">
|
||||||
<div class="banner">
|
<h1>{{ page.title }}</h1>
|
||||||
<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<XPage :page="page"/>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<div class="like">
|
|
||||||
<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
|
|
||||||
<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="other">
|
-->
|
||||||
<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
|
<div class="banner">
|
||||||
<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
|
<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<XPage :page="page"/>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<div class="like">
|
||||||
|
<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
|
||||||
|
<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
|
||||||
|
</div>
|
||||||
|
<div class="other">
|
||||||
|
<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
|
||||||
|
<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user">
|
||||||
|
<MkAvatar :user="page.user" class="avatar"/>
|
||||||
|
<div class="name">
|
||||||
|
<MkUserName :user="page.user" style="display: block;"/>
|
||||||
|
<MkAcct :user="page.user"/>
|
||||||
|
</div>
|
||||||
|
<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
|
||||||
|
</div>
|
||||||
|
<div class="links">
|
||||||
|
<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA>
|
||||||
|
<template v-if="$i && $i.id === page.userId">
|
||||||
|
<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA>
|
||||||
|
<button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
|
||||||
|
<button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user">
|
<div class="footer">
|
||||||
<MkAvatar :user="page.user" class="avatar"/>
|
<div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
|
||||||
<div class="name">
|
<div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
|
||||||
<MkUserName :user="page.user" style="display: block;"/>
|
|
||||||
<MkAcct :user="page.user"/>
|
|
||||||
</div>
|
|
||||||
<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
|
|
||||||
</div>
|
|
||||||
<div class="links">
|
|
||||||
<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA>
|
|
||||||
<template v-if="$i && $i.id === page.userId">
|
|
||||||
<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA>
|
|
||||||
<button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
|
|
||||||
<button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button>
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
|
<MkAd :prefer="['horizontal', 'horizontal-big']"/>
|
||||||
|
<MkContainer :max-height="300" :foldable="true" class="other">
|
||||||
|
<template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template>
|
||||||
|
<MkPagination :pagination="otherPostsPagination" #default="{items}">
|
||||||
|
<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
|
||||||
|
</MkPagination>
|
||||||
|
</MkContainer>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<MkError v-else-if="error" @retry="fetch()"/>
|
||||||
<div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
|
<MkLoading v-else/>
|
||||||
<div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
<MkAd :prefer="['horizontal', 'horizontal-big']"/>
|
|
||||||
<MkContainer :max-height="300" :foldable="true" class="other">
|
|
||||||
<template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template>
|
|
||||||
<MkPagination :pagination="otherPostsPagination" #default="{items}">
|
|
||||||
<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
|
|
||||||
</MkPagination>
|
|
||||||
</MkContainer>
|
|
||||||
</div>
|
|
||||||
<MkError v-else-if="error" @retry="fetch()"/>
|
|
||||||
<MkLoading v-else/>
|
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -97,6 +101,10 @@ export default defineComponent({
|
||||||
[symbols.PAGE_INFO]: computed(() => this.page ? {
|
[symbols.PAGE_INFO]: computed(() => this.page ? {
|
||||||
title: computed(() => this.page.title || this.page.name),
|
title: computed(() => this.page.title || this.page.name),
|
||||||
avatar: this.page.user,
|
avatar: this.page.user,
|
||||||
|
} : null),
|
||||||
|
header: computed(() => this.page ? {
|
||||||
|
title: computed(() => this.page.title || this.page.name),
|
||||||
|
avatar: this.page.user,
|
||||||
path: `/@${this.page.user.username}/pages/${this.page.name}`,
|
path: `/@${this.page.user.username}/pages/${this.page.name}`,
|
||||||
share: {
|
share: {
|
||||||
title: this.page.title || this.page.name,
|
title: this.page.title || this.page.name,
|
||||||
|
|
|
@ -271,6 +271,12 @@ export default defineComponent({
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.vvcocwet {
|
.vvcocwet {
|
||||||
> .nav {
|
> .nav {
|
||||||
|
> .title {
|
||||||
|
margin: 16px;
|
||||||
|
font-size: 1.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
> .info {
|
> .info {
|
||||||
margin: 0 16px;
|
margin: 0 16px;
|
||||||
}
|
}
|
||||||
|
@ -295,6 +301,10 @@ export default defineComponent({
|
||||||
width: 32%;
|
width: 32%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
margin: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
> .main {
|
||||||
|
|
|
@ -215,6 +215,10 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .post-form {
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
> .tl {
|
> .tl {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
|
@ -202,6 +202,20 @@ hr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
._buttonGradate {
|
||||||
|
@extend ._buttonPrimary;
|
||||||
|
color: var(--fgOnAccent);
|
||||||
|
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):active {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
._help {
|
._help {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
cursor: help
|
cursor: help
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
renote: '@accent',
|
renote: '@accent',
|
||||||
mention: 'rgb(212, 153, 76)',
|
mention: 'rgb(212, 153, 76)',
|
||||||
mentionMe: 'rgb(212, 210, 76)',
|
mentionMe: 'rgb(212, 210, 76)',
|
||||||
hashtag: 'rgb(76, 212, 180)',
|
hashtag: '#5bcbb0',
|
||||||
link: '@accent',
|
link: '@accent',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
</div>
|
</div>
|
||||||
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
||||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="false" class="url-preview"/>
|
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="false" class="url-preview"/>
|
||||||
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
|
<div class="renote" v-if="appearNote.renote"><XNoteSimple :note="appearNote.renote"/></div>
|
||||||
<button v-if="collapsed" class="fade _button" @click="collapsed = false">
|
<button v-if="collapsed" class="fade _button" @click="collapsed = false">
|
||||||
<span>{{ $ts.showMore }}</span>
|
<span>{{ $ts.showMore }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
@ -106,7 +106,7 @@ import * as mfm from 'mfm-js';
|
||||||
import { sum } from '../../../prelude/array';
|
import { sum } from '../../../prelude/array';
|
||||||
import XSub from './note.sub.vue';
|
import XSub from './note.sub.vue';
|
||||||
import XNoteHeader from './note-header.vue';
|
import XNoteHeader from './note-header.vue';
|
||||||
import XNotePreview from './note-preview.vue';
|
import XNoteSimple from './note-preview.vue';
|
||||||
import XReactionsViewer from '@client/components/reactions-viewer.vue';
|
import XReactionsViewer from '@client/components/reactions-viewer.vue';
|
||||||
import XMediaList from '@client/components/media-list.vue';
|
import XMediaList from '@client/components/media-list.vue';
|
||||||
import XCwButton from '@client/components/cw-button.vue';
|
import XCwButton from '@client/components/cw-button.vue';
|
||||||
|
@ -126,7 +126,7 @@ export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XSub,
|
XSub,
|
||||||
XNoteHeader,
|
XNoteHeader,
|
||||||
XNotePreview,
|
XNoteSimple,
|
||||||
XReactionsViewer,
|
XReactionsViewer,
|
||||||
XMediaList,
|
XMediaList,
|
||||||
XCwButton,
|
XCwButton,
|
||||||
|
|
|
@ -37,6 +37,11 @@ import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownCo
|
||||||
import { deckStore } from './deck-store';
|
import { deckStore } from './deck-store';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
provide: {
|
||||||
|
shouldHeaderThin: true,
|
||||||
|
shouldOmitHeaderTitle: true,
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
column: {
|
column: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -267,6 +272,7 @@ export default defineComponent({
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: content;
|
contain: content;
|
||||||
|
box-shadow: 0 0 8px 0 var(--shadow);
|
||||||
|
|
||||||
&.draghover {
|
&.draghover {
|
||||||
box-shadow: 0 0 0 2px var(--focus);
|
box-shadow: 0 0 0 2px var(--focus);
|
||||||
|
@ -320,15 +326,6 @@ export default defineComponent({
|
||||||
|
|
||||||
&.paged {
|
&.paged {
|
||||||
background: var(--bg) !important;
|
background: var(--bg) !important;
|
||||||
|
|
||||||
> header {
|
|
||||||
background: transparent;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
> button {
|
|
||||||
color: var(--fg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> header {
|
> header {
|
||||||
|
@ -365,7 +362,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
> .toggleActive,
|
> .toggleActive,
|
||||||
> .action > *,
|
> .action > ::v-deep(*),
|
||||||
> .menu {
|
> .menu {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
width: var(--deckColumnHeaderHeight);
|
width: var(--deckColumnHeaderHeight);
|
||||||
|
|
|
@ -219,10 +219,20 @@ export function stackLeftColumn(id: Column['id']) {
|
||||||
export function popRightColumn(id: Column['id']) {
|
export function popRightColumn(id: Column['id']) {
|
||||||
let layout = copy(deckStore.state.layout);
|
let layout = copy(deckStore.state.layout);
|
||||||
const i = deckStore.state.layout.findIndex(ids => ids.includes(id));
|
const i = deckStore.state.layout.findIndex(ids => ids.includes(id));
|
||||||
|
const affected = layout[i];
|
||||||
layout = layout.map(ids => ids.filter(_id => _id !== id));
|
layout = layout.map(ids => ids.filter(_id => _id !== id));
|
||||||
layout.splice(i + 1, 0, [id]);
|
layout.splice(i + 1, 0, [id]);
|
||||||
layout = layout.filter(ids => ids.length > 0);
|
layout = layout.filter(ids => ids.length > 0);
|
||||||
deckStore.set('layout', layout);
|
deckStore.set('layout', layout);
|
||||||
|
|
||||||
|
const columns = copy(deckStore.state.columns);
|
||||||
|
for (const column of columns) {
|
||||||
|
if (affected.includes(column.id)) {
|
||||||
|
column.active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deckStore.set('columns', columns);
|
||||||
|
|
||||||
saveDeck();
|
saveDeck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked">
|
<XColumn v-if="deckStore.state.alwaysShowMainColumn || $route.name !== 'index'" :column="column" :is-stacked="isStacked">
|
||||||
<template #header>
|
<template #header>
|
||||||
<template v-if="pageInfo">
|
<template v-if="pageInfo">
|
||||||
|
<i :class="pageInfo.icon"></i>
|
||||||
{{ pageInfo.title }}
|
{{ pageInfo.title }}
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -80,6 +80,12 @@ export default defineComponent({
|
||||||
XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')),
|
XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
shouldHeaderThin: this.showMenuOnTop,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pageInfo: null,
|
pageInfo: null,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"short_name": "Misskey",
|
"short_name": "Misskey",
|
||||||
"name": "Misskey",
|
"name": "Misskey",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "minimal-ui",
|
||||||
"background_color": "#313a42",
|
"background_color": "#313a42",
|
||||||
"theme_color": "#86b300",
|
"theme_color": "#86b300",
|
||||||
"icons": [
|
"icons": [
|
||||||
|
|
Loading…
Reference in a new issue