commit
3f6691bd5e
@ -7,6 +7,14 @@
|
|||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## 12.x.x (unreleased)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
- クライアント: ノートプレビューの精度を改善
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
|
||||||
|
|
||||||
## 12.100.2 (2021/12/18)
|
## 12.100.2 (2021/12/18)
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
@ -87,7 +87,7 @@ Configuration files are located in [`/.github/workflows`](/.github/workflows).
|
|||||||
|
|
||||||
## Vue
|
## Vue
|
||||||
Misskey uses Vue(v3) as its front-end framework.
|
Misskey uses Vue(v3) as its front-end framework.
|
||||||
**When creating a new component, please use the Composition API instead of the Options API.**
|
**When creating a new component, please use the Composition API (and [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html)) instead of the Options API.**
|
||||||
Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.
|
Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.
|
||||||
|
|
||||||
## Adding MisskeyRoom items
|
## Adding MisskeyRoom items
|
||||||
|
@ -448,6 +448,7 @@ uiLanguage: "UIの表示言語"
|
|||||||
groupInvited: "グループに招待されました"
|
groupInvited: "グループに招待されました"
|
||||||
aboutX: "{x}について"
|
aboutX: "{x}について"
|
||||||
useOsNativeEmojis: "OSネイティブの絵文字を使用"
|
useOsNativeEmojis: "OSネイティブの絵文字を使用"
|
||||||
|
disableDrawer: "メニューをドロワーで表示しない"
|
||||||
youHaveNoGroups: "グループがありません"
|
youHaveNoGroups: "グループがありません"
|
||||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
|
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
|
||||||
noHistory: "履歴はありません"
|
noHistory: "履歴はありません"
|
||||||
@ -613,7 +614,6 @@ regenerateLoginToken: "ログイントークンを再生成"
|
|||||||
regenerateLoginTokenDescription: "ログインに使用される内部トークンを再生成します。通常この操作を行う必要はありません。再生成すると、全てのデバイスでログアウトされます。"
|
regenerateLoginTokenDescription: "ログインに使用される内部トークンを再生成します。通常この操作を行う必要はありません。再生成すると、全てのデバイスでログアウトされます。"
|
||||||
setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。"
|
setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。"
|
||||||
fileIdOrUrl: "ファイルIDまたはURL"
|
fileIdOrUrl: "ファイルIDまたはURL"
|
||||||
chatOpenBehavior: "チャットを開くときの動作"
|
|
||||||
behavior: "動作"
|
behavior: "動作"
|
||||||
sample: "サンプル"
|
sample: "サンプル"
|
||||||
abuseReports: "通報"
|
abuseReports: "通報"
|
||||||
@ -818,6 +818,7 @@ leaveGroup: "グループから抜ける"
|
|||||||
leaveGroupConfirm: "「{name}」から抜けますか?"
|
leaveGroupConfirm: "「{name}」から抜けますか?"
|
||||||
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
||||||
welcomeBackWithName: "おかえりなさい、{name}さん"
|
welcomeBackWithName: "おかえりなさい、{name}さん"
|
||||||
|
clickToFinishEmailVerification: "[{ok}]を押して、メールアドレスの確認を完了してください。"
|
||||||
|
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "既に使用されています"
|
used: "既に使用されています"
|
||||||
|
1779
locales/ja-NYA.yml
Normal file
1779
locales/ja-NYA.yml
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "12.100.2",
|
"version": "12.100.2-simkey",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -1,2 +1,47 @@
|
|||||||
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
|
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
|
||||||
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
|
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
|
||||||
|
|
||||||
|
// ブラウザで直接表示することを許可するファイルの種類のリスト
|
||||||
|
// ここに含まれないものは application/octet-stream としてレスポンスされる
|
||||||
|
// SVGはXSSを生むので許可しない
|
||||||
|
export const FILE_TYPE_BROWSERSAFE = [
|
||||||
|
// Images
|
||||||
|
'image/png',
|
||||||
|
'image/gif',
|
||||||
|
'image/jpeg',
|
||||||
|
'image/webp',
|
||||||
|
'image/apng',
|
||||||
|
'image/bmp',
|
||||||
|
'image/tiff',
|
||||||
|
'image/x-icon',
|
||||||
|
|
||||||
|
// OggS
|
||||||
|
'audio/opus',
|
||||||
|
'video/ogg',
|
||||||
|
'audio/ogg',
|
||||||
|
'application/ogg',
|
||||||
|
|
||||||
|
// ISO/IEC base media file format
|
||||||
|
'video/quicktime',
|
||||||
|
'video/mp4',
|
||||||
|
'audio/mp4',
|
||||||
|
'video/x-m4v',
|
||||||
|
'audio/x-m4a',
|
||||||
|
'video/3gpp',
|
||||||
|
'video/3gpp2',
|
||||||
|
|
||||||
|
'video/mpeg',
|
||||||
|
'audio/mpeg',
|
||||||
|
|
||||||
|
'video/webm',
|
||||||
|
'audio/webm',
|
||||||
|
|
||||||
|
'audio/aac',
|
||||||
|
'audio/x-flac',
|
||||||
|
'audio/vnd.wave',
|
||||||
|
];
|
||||||
|
/*
|
||||||
|
https://github.com/sindresorhus/file-type/blob/main/supported.js
|
||||||
|
https://github.com/sindresorhus/file-type/blob/main/core.js
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
|
||||||
|
*/
|
||||||
|
@ -99,7 +99,10 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
|
|||||||
/**
|
/**
|
||||||
* Detect MIME Type and extension
|
* Detect MIME Type and extension
|
||||||
*/
|
*/
|
||||||
export async function detectType(path: string) {
|
export async function detectType(path: string): Promise<{
|
||||||
|
mime: string;
|
||||||
|
ext: string | null;
|
||||||
|
}> {
|
||||||
// Check 0 byte
|
// Check 0 byte
|
||||||
const fileSize = await getFileSize(path);
|
const fileSize = await getFileSize(path);
|
||||||
if (fileSize === 0) {
|
if (fileSize === 0) {
|
||||||
|
@ -14,6 +14,7 @@ import { detectType } from '@/misc/get-file-info';
|
|||||||
import { convertToJpeg, convertToPngOrJpeg } from '@/services/drive/image-processor';
|
import { convertToJpeg, convertToPngOrJpeg } from '@/services/drive/image-processor';
|
||||||
import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail';
|
import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail';
|
||||||
import { StatusError } from '@/misc/fetch';
|
import { StatusError } from '@/misc/fetch';
|
||||||
|
import { FILE_TYPE_BROWSERSAFE } from '@/const';
|
||||||
|
|
||||||
//const _filename = fileURLToPath(import.meta.url);
|
//const _filename = fileURLToPath(import.meta.url);
|
||||||
const _filename = __filename;
|
const _filename = __filename;
|
||||||
@ -27,6 +28,7 @@ const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void =>
|
|||||||
ctx.set('Cache-Control', 'max-age=300');
|
ctx.set('Cache-Control', 'max-age=300');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default async function(ctx: Koa.Context) {
|
export default async function(ctx: Koa.Context) {
|
||||||
const key = ctx.params.key;
|
const key = ctx.params.key;
|
||||||
|
|
||||||
@ -81,7 +83,7 @@ export default async function(ctx: Koa.Context) {
|
|||||||
|
|
||||||
const image = await convertFile();
|
const image = await convertFile();
|
||||||
ctx.body = image.data;
|
ctx.body = image.data;
|
||||||
ctx.set('Content-Type', image.type);
|
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
serverLogger.error(`${e}`);
|
serverLogger.error(`${e}`);
|
||||||
@ -112,14 +114,14 @@ export default async function(ctx: Koa.Context) {
|
|||||||
}).toString();
|
}).toString();
|
||||||
|
|
||||||
ctx.body = InternalStorage.read(key);
|
ctx.body = InternalStorage.read(key);
|
||||||
ctx.set('Content-Type', mime);
|
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream');
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
||||||
ctx.set('Content-Disposition', contentDisposition('inline', filename));
|
ctx.set('Content-Disposition', contentDisposition('inline', filename));
|
||||||
} else {
|
} else {
|
||||||
const readable = InternalStorage.read(file.accessKey!);
|
const readable = InternalStorage.read(file.accessKey!);
|
||||||
readable.on('error', commonReadableHandlerGenerator(ctx));
|
readable.on('error', commonReadableHandlerGenerator(ctx));
|
||||||
ctx.body = readable;
|
ctx.body = readable;
|
||||||
ctx.set('Content-Type', file.type);
|
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream');
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
||||||
ctx.set('Content-Disposition', contentDisposition('inline', file.name));
|
ctx.set('Content-Disposition', contentDisposition('inline', file.name));
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { createTemp } from '@/misc/create-temp';
|
|||||||
import { downloadUrl } from '@/misc/download-url';
|
import { downloadUrl } from '@/misc/download-url';
|
||||||
import { detectType } from '@/misc/get-file-info';
|
import { detectType } from '@/misc/get-file-info';
|
||||||
import { StatusError } from '@/misc/fetch';
|
import { StatusError } from '@/misc/fetch';
|
||||||
|
import { FILE_TYPE_BROWSERSAFE } from '@/const';
|
||||||
|
|
||||||
export async function proxyMedia(ctx: Koa.Context) {
|
export async function proxyMedia(ctx: Koa.Context) {
|
||||||
const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url;
|
const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url;
|
||||||
@ -18,7 +19,7 @@ export async function proxyMedia(ctx: Koa.Context) {
|
|||||||
|
|
||||||
const { mime, ext } = await detectType(path);
|
const { mime, ext } = await detectType(path);
|
||||||
|
|
||||||
if (!mime.startsWith('image/')) throw 403;
|
if (!FILE_TYPE_BROWSERSAFE.includes(mime)) throw 403;
|
||||||
|
|
||||||
let image: IImage;
|
let image: IImage;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ block vars
|
|||||||
- const user = note.user;
|
- const user = note.user;
|
||||||
- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
|
- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
|
||||||
- const url = `${config.url}/notes/${note.id}`;
|
- const url = `${config.url}/notes/${note.id}`;
|
||||||
|
- const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null;
|
||||||
|
|
||||||
block title
|
block title
|
||||||
= `${title} | ${instanceName}`
|
= `${title} | ${instanceName}`
|
||||||
@ -19,7 +20,7 @@ block og
|
|||||||
meta(property='og:image' content= user.avatarUrl)
|
meta(property='og:image' content= user.avatarUrl)
|
||||||
|
|
||||||
block meta
|
block meta
|
||||||
if user.host || profile.noCrawle
|
if user.host || isRenote || profile.noCrawle
|
||||||
meta(name='robots' content='noindex')
|
meta(name='robots' content='noindex')
|
||||||
|
|
||||||
meta(name='misskey:user-username' content=user.username)
|
meta(name='misskey:user-username' content=user.username)
|
||||||
|
@ -20,6 +20,7 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error';
|
|||||||
import * as S3 from 'aws-sdk/clients/s3';
|
import * as S3 from 'aws-sdk/clients/s3';
|
||||||
import { getS3 } from './s3';
|
import { getS3 } from './s3';
|
||||||
import * as sharp from 'sharp';
|
import * as sharp from 'sharp';
|
||||||
|
import { FILE_TYPE_BROWSERSAFE } from '@/const';
|
||||||
|
|
||||||
const logger = driveLogger.createSubLogger('register', 'yellow');
|
const logger = driveLogger.createSubLogger('register', 'yellow');
|
||||||
|
|
||||||
@ -241,6 +242,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
|
|||||||
*/
|
*/
|
||||||
async function upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
async function upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
|
||||||
if (type === 'image/apng') type = 'image/png';
|
if (type === 'image/apng') type = 'image/png';
|
||||||
|
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
|
||||||
|
|
||||||
const meta = await fetchMeta();
|
const meta = await fetchMeta();
|
||||||
|
|
||||||
|
@ -3,10 +3,33 @@ import config from '@/config/index';
|
|||||||
import { SwSubscriptions } from '@/models/index';
|
import { SwSubscriptions } from '@/models/index';
|
||||||
import { fetchMeta } from '@/misc/fetch-meta';
|
import { fetchMeta } from '@/misc/fetch-meta';
|
||||||
import { Packed } from '@/misc/schema';
|
import { Packed } from '@/misc/schema';
|
||||||
|
import { getNoteSummary } from '@/misc/get-note-summary';
|
||||||
|
|
||||||
type notificationType = 'notification' | 'unreadMessagingMessage';
|
type notificationType = 'notification' | 'unreadMessagingMessage';
|
||||||
type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>;
|
type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>;
|
||||||
|
|
||||||
|
// プッシュメッセージサーバーには文字数制限があるため、内容を削減します
|
||||||
|
function truncateNotification(notification: Packed<'Notification'>): any {
|
||||||
|
if (notification.note) {
|
||||||
|
return {
|
||||||
|
...notification,
|
||||||
|
note: {
|
||||||
|
...notification.note,
|
||||||
|
// textをgetNoteSummaryしたものに置き換える
|
||||||
|
text: getNoteSummary(notification.type === 'renote' ? notification.note.renote as Packed<'Note'> : notification.note),
|
||||||
|
...{
|
||||||
|
cw: undefined,
|
||||||
|
reply: undefined,
|
||||||
|
renote: undefined,
|
||||||
|
user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
export default async function(userId: string, type: notificationType, body: notificationBody) {
|
export default async function(userId: string, type: notificationType, body: notificationBody) {
|
||||||
const meta = await fetchMeta();
|
const meta = await fetchMeta();
|
||||||
|
|
||||||
@ -32,7 +55,9 @@ export default async function(userId: string, type: notificationType, body: noti
|
|||||||
};
|
};
|
||||||
|
|
||||||
push.sendNotification(pushSubscription, JSON.stringify({
|
push.sendNotification(pushSubscription, JSON.stringify({
|
||||||
type, body,
|
type,
|
||||||
|
body: type === 'notification' ? truncateNotification(body as Packed<'Notification'>) : body,
|
||||||
|
userId,
|
||||||
}), {
|
}), {
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
}).catch((err: any) => {
|
}).catch((err: any) => {
|
||||||
|
@ -77,7 +77,7 @@
|
|||||||
import { defineComponent, markRaw } from 'vue';
|
import { defineComponent, markRaw } from 'vue';
|
||||||
import { emojilist } from '@/scripts/emojilist';
|
import { emojilist } from '@/scripts/emojilist';
|
||||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
import Particle from '@/components/particle.vue';
|
import Ripple from '@/components/ripple.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { isTouchUsing } from '@/scripts/touch';
|
import { isTouchUsing } from '@/scripts/touch';
|
||||||
import { isMobile } from '@/scripts/is-mobile';
|
import { isMobile } from '@/scripts/is-mobile';
|
||||||
@ -296,9 +296,9 @@ export default defineComponent({
|
|||||||
if (ev) {
|
if (ev) {
|
||||||
const el = ev.currentTarget || ev.target;
|
const el = ev.currentTarget || ev.target;
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
const x = rect.left + (el.clientWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.clientHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
os.popup(Particle, { x, y }, {}, 'end');
|
os.popup(Ripple, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = this.getKey(emoji);
|
const key = this.getKey(emoji);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
|
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
|
||||||
<input ref="inputEl"
|
<input ref="inputEl"
|
||||||
v-model="v"
|
v-model="v"
|
||||||
v-panel
|
v-adaptive-border
|
||||||
:type="type"
|
:type="type"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:required="required"
|
:required="required"
|
||||||
@ -243,7 +243,8 @@ export default defineComponent({
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
border: solid 0.5px var(--panel);
|
background: var(--panel);
|
||||||
|
border: solid 1px var(--panel);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -251,7 +252,7 @@ export default defineComponent({
|
|||||||
transition: border-color 0.1s ease-out;
|
transition: border-color 0.1s ease-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--inputBorderHover);
|
border-color: var(--inputBorderHover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +299,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
&.focused {
|
&.focused {
|
||||||
> input {
|
> input {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent) !important;
|
||||||
//box-shadow: 0 0 0 4px var(--focus);
|
//box-shadow: 0 0 0 4px var(--focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
<div class="label" @click="focus"><slot name="label"></slot></div>
|
<div class="label" @click="focus"><slot name="label"></slot></div>
|
||||||
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
|
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
|
||||||
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
|
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
|
||||||
<select ref="inputEl" v-model="v" v-panel
|
<select ref="inputEl"
|
||||||
|
v-model="v"
|
||||||
|
v-adaptive-border
|
||||||
class="select"
|
class="select"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:required="required"
|
:required="required"
|
||||||
@ -226,7 +228,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
> .select {
|
> .select {
|
||||||
border-color: var(--inputBorderHover);
|
border-color: var(--inputBorderHover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,6 +244,7 @@ export default defineComponent({
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
background: var(--panel);
|
||||||
border: solid 1px var(--panel);
|
border: solid 1px var(--panel);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -295,7 +298,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
&.focused {
|
&.focused {
|
||||||
> select {
|
> select {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,6 @@
|
|||||||
<div
|
<div
|
||||||
class="ziffeoms"
|
class="ziffeoms"
|
||||||
:class="{ disabled, checked }"
|
:class="{ disabled, checked }"
|
||||||
role="switch"
|
|
||||||
:aria-checked="checked"
|
|
||||||
:aria-disabled="disabled"
|
|
||||||
@click.prevent="toggle"
|
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
ref="input"
|
ref="input"
|
||||||
@ -13,18 +9,20 @@
|
|||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@keydown.enter="toggle"
|
@keydown.enter="toggle"
|
||||||
>
|
>
|
||||||
<span v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button">
|
<span ref="button" v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle">
|
||||||
<span class="handle"></span>
|
<i class="check fas fa-check"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="label">
|
<span class="label">
|
||||||
<span><slot></slot></span>
|
<span @click="toggle"><slot></slot></span>
|
||||||
<p class="caption"><slot name="caption"></slot></p>
|
<p class="caption"><slot name="caption"></slot></p>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, ref, toRefs } from 'vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import Ripple from '@/components/ripple.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -37,17 +35,28 @@ export default defineComponent({
|
|||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
checked(): boolean {
|
setup(props, context) {
|
||||||
return this.modelValue;
|
const button = ref<HTMLElement>();
|
||||||
}
|
const checked = toRefs(props).modelValue;
|
||||||
|
const toggle = () => {
|
||||||
|
if (props.disabled) return;
|
||||||
|
context.emit('update:modelValue', !checked.value);
|
||||||
|
|
||||||
|
if (!checked.value) {
|
||||||
|
const rect = button.value.getBoundingClientRect();
|
||||||
|
const x = rect.left + (button.value.offsetWidth / 2);
|
||||||
|
const y = rect.top + (button.value.offsetHeight / 2);
|
||||||
|
os.popup(Ripple, { x, y, particle: false }, {}, 'end');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
button,
|
||||||
|
checked,
|
||||||
|
toggle,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
|
||||||
toggle() {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.$emit('update:modelValue', !this.checked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -55,16 +64,7 @@ export default defineComponent({
|
|||||||
.ziffeoms {
|
.ziffeoms {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
cursor: pointer;
|
transition: all 0.2s ease;
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
@ -80,27 +80,32 @@ export default defineComponent({
|
|||||||
|
|
||||||
> .button {
|
> .button {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 36px;
|
box-sizing: border-box;
|
||||||
height: 26px;
|
width: 23px;
|
||||||
background: var(--switchBg);
|
height: 23px;
|
||||||
outline: none;
|
outline: none;
|
||||||
border-radius: 999px;
|
background: var(--panel);
|
||||||
|
border: solid 1px var(--panel);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
transition: inherit;
|
transition: inherit;
|
||||||
|
|
||||||
> .handle {
|
> .check {
|
||||||
position: absolute;
|
margin: auto;
|
||||||
top: 0;
|
opacity: 0;
|
||||||
bottom: 0;
|
color: var(--fgOnAccent);
|
||||||
left: 5px;
|
font-size: 13px;
|
||||||
margin: auto 0;
|
transform: scale(0.5);
|
||||||
border-radius: 100%;
|
transition: all 0.2s ease;
|
||||||
transition: background-color 0.3s, transform 0.3s;
|
}
|
||||||
width: 16px;
|
}
|
||||||
height: 16px;
|
|
||||||
background-color: #fff;
|
&:hover {
|
||||||
|
> .button {
|
||||||
|
border-color: var(--inputBorderHover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,13 +113,13 @@ export default defineComponent({
|
|||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
display: block;
|
display: block;
|
||||||
cursor: pointer;
|
|
||||||
transition: inherit;
|
transition: inherit;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
transition: inherit;
|
transition: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,12 +134,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> .button {
|
|
||||||
background-color: var(--accentedBg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
@ -142,11 +141,12 @@ export default defineComponent({
|
|||||||
|
|
||||||
&.checked {
|
&.checked {
|
||||||
> .button {
|
> .button {
|
||||||
background-color: var(--accent);
|
background-color: var(--accent) !important;
|
||||||
border-color: var(--accent);
|
border-color: var(--accent) !important;
|
||||||
|
|
||||||
> .handle {
|
> .check {
|
||||||
transform: translateX(10px);
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="input" :class="{ disabled, focused, tall, pre }">
|
<div class="input" :class="{ disabled, focused, tall, pre }">
|
||||||
<textarea ref="inputEl"
|
<textarea ref="inputEl"
|
||||||
v-model="v"
|
v-model="v"
|
||||||
v-panel
|
v-adaptive-border
|
||||||
:class="{ code, _monospace: code }"
|
:class="{ code, _monospace: code }"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:required="required"
|
:required="required"
|
||||||
@ -210,7 +210,8 @@ export default defineComponent({
|
|||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
border: solid 0.5px var(--panel);
|
background: var(--panel);
|
||||||
|
border: solid 1px var(--panel);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -218,13 +219,13 @@ export default defineComponent({
|
|||||||
transition: border-color 0.1s ease-out;
|
transition: border-color 0.1s ease-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--inputBorderHover);
|
border-color: var(--inputBorderHover) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.focused {
|
&.focused {
|
||||||
> textarea {
|
> textarea {
|
||||||
border-color: var(--accent);
|
border-color: var(--accent) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,11 +106,6 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.to.startsWith('/my/messaging')) {
|
|
||||||
if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
|
|
||||||
if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.behavior) {
|
if (this.behavior) {
|
||||||
if (this.behavior === 'window') {
|
if (this.behavior === 'window') {
|
||||||
return this.window();
|
return this.window();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<i v-else-if="info.icon" class="icon" :class="info.icon"></i>
|
<i v-else-if="info.icon" class="icon" :class="info.icon"></i>
|
||||||
|
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/>
|
<MkUserName v-if="info.userName" :user="info.userName" :nowrap="true" class="title"/>
|
||||||
<div v-else-if="info.title" class="title">{{ info.title }}</div>
|
<div v-else-if="info.title" class="title">{{ info.title }}</div>
|
||||||
<div v-if="!narrow && info.subtitle" class="subtitle">
|
<div v-if="!narrow && info.subtitle" class="subtitle">
|
||||||
{{ info.subtitle }}
|
{{ info.subtitle }}
|
||||||
@ -268,6 +268,7 @@ export default defineComponent({
|
|||||||
> .titleContainer {
|
> .titleContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
max-width: 400px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
<component :is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
||||||
@mouseover="onMouseover"
|
|
||||||
@mouseleave="onMouseleave"
|
|
||||||
@contextmenu.stop="() => {}"
|
@contextmenu.stop="() => {}"
|
||||||
>
|
>
|
||||||
<template v-if="!self">
|
<template v-if="!self">
|
||||||
@ -20,11 +18,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import { toUnicode as decodePunycode } from 'punycode/';
|
import { toUnicode as decodePunycode } from 'punycode/';
|
||||||
import { url as local } from '@/config';
|
import { url as local } from '@/config';
|
||||||
import { isTouchUsing } from '@/scripts/touch';
|
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { useTooltip } from '@/scripts/use-tooltip';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -35,74 +33,36 @@ export default defineComponent({
|
|||||||
rel: {
|
rel: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
|
default: null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
setup(props) {
|
||||||
const self = this.url.startsWith(local);
|
const self = props.url.startsWith(local);
|
||||||
|
const url = new URL(props.url);
|
||||||
|
const el = ref();
|
||||||
|
|
||||||
|
useTooltip(el, (showing) => {
|
||||||
|
os.popup(import('@/components/url-preview-popup.vue'), {
|
||||||
|
showing,
|
||||||
|
url: props.url,
|
||||||
|
source: el.value,
|
||||||
|
}, {}, 'closed');
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
local,
|
local,
|
||||||
schema: null as string | null,
|
schema: url.protocol,
|
||||||
hostname: null as string | null,
|
hostname: decodePunycode(url.hostname),
|
||||||
port: null as string | null,
|
port: url.port,
|
||||||
pathname: null as string | null,
|
pathname: decodeURIComponent(url.pathname),
|
||||||
query: null as string | null,
|
query: decodeURIComponent(url.search),
|
||||||
hash: null as string | null,
|
hash: decodeURIComponent(url.hash),
|
||||||
self: self,
|
self: self,
|
||||||
attr: self ? 'to' : 'href',
|
attr: self ? 'to' : 'href',
|
||||||
target: self ? null : '_blank',
|
target: self ? null : '_blank',
|
||||||
showTimer: null,
|
el,
|
||||||
hideTimer: null,
|
|
||||||
checkTimer: null,
|
|
||||||
close: null,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
|
||||||
const url = new URL(this.url);
|
|
||||||
this.schema = url.protocol;
|
|
||||||
this.hostname = decodePunycode(url.hostname);
|
|
||||||
this.port = url.port;
|
|
||||||
this.pathname = decodeURIComponent(url.pathname);
|
|
||||||
this.query = decodeURIComponent(url.search);
|
|
||||||
this.hash = decodeURIComponent(url.hash);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async showPreview() {
|
|
||||||
if (!document.body.contains(this.$el)) return;
|
|
||||||
if (this.close) return;
|
|
||||||
|
|
||||||
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
|
|
||||||
url: this.url,
|
|
||||||
source: this.$el
|
|
||||||
});
|
|
||||||
|
|
||||||
this.close = () => {
|
|
||||||
dispose();
|
|
||||||
};
|
|
||||||
|
|
||||||
this.checkTimer = setInterval(() => {
|
|
||||||
if (!document.body.contains(this.$el)) this.closePreview();
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
closePreview() {
|
|
||||||
if (this.close) {
|
|
||||||
clearInterval(this.checkTimer);
|
|
||||||
this.close();
|
|
||||||
this.close = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onMouseover() {
|
|
||||||
if (isTouchUsing) return;
|
|
||||||
clearTimeout(this.showTimer);
|
|
||||||
clearTimeout(this.hideTimer);
|
|
||||||
this.showTimer = setTimeout(this.showPreview, 500);
|
|
||||||
},
|
|
||||||
onMouseleave() {
|
|
||||||
if (isTouchUsing) return;
|
|
||||||
clearTimeout(this.showTimer);
|
|
||||||
clearTimeout(this.hideTimer);
|
|
||||||
this.hideTimer = setTimeout(this.closePreview, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
previewable,
|
previewable,
|
||||||
gallery,
|
gallery,
|
||||||
|
pswpZIndex: os.claimZIndex('middle'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -188,3 +189,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.pswp {
|
||||||
|
// なぜか機能しない
|
||||||
|
//z-index: v-bind(pswpZIndex);
|
||||||
|
z-index: 2000000;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<Mfm :text="text" :author="$i" :i="$i"/>
|
<Mfm :text="text.trim()" :author="$i" :i="$i"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -61,6 +61,7 @@ export default defineComponent({
|
|||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
> .main {
|
||||||
@ -69,6 +70,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
> .header {
|
> .header {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .body {
|
> .body {
|
||||||
|
@ -16,7 +16,13 @@
|
|||||||
<template #headerLeft>
|
<template #headerLeft>
|
||||||
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
|
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
|
||||||
</template>
|
</template>
|
||||||
<div class="yrolvcoq">
|
<template #headerRight>
|
||||||
|
<button v-tooltip="$ts.showInPage" class="_button" @click="expand()"><i class="fas fa-expand-alt"></i></button>
|
||||||
|
<button v-tooltip="$ts.popout" class="_button" @click="popout()"><i class="fas fa-external-link-alt"></i></button>
|
||||||
|
<button class="_button" @click="menu"><i class="fas fa-ellipsis-h"></i></button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="yrolvcoq" :style="{ background: pageInfo?.bg }">
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
|
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
|
||||||
<component :is="component" v-bind="props" :ref="changePage"/>
|
<component :is="component" v-bind="props" :ref="changePage"/>
|
||||||
@ -33,6 +39,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
|
|||||||
import { resolve } from '@/router';
|
import { resolve } from '@/router';
|
||||||
import { url } from '@/config';
|
import { url } from '@/config';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -139,6 +146,23 @@ export default defineComponent({
|
|||||||
this.props = props;
|
this.props = props;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
menu(ev) {
|
||||||
|
os.popupMenu([{
|
||||||
|
icon: 'fas fa-external-link-alt',
|
||||||
|
text: this.$ts.openInNewTab,
|
||||||
|
action: () => {
|
||||||
|
window.open(this.url, '_blank');
|
||||||
|
this.$refs.window.close();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
icon: 'fas fa-link',
|
||||||
|
text: this.$ts.copyLink,
|
||||||
|
action: () => {
|
||||||
|
copyToClipboard(this.url);
|
||||||
|
}
|
||||||
|
}], ev.currentTarget || ev.target);
|
||||||
|
},
|
||||||
|
|
||||||
back() {
|
back() {
|
||||||
this.navigate(this.history.pop(), false);
|
this.navigate(this.history.pop(), false);
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="count > 0"
|
v-if="count > 0"
|
||||||
ref="buttonRef"
|
ref="buttonRef"
|
||||||
v-particle="canToggle"
|
v-ripple="canToggle"
|
||||||
class="hkzvhatu _button"
|
class="hkzvhatu _button"
|
||||||
:class="{ reacted: note.myReaction == reaction, canToggle }"
|
:class="{ reacted: note.myReaction == reaction, canToggle }"
|
||||||
@click="toggleReaction()"
|
@click="toggleReaction()"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="vswabwbm" :style="{ top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
|
<div class="vswabwbm" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
|
||||||
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle fill="none" cx="64" cy="64">
|
<circle fill="none" cx="64" cy="64">
|
||||||
<animate attributeName="r"
|
<animate attributeName="r"
|
||||||
@ -52,7 +52,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, onMounted } from 'vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -63,37 +64,46 @@ export default defineComponent({
|
|||||||
y: {
|
y: {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
particle: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['end'],
|
emits: ['end'],
|
||||||
data() {
|
setup(props, context) {
|
||||||
const particles = [];
|
const particles = [];
|
||||||
const origin = 64;
|
const origin = 64;
|
||||||
const colors = ['#FF1493', '#00FFFF', '#FFE202'];
|
const colors = ['#FF1493', '#00FFFF', '#FFE202'];
|
||||||
|
|
||||||
for (let i = 0; i < 12; i++) {
|
if (props.particle) {
|
||||||
const angle = Math.random() * (Math.PI * 2);
|
for (let i = 0; i < 12; i++) {
|
||||||
const pos = Math.random() * 16;
|
const angle = Math.random() * (Math.PI * 2);
|
||||||
const velocity = 16 + (Math.random() * 48);
|
const pos = Math.random() * 16;
|
||||||
particles.push({
|
const velocity = 16 + (Math.random() * 48);
|
||||||
size: 4 + (Math.random() * 8),
|
particles.push({
|
||||||
xA: origin + (Math.sin(angle) * pos),
|
size: 4 + (Math.random() * 8),
|
||||||
yA: origin + (Math.cos(angle) * pos),
|
xA: origin + (Math.sin(angle) * pos),
|
||||||
xB: origin + (Math.sin(angle) * (pos + velocity)),
|
yA: origin + (Math.cos(angle) * pos),
|
||||||
yB: origin + (Math.cos(angle) * (pos + velocity)),
|
xB: origin + (Math.sin(angle) * (pos + velocity)),
|
||||||
color: colors[Math.floor(Math.random() * colors.length)]
|
yB: origin + (Math.cos(angle) * (pos + velocity)),
|
||||||
});
|
color: colors[Math.floor(Math.random() * colors.length)]
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
context.emit('end');
|
||||||
|
}, 1100);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
particles
|
particles,
|
||||||
|
zIndex: os.claimZIndex('high'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.$emit('end');
|
|
||||||
}, 1100);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -101,7 +111,6 @@ export default defineComponent({
|
|||||||
.vswabwbm {
|
.vswabwbm {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1000000;
|
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
|
|
@ -51,14 +51,13 @@
|
|||||||
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span>
|
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span>
|
||||||
</template>
|
</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<label v-if="meta.tosUrl" class="_formBlock tou">
|
<MkSwitch v-if="meta.tosUrl" v-model="ToSAgreement" class="_formBlock tou">
|
||||||
<input v-model="ToSAgreement" type="checkbox">
|
|
||||||
<I18n :src="$ts.agreeTo">
|
<I18n :src="$ts.agreeTo">
|
||||||
<template #0>
|
<template #0>
|
||||||
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a>
|
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a>
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
</label>
|
</MkSwitch>
|
||||||
<captcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
|
<captcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
|
||||||
<captcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
|
<captcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
|
||||||
<MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton>
|
<MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton>
|
||||||
@ -258,11 +257,5 @@ export default defineComponent({
|
|||||||
.captcha {
|
.captcha {
|
||||||
margin: 16px 0;
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .tou {
|
|
||||||
display: block;
|
|
||||||
margin: 16px 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -284,7 +284,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.asDrawer {
|
&.asDrawer {
|
||||||
padding: 12px 0;
|
padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
> .item {
|
> .item {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import { defineComponent, nextTick, onMounted, computed, PropType, ref, watch } from 'vue';
|
import { defineComponent, nextTick, onMounted, computed, PropType, ref, watch } from 'vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { isTouchUsing } from '@/scripts/touch';
|
import { isTouchUsing } from '@/scripts/touch';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
|
||||||
function getFixedContainer(el: Element | null): Element | null {
|
function getFixedContainer(el: Element | null): Element | null {
|
||||||
if (el == null || el.tagName === 'BODY') return null;
|
if (el == null || el.tagName === 'BODY') return null;
|
||||||
@ -77,7 +78,7 @@ export default defineComponent({
|
|||||||
const zIndex = os.claimZIndex(props.zPriority);
|
const zIndex = os.claimZIndex(props.zPriority);
|
||||||
const type = computed(() => {
|
const type = computed(() => {
|
||||||
if (props.preferType === 'auto') {
|
if (props.preferType === 'auto') {
|
||||||
if (isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
|
if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
|
||||||
return 'drawer';
|
return 'drawer';
|
||||||
} else {
|
} else {
|
||||||
return props.src != null ? 'popup' : 'dialog';
|
return props.src != null ? 'popup' : 'dialog';
|
||||||
|
@ -5,7 +5,12 @@
|
|||||||
<MkError v-else-if="error" @retry="init()"/>
|
<MkError v-else-if="error" @retry="init()"/>
|
||||||
|
|
||||||
<div v-else-if="empty" key="_empty_" class="empty">
|
<div v-else-if="empty" key="_empty_" class="empty">
|
||||||
<slot name="empty"></slot>
|
<slot name="empty">
|
||||||
|
<div class="_fullinfo">
|
||||||
|
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
||||||
|
<div>{{ $ts.nothing }}</div>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="cxiknjgy">
|
<div v-else class="cxiknjgy">
|
||||||
|
@ -414,6 +414,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .left {
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
> .title {
|
> .title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -421,7 +425,6 @@ export default defineComponent({
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
text-align: center;
|
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
packages/client/src/directives/adaptive-border.ts
Normal file
24
packages/client/src/directives/adaptive-border.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { Directive } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted(src, binding, vn) {
|
||||||
|
const getBgColor = (el: HTMLElement) => {
|
||||||
|
const style = window.getComputedStyle(el);
|
||||||
|
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||||
|
return style.backgroundColor;
|
||||||
|
} else {
|
||||||
|
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentBg = getBgColor(src.parentElement);
|
||||||
|
|
||||||
|
const myBg = window.getComputedStyle(src).backgroundColor;
|
||||||
|
|
||||||
|
if (parentBg === myBg) {
|
||||||
|
src.style.borderColor = 'var(--divider)';
|
||||||
|
} else {
|
||||||
|
src.style.borderColor = myBg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} as Directive;
|
@ -3,7 +3,7 @@ import { App } from 'vue';
|
|||||||
import userPreview from './user-preview';
|
import userPreview from './user-preview';
|
||||||
import size from './size';
|
import size from './size';
|
||||||
import getSize from './get-size';
|
import getSize from './get-size';
|
||||||
import particle from './particle';
|
import ripple from './ripple';
|
||||||
import tooltip from './tooltip';
|
import tooltip from './tooltip';
|
||||||
import hotkey from './hotkey';
|
import hotkey from './hotkey';
|
||||||
import appear from './appear';
|
import appear from './appear';
|
||||||
@ -11,13 +11,14 @@ import anim from './anim';
|
|||||||
import stickyContainer from './sticky-container';
|
import stickyContainer from './sticky-container';
|
||||||
import clickAnime from './click-anime';
|
import clickAnime from './click-anime';
|
||||||
import panel from './panel';
|
import panel from './panel';
|
||||||
|
import adaptiveBorder from './adaptive-border';
|
||||||
|
|
||||||
export default function(app: App) {
|
export default function(app: App) {
|
||||||
app.directive('userPreview', userPreview);
|
app.directive('userPreview', userPreview);
|
||||||
app.directive('user-preview', userPreview);
|
app.directive('user-preview', userPreview);
|
||||||
app.directive('size', size);
|
app.directive('size', size);
|
||||||
app.directive('get-size', getSize);
|
app.directive('get-size', getSize);
|
||||||
app.directive('particle', particle);
|
app.directive('ripple', ripple);
|
||||||
app.directive('tooltip', tooltip);
|
app.directive('tooltip', tooltip);
|
||||||
app.directive('hotkey', hotkey);
|
app.directive('hotkey', hotkey);
|
||||||
app.directive('appear', appear);
|
app.directive('appear', appear);
|
||||||
@ -25,4 +26,5 @@ export default function(app: App) {
|
|||||||
app.directive('click-anime', clickAnime);
|
app.directive('click-anime', clickAnime);
|
||||||
app.directive('sticky-container', stickyContainer);
|
app.directive('sticky-container', stickyContainer);
|
||||||
app.directive('panel', panel);
|
app.directive('panel', panel);
|
||||||
|
app.directive('adaptive-border', adaptiveBorder);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ export default {
|
|||||||
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
|
||||||
return style.backgroundColor;
|
return style.backgroundColor;
|
||||||
} else {
|
} else {
|
||||||
return getBgColor(el.parentElement);
|
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import Particle from '@/components/particle.vue';
|
import Ripple from '@/components/ripple.vue';
|
||||||
import { popup } from '@/os';
|
import { popup } from '@/os';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -9,10 +9,10 @@ export default {
|
|||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
const x = rect.left + (el.clientWidth / 2);
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
const y = rect.top + (el.clientHeight / 2);
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
|
||||||
popup(Particle, { x, y }, {}, 'end');
|
popup(Ripple, { x, y }, {}, 'end');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -40,7 +40,6 @@ import MkButton from '@/components/ui/button.vue';
|
|||||||
import MkSwitch from '@/components/form/switch.vue';
|
import MkSwitch from '@/components/form/switch.vue';
|
||||||
import XModalWindow from '@/components/ui/modal-window.vue';
|
import XModalWindow from '@/components/ui/modal-window.vue';
|
||||||
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
|
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
|
||||||
@ -74,11 +73,9 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
async fetch() {
|
async fetch() {
|
||||||
Progress.start();
|
|
||||||
this.file = await os.api('drive/files/show', { fileId: this.fileId });
|
this.file = await os.api('drive/files/show', { fileId: this.fileId });
|
||||||
this.info = await os.api('admin/drive/show-file', { fileId: this.fileId });
|
this.info = await os.api('admin/drive/show-file', { fileId: this.fileId });
|
||||||
this.isSensitive = this.file.isSensitive;
|
this.isSensitive = this.file.isSensitive;
|
||||||
Progress.done();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
showUser() {
|
showUser() {
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
src="antenna"
|
src="antenna"
|
||||||
:antenna="antennaId"
|
:antenna="antennaId"
|
||||||
:sound="true"
|
:sound="true"
|
||||||
@before="before()"
|
|
||||||
@after="after()"
|
|
||||||
@queue="queueUpdated"
|
@queue="queueUpdated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -17,7 +15,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import { scroll } from '@/scripts/scroll';
|
import { scroll } from '@/scripts/scroll';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
@ -76,14 +73,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
},
|
|
||||||
|
|
||||||
queueUpdated(q) {
|
queueUpdated(q) {
|
||||||
this.queue = q;
|
this.queue = q;
|
||||||
},
|
},
|
||||||
|
@ -1,28 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<MkSpacer :content-max="700">
|
||||||
<div class="_section">
|
<div class="_formRoot">
|
||||||
<div class="_content">
|
<MkInput v-model="name" class="_formBlock">
|
||||||
<MkInput v-model="name">
|
<template #label>{{ $ts.name }}</template>
|
||||||
<template #label>{{ $ts.name }}</template>
|
</MkInput>
|
||||||
</MkInput>
|
|
||||||
|
|
||||||
<MkTextarea v-model="description">
|
<MkTextarea v-model="description" class="_formBlock">
|
||||||
<template #label>{{ $ts.description }}</template>
|
<template #label>{{ $ts.description }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
|
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>
|
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>
|
||||||
<div v-else-if="bannerUrl">
|
<div v-else-if="bannerUrl">
|
||||||
<img :src="bannerUrl" style="width: 100%;"/>
|
<img :src="bannerUrl" style="width: 100%;"/>
|
||||||
<MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton>
|
<MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="_footer">
|
<div class="_formBlock">
|
||||||
<MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton>
|
<MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -51,9 +49,11 @@ export default defineComponent({
|
|||||||
[symbols.PAGE_INFO]: computed(() => this.channelId ? {
|
[symbols.PAGE_INFO]: computed(() => this.channelId ? {
|
||||||
title: this.$ts._channel.edit,
|
title: this.$ts._channel.edit,
|
||||||
icon: 'fas fa-satellite-dish',
|
icon: 'fas fa-satellite-dish',
|
||||||
|
bg: 'var(--bg)',
|
||||||
} : {
|
} : {
|
||||||
title: this.$ts._channel.create,
|
title: this.$ts._channel.create,
|
||||||
icon: 'fas fa-satellite-dish',
|
icon: 'fas fa-satellite-dish',
|
||||||
|
bg: 'var(--bg)',
|
||||||
}),
|
}),
|
||||||
channel: null,
|
channel: null,
|
||||||
name: null,
|
name: null,
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="channel" class="_section">
|
<MkSpacer :content-max="700">
|
||||||
<div class="wpgynlbz _content _panel _gap" :class="{ hide: !showBanner }">
|
<div v-if="channel">
|
||||||
<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
|
<div class="wpgynlbz _panel _gap" :class="{ hide: !showBanner }">
|
||||||
<button class="_button toggle" @click="() => showBanner = !showBanner">
|
<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
|
||||||
<template v-if="showBanner"><i class="fas fa-angle-up"></i></template>
|
<button class="_button toggle" @click="() => showBanner = !showBanner">
|
||||||
<template v-else><i class="fas fa-angle-down"></i></template>
|
<template v-if="showBanner"><i class="fas fa-angle-up"></i></template>
|
||||||
</button>
|
<template v-else><i class="fas fa-angle-down"></i></template>
|
||||||
<div v-if="!showBanner" class="hideOverlay">
|
</button>
|
||||||
</div>
|
<div v-if="!showBanner" class="hideOverlay">
|
||||||
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
|
</div>
|
||||||
<div class="status">
|
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
|
||||||
<div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
|
<div class="status">
|
||||||
<div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
|
<div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
|
||||||
|
<div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
|
||||||
|
</div>
|
||||||
|
<div class="fade"></div>
|
||||||
|
</div>
|
||||||
|
<div v-if="channel.description" class="description">
|
||||||
|
<Mfm :text="channel.description" :is-note="false" :i="$i"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="fade"></div>
|
|
||||||
</div>
|
|
||||||
<div v-if="channel.description" class="description">
|
|
||||||
<Mfm :text="channel.description" :is-note="false" :i="$i"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<XPostForm v-if="$i" :channel="channel" class="post-form _panel _gap" fixed/>
|
||||||
|
|
||||||
|
<XTimeline :key="channelId" class="_gap" src="channel" :channel="channelId" @before="before" @after="after"/>
|
||||||
</div>
|
</div>
|
||||||
|
</MkSpacer>
|
||||||
<XPostForm v-if="$i" :channel="channel" class="post-form _content _panel _gap" fixed/>
|
|
||||||
|
|
||||||
<XTimeline :key="channelId" class="_content _gap" src="channel" :channel="channelId" @before="before" @after="after"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -55,6 +57,12 @@ export default defineComponent({
|
|||||||
[symbols.PAGE_INFO]: computed(() => this.channel ? {
|
[symbols.PAGE_INFO]: computed(() => this.channel ? {
|
||||||
title: this.channel.name,
|
title: this.channel.name,
|
||||||
icon: 'fas fa-satellite-dish',
|
icon: 'fas fa-satellite-dish',
|
||||||
|
bg: 'var(--bg)',
|
||||||
|
actions: [...(this.$i && this.$i.id === this.channel.userId ? [{
|
||||||
|
icon: 'fas fa-cog',
|
||||||
|
text: this.$ts.edit,
|
||||||
|
handler: this.edit,
|
||||||
|
}] : [])],
|
||||||
} : null),
|
} : null),
|
||||||
channel: null,
|
channel: null,
|
||||||
showBanner: true,
|
showBanner: true,
|
||||||
@ -79,8 +87,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
methods: {
|
||||||
|
edit() {
|
||||||
|
this.$router.push(`/channels/${this.channel.id}/edit`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,58 +1,63 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<MkSpacer :content-max="700">
|
||||||
<div v-if="$i" class="_section" style="padding: 0;">
|
<div v-if="tab === 'featured'" class="_content grwlizim featured">
|
||||||
<MkTab v-model="tab" class="_content">
|
<MkPagination v-slot="{items}" :pagination="featuredPagination">
|
||||||
<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._channel.featured }}</option>
|
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
||||||
<option value="following"><i class="fas fa-heart"></i> {{ $ts._channel.following }}</option>
|
</MkPagination>
|
||||||
<option value="owned"><i class="fas fa-edit"></i> {{ $ts._channel.owned }}</option>
|
|
||||||
</MkTab>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="tab === 'following'" class="_content grwlizim following">
|
||||||
<div class="_section">
|
<MkPagination v-slot="{items}" :pagination="followingPagination">
|
||||||
<div v-if="tab === 'featured'" class="_content grwlizim featured">
|
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
||||||
<MkPagination v-slot="{items}" :pagination="featuredPagination">
|
</MkPagination>
|
||||||
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
|
||||||
</MkPagination>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="tab === 'following'" class="_content grwlizim following">
|
|
||||||
<MkPagination v-slot="{items}" :pagination="followingPagination">
|
|
||||||
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
|
||||||
</MkPagination>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="tab === 'owned'" class="_content grwlizim owned">
|
|
||||||
<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
|
|
||||||
<MkPagination v-slot="{items}" :pagination="ownedPagination">
|
|
||||||
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
|
||||||
</MkPagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-else-if="tab === 'owned'" class="_content grwlizim owned">
|
||||||
|
<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
|
||||||
|
<MkPagination v-slot="{items}" :pagination="ownedPagination">
|
||||||
|
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
|
||||||
|
</MkPagination>
|
||||||
|
</div>
|
||||||
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import MkChannelPreview from '@/components/channel-preview.vue';
|
import MkChannelPreview from '@/components/channel-preview.vue';
|
||||||
import MkPagination from '@/components/ui/pagination.vue';
|
import MkPagination from '@/components/ui/pagination.vue';
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import MkTab from '@/components/tab.vue';
|
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
MkChannelPreview, MkPagination, MkButton, MkTab
|
MkChannelPreview, MkPagination, MkButton,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
[symbols.PAGE_INFO]: {
|
[symbols.PAGE_INFO]: computed(() => ({
|
||||||
title: this.$ts.channel,
|
title: this.$ts.channel,
|
||||||
icon: 'fas fa-satellite-dish',
|
icon: 'fas fa-satellite-dish',
|
||||||
action: {
|
bg: 'var(--bg)',
|
||||||
|
actions: [{
|
||||||
icon: 'fas fa-plus',
|
icon: 'fas fa-plus',
|
||||||
handler: this.create
|
text: this.$ts.create,
|
||||||
}
|
handler: this.create,
|
||||||
},
|
}],
|
||||||
|
tabs: [{
|
||||||
|
active: this.tab === 'featured',
|
||||||
|
title: this.$ts._channel.featured,
|
||||||
|
icon: 'fas fa-fire-alt',
|
||||||
|
onClick: () => { this.tab = 'featured'; },
|
||||||
|
}, {
|
||||||
|
active: this.tab === 'following',
|
||||||
|
title: this.$ts._channel.following,
|
||||||
|
icon: 'fas fa-heart',
|
||||||
|
onClick: () => { this.tab = 'following'; },
|
||||||
|
}, {
|
||||||
|
active: this.tab === 'owned',
|
||||||
|
title: this.$ts._channel.owned,
|
||||||
|
icon: 'fas fa-edit',
|
||||||
|
onClick: () => { this.tab = 'owned'; },
|
||||||
|
},]
|
||||||
|
})),
|
||||||
tab: 'featured',
|
tab: 'featured',
|
||||||
featuredPagination: {
|
featuredPagination: {
|
||||||
endpoint: 'channels/featured',
|
endpoint: 'channels/featured',
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="jmelgwjh">
|
<div class="jmelgwjh">
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
|
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
@ -33,16 +32,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkSpacer :content-max="800">
|
<MkSpacer :content-max="800">
|
||||||
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
|
<XNotes ref="notes" :pagination="pagination"/>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
@ -29,15 +28,5 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkSpacer :content-max="800">
|
<MkSpacer :content-max="800">
|
||||||
<XNotes :pagination="pagination" @before="before()" @after="after()"/>
|
<XNotes :pagination="pagination"/>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
@ -28,15 +27,5 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkSpacer :content-max="800">
|
<MkSpacer :content-max="800">
|
||||||
<XNotes :pagination="pagination" @before="before()" @after="after()"/>
|
<XNotes :pagination="pagination"/>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
@ -31,15 +30,5 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
@ -73,7 +72,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetch() {
|
fetch() {
|
||||||
Progress.start();
|
|
||||||
os.api('users/groups/show', {
|
os.api('users/groups/show', {
|
||||||
groupId: this.groupId
|
groupId: this.groupId
|
||||||
}).then(group => {
|
}).then(group => {
|
||||||
@ -82,7 +80,6 @@ export default defineComponent({
|
|||||||
userIds: this.group.userIds
|
userIds: this.group.userIds
|
||||||
}).then(users => {
|
}).then(users => {
|
||||||
this.users = users;
|
this.users = users;
|
||||||
Progress.done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
@ -68,7 +67,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
fetch() {
|
fetch() {
|
||||||
Progress.start();
|
|
||||||
os.api('users/lists/show', {
|
os.api('users/lists/show', {
|
||||||
listId: this.$route.params.list
|
listId: this.$route.params.list
|
||||||
}).then(list => {
|
}).then(list => {
|
||||||
@ -77,7 +75,6 @@ export default defineComponent({
|
|||||||
userIds: this.list.userIds
|
userIds: this.list.userIds
|
||||||
}).then(users => {
|
}).then(users => {
|
||||||
this.users = users;
|
this.users = users;
|
||||||
Progress.done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkSpacer :content-max="800">
|
<MkSpacer :content-max="800">
|
||||||
<div class="clupoqwt">
|
<div class="clupoqwt">
|
||||||
<XNotifications class="notifications" :include-types="includeTypes" :unread-only="tab === 'unread'" @before="before" @after="after"/>
|
<XNotifications class="notifications" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotifications from '@/components/notifications.vue';
|
import XNotifications from '@/components/notifications.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
@ -53,14 +52,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
},
|
|
||||||
|
|
||||||
setFilter(ev) {
|
setFilter(ev) {
|
||||||
const typeItems = notificationTypes.map(t => ({
|
const typeItems = notificationTypes.map(t => ({
|
||||||
text: this.$t(`_notification._types.${t}`),
|
text: this.$t(`_notification._types.${t}`),
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
|
<XNotes ref="notes" :pagination="pagination"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
@ -39,15 +38,5 @@ export default defineComponent({
|
|||||||
(this.$refs.notes as any).reload();
|
(this.$refs.notes as any).reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
<FormSwitch v-model="useOsNativeEmojis" class="_formBlock">{{ $ts.useOsNativeEmojis }}
|
<FormSwitch v-model="useOsNativeEmojis" class="_formBlock">{{ $ts.useOsNativeEmojis }}
|
||||||
<div><Mfm :key="useOsNativeEmojis" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
|
<div><Mfm :key="useOsNativeEmojis" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
|
||||||
</FormSwitch>
|
</FormSwitch>
|
||||||
|
<FormSwitch v-model="disableDrawer" class="_formBlock">{{ $ts.disableDrawer }}</FormSwitch>
|
||||||
|
|
||||||
<FormRadios v-model="fontSize" class="_formBlock">
|
<FormRadios v-model="fontSize" class="_formBlock">
|
||||||
<template #label>{{ $ts.fontSize }}</template>
|
<template #label>{{ $ts.fontSize }}</template>
|
||||||
@ -76,13 +77,6 @@
|
|||||||
<FormSwitch v-model="defaultSideView">{{ $ts.openInSideView }}</FormSwitch>
|
<FormSwitch v-model="defaultSideView">{{ $ts.openInSideView }}</FormSwitch>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormSelect v-model="chatOpenBehavior" class="_formBlock">
|
|
||||||
<template #label>{{ $ts.chatOpenBehavior }}</template>
|
|
||||||
<option value="page">{{ $ts.showInPage }}</option>
|
|
||||||
<option value="window">{{ $ts.openInWindow }}</option>
|
|
||||||
<option value="popout">{{ $ts.popout }}</option>
|
|
||||||
</FormSelect>
|
|
||||||
|
|
||||||
<FormLink to="/settings/deck" class="_formBlock">{{ $ts.deck }}</FormLink>
|
<FormLink to="/settings/deck" class="_formBlock">{{ $ts.deck }}</FormLink>
|
||||||
|
|
||||||
<FormLink to="/settings/custom-css" class="_formBlock"><template #icon><i class="fas fa-code"></i></template>{{ $ts.customCss }}</FormLink>
|
<FormLink to="/settings/custom-css" class="_formBlock"><template #icon><i class="fas fa-code"></i></template>{{ $ts.customCss }}</FormLink>
|
||||||
@ -140,6 +134,7 @@ export default defineComponent({
|
|||||||
showGapBetweenNotesInTimeline: defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'),
|
showGapBetweenNotesInTimeline: defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'),
|
||||||
disableAnimatedMfm: defaultStore.makeGetterSetter('animatedMfm', v => !v, v => !v),
|
disableAnimatedMfm: defaultStore.makeGetterSetter('animatedMfm', v => !v, v => !v),
|
||||||
useOsNativeEmojis: defaultStore.makeGetterSetter('useOsNativeEmojis'),
|
useOsNativeEmojis: defaultStore.makeGetterSetter('useOsNativeEmojis'),
|
||||||
|
disableDrawer: defaultStore.makeGetterSetter('disableDrawer'),
|
||||||
disableShowingAnimatedImages: defaultStore.makeGetterSetter('disableShowingAnimatedImages'),
|
disableShowingAnimatedImages: defaultStore.makeGetterSetter('disableShowingAnimatedImages'),
|
||||||
loadRawImages: defaultStore.makeGetterSetter('loadRawImages'),
|
loadRawImages: defaultStore.makeGetterSetter('loadRawImages'),
|
||||||
imageNewTab: defaultStore.makeGetterSetter('imageNewTab'),
|
imageNewTab: defaultStore.makeGetterSetter('imageNewTab'),
|
||||||
@ -147,7 +142,6 @@ export default defineComponent({
|
|||||||
disablePagesScript: defaultStore.makeGetterSetter('disablePagesScript'),
|
disablePagesScript: defaultStore.makeGetterSetter('disablePagesScript'),
|
||||||
showFixedPostForm: defaultStore.makeGetterSetter('showFixedPostForm'),
|
showFixedPostForm: defaultStore.makeGetterSetter('showFixedPostForm'),
|
||||||
defaultSideView: defaultStore.makeGetterSetter('defaultSideView'),
|
defaultSideView: defaultStore.makeGetterSetter('defaultSideView'),
|
||||||
chatOpenBehavior: ColdDeviceStorage.makeGetterSetter('chatOpenBehavior'),
|
|
||||||
instanceTicker: defaultStore.makeGetterSetter('instanceTicker'),
|
instanceTicker: defaultStore.makeGetterSetter('instanceTicker'),
|
||||||
enableInfiniteScroll: defaultStore.makeGetterSetter('enableInfiniteScroll'),
|
enableInfiniteScroll: defaultStore.makeGetterSetter('enableInfiniteScroll'),
|
||||||
useReactionPickerForContextMenu: defaultStore.makeGetterSetter('useReactionPickerForContextMenu'),
|
useReactionPickerForContextMenu: defaultStore.makeGetterSetter('useReactionPickerForContextMenu'),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="_formRoot">
|
<div class="_formRoot">
|
||||||
<div v-panel class="rfqxtzch _formBlock">
|
<div v-adaptive-border class="rfqxtzch _panel _formBlock">
|
||||||
<div class="toggle">
|
<div class="toggle">
|
||||||
<div class="toggleWrapper">
|
<div class="toggleWrapper">
|
||||||
<input id="dn" v-model="darkMode" type="checkbox" class="dn"/>
|
<input id="dn" v-model="darkMode" type="checkbox" class="dn"/>
|
||||||
|
@ -31,12 +31,15 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
os.apiWithDialog('signup-pending', {
|
await os.alert({
|
||||||
code: this.code,
|
type: 'info',
|
||||||
}).then(res => {
|
text: this.$t('clickToFinishEmailVerification', { ok: this.$ts.gotIt }),
|
||||||
login(res.i, '/');
|
|
||||||
});
|
});
|
||||||
|
const res = await os.apiWithDialog('signup-pending', {
|
||||||
|
code: this.code,
|
||||||
|
});
|
||||||
|
login(res.i, '/');
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<XNotes ref="notes" class="_content" :pagination="pagination" @before="before" @after="after"/>
|
<XNotes ref="notes" class="_content" :pagination="pagination"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
|
|
||||||
@ -43,15 +42,5 @@ export default defineComponent({
|
|||||||
(this.$refs.notes as any).reload();
|
(this.$refs.notes as any).reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
class="tl"
|
class="tl"
|
||||||
:src="src"
|
:src="src"
|
||||||
:sound="true"
|
:sound="true"
|
||||||
@before="before()"
|
|
||||||
@after="after()"
|
|
||||||
@queue="queueUpdated"
|
@queue="queueUpdated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -21,7 +19,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import XPostForm from '@/components/post-form.vue';
|
import XPostForm from '@/components/post-form.vue';
|
||||||
import { scroll } from '@/scripts/scroll';
|
import { scroll } from '@/scripts/scroll';
|
||||||
@ -118,14 +115,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
},
|
|
||||||
|
|
||||||
queueUpdated(q) {
|
queueUpdated(q) {
|
||||||
this.queue = q;
|
this.queue = q;
|
||||||
},
|
},
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
src="list"
|
src="list"
|
||||||
:list="listId"
|
:list="listId"
|
||||||
:sound="true"
|
:sound="true"
|
||||||
@before="before()"
|
|
||||||
@after="after()"
|
|
||||||
@queue="queueUpdated"
|
@queue="queueUpdated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -17,7 +15,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
import { defineComponent, defineAsyncComponent, computed } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XTimeline from '@/components/timeline.vue';
|
import XTimeline from '@/components/timeline.vue';
|
||||||
import { scroll } from '@/scripts/scroll';
|
import { scroll } from '@/scripts/scroll';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
@ -76,14 +73,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
},
|
|
||||||
|
|
||||||
queueUpdated(q) {
|
queueUpdated(q) {
|
||||||
this.queue = q;
|
this.queue = q;
|
||||||
},
|
},
|
||||||
|
@ -205,7 +205,6 @@ import MkFolder from '@/components/ui/folder.vue';
|
|||||||
import MkRemoteCaution from '@/components/remote-caution.vue';
|
import MkRemoteCaution from '@/components/remote-caution.vue';
|
||||||
import MkTab from '@/components/tab.vue';
|
import MkTab from '@/components/tab.vue';
|
||||||
import MkInfo from '@/components/ui/info.vue';
|
import MkInfo from '@/components/ui/info.vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import * as Acct from 'misskey-js/built/acct';
|
import * as Acct from 'misskey-js/built/acct';
|
||||||
import { getScrollPosition } from '@/scripts/scroll';
|
import { getScrollPosition } from '@/scripts/scroll';
|
||||||
import { getUserMenu } from '@/scripts/get-user-menu';
|
import { getUserMenu } from '@/scripts/get-user-menu';
|
||||||
@ -328,13 +327,10 @@ export default defineComponent({
|
|||||||
fetch() {
|
fetch() {
|
||||||
if (this.acct == null) return;
|
if (this.acct == null) return;
|
||||||
this.user = null;
|
this.user = null;
|
||||||
Progress.start();
|
|
||||||
os.api('users/show', Acct.parse(this.acct)).then(user => {
|
os.api('users/show', Acct.parse(this.acct)).then(user => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
}).finally(() => {
|
|
||||||
Progress.done();
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
export default {
|
|
||||||
start: () => {
|
|
||||||
// TODO
|
|
||||||
},
|
|
||||||
done: () => {
|
|
||||||
// TODO
|
|
||||||
},
|
|
||||||
set: val => {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,4 +1,4 @@
|
|||||||
import { Ref, ref, watch } from 'vue';
|
import { Ref, ref, watch, onUnmounted } from 'vue';
|
||||||
|
|
||||||
export function useTooltip(
|
export function useTooltip(
|
||||||
elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>,
|
elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>,
|
||||||
@ -18,6 +18,9 @@ export function useTooltip(
|
|||||||
const open = () => {
|
const open = () => {
|
||||||
close();
|
close();
|
||||||
if (!isHovering) return;
|
if (!isHovering) return;
|
||||||
|
if (elRef.value == null) return;
|
||||||
|
const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el;
|
||||||
|
if (!document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため
|
||||||
|
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
onShow(showing);
|
onShow(showing);
|
||||||
@ -69,9 +72,14 @@ export function useTooltip(
|
|||||||
el.addEventListener('mouseleave', onMouseleave, { passive: true });
|
el.addEventListener('mouseleave', onMouseleave, { passive: true });
|
||||||
el.addEventListener('touchstart', onTouchstart, { passive: true });
|
el.addEventListener('touchstart', onTouchstart, { passive: true });
|
||||||
el.addEventListener('touchend', onTouchend, { passive: true });
|
el.addEventListener('touchend', onTouchend, { passive: true });
|
||||||
|
el.addEventListener('click', close, { passive: true });
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
flush: 'post',
|
flush: 'post',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
|||||||
where: 'device',
|
where: 'device',
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
disableDrawer: {
|
||||||
|
where: 'device',
|
||||||
|
default: false
|
||||||
|
},
|
||||||
useBlurEffectForModal: {
|
useBlurEffectForModal: {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
default: true
|
default: true
|
||||||
@ -241,7 +245,6 @@ export class ColdDeviceStorage {
|
|||||||
lightTheme: require('@/themes/l-light.json5') as Theme,
|
lightTheme: require('@/themes/l-light.json5') as Theme,
|
||||||
darkTheme: require('@/themes/d-dark.json5') as Theme,
|
darkTheme: require('@/themes/d-dark.json5') as Theme,
|
||||||
syncDeviceDarkMode: true,
|
syncDeviceDarkMode: true,
|
||||||
chatOpenBehavior: 'page' as 'page' | 'window' | 'popout',
|
|
||||||
plugins: [] as Plugin[],
|
plugins: [] as Plugin[],
|
||||||
mediaVolume: 0.5,
|
mediaVolume: 0.5,
|
||||||
sound_masterVolume: 0.3,
|
sound_masterVolume: 0.3,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
declare var self: ServiceWorkerGlobalScope;
|
declare var self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
import { getNoteSummary } from '@/scripts/get-note-summary';
|
|
||||||
import * as misskey from 'misskey-js';
|
import * as misskey from 'misskey-js';
|
||||||
|
|
||||||
function getUserName(user: misskey.entities.User): string {
|
function getUserName(user: misskey.entities.User): string {
|
||||||
@ -26,37 +25,37 @@ export default async function(type, data, i18n): Promise<[string, NotificationOp
|
|||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case 'mention':
|
case 'mention':
|
||||||
return [i18n.t('_notification.youGotMention', { name: getUserName(data.user) }), {
|
return [i18n.t('_notification.youGotMention', { name: getUserName(data.user) }), {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'reply':
|
case 'reply':
|
||||||
return [i18n.t('_notification.youGotReply', { name: getUserName(data.user) }), {
|
return [i18n.t('_notification.youGotReply', { name: getUserName(data.user) }), {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'renote':
|
case 'renote':
|
||||||
return [i18n.t('_notification.youRenoted', { name: getUserName(data.user) }), {
|
return [i18n.t('_notification.youRenoted', { name: getUserName(data.user) }), {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'quote':
|
case 'quote':
|
||||||
return [i18n.t('_notification.youGotQuote', { name: getUserName(data.user) }), {
|
return [i18n.t('_notification.youGotQuote', { name: getUserName(data.user) }), {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'reaction':
|
case 'reaction':
|
||||||
return [`${data.reaction} ${getUserName(data.user)}`, {
|
return [`${data.reaction} ${getUserName(data.user)}`, {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
case 'pollVote':
|
case 'pollVote':
|
||||||
return [i18n.t('_notification.youGotPoll', { name: getUserName(data.user) }), {
|
return [i18n.t('_notification.youGotPoll', { name: getUserName(data.user) }), {
|
||||||
body: getNoteSummary(data.note, i18n.locale),
|
body: data.note.text,
|
||||||
icon: data.user.avatarUrl
|
icon: data.user.avatarUrl
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
@ -170,6 +170,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover, &.active {
|
&:hover, &.active {
|
||||||
|
color: var(--accent);
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
@ -283,8 +285,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
width: 100%;
|
width: auto;
|
||||||
border-radius: 0;
|
height: 100%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.post {
|
&.post {
|
||||||
@ -296,8 +300,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.post:before {
|
&.post:before {
|
||||||
width: calc(100% - 32px);
|
width: calc(100% - 28px);
|
||||||
height: calc(100% - 32px);
|
height: auto;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
@ -41,15 +40,5 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
@ -38,15 +37,5 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
|
||||||
before() {
|
|
||||||
Progress.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
after() {
|
|
||||||
Progress.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -56,6 +56,7 @@ module.exports = {
|
|||||||
'object-curly-spacing': ['error', 'always'],
|
'object-curly-spacing': ['error', 'always'],
|
||||||
'space-infix-ops': ['error'],
|
'space-infix-ops': ['error'],
|
||||||
'space-before-blocks': ['error', 'always'],
|
'space-before-blocks': ['error', 'always'],
|
||||||
|
'@typescript-eslint/no-unnecessary-condition': ['error'],
|
||||||
'@typescript-eslint/no-var-requires': ['warn'],
|
'@typescript-eslint/no-var-requires': ['warn'],
|
||||||
'@typescript-eslint/no-inferrable-types': ['warn'],
|
'@typescript-eslint/no-inferrable-types': ['warn'],
|
||||||
'@typescript-eslint/no-empty-function': ['off'],
|
'@typescript-eslint/no-empty-function': ['off'],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user