Merge branch 'develop' into mkjs-n
This commit is contained in:
commit
d7fe783c46
27 changed files with 3254 additions and 1002 deletions
72
locales/generateDTS.js
Normal file
72
locales/generateDTS.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
const fs = require('fs');
|
||||
const yaml = require('js-yaml');
|
||||
const ts = require('typescript');
|
||||
|
||||
function createMembers(record) {
|
||||
return Object.entries(record)
|
||||
.map(([k, v]) => ts.factory.createPropertySignature(
|
||||
undefined,
|
||||
ts.factory.createStringLiteral(k),
|
||||
undefined,
|
||||
typeof v === 'string'
|
||||
? ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
|
||||
: ts.factory.createTypeLiteralNode(createMembers(v)),
|
||||
));
|
||||
}
|
||||
|
||||
module.exports = function generateDTS() {
|
||||
const locale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8'));
|
||||
const members = createMembers(locale);
|
||||
const elements = [
|
||||
ts.factory.createInterfaceDeclaration(
|
||||
[ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
|
||||
ts.factory.createIdentifier('Locale'),
|
||||
undefined,
|
||||
undefined,
|
||||
members,
|
||||
),
|
||||
ts.factory.createVariableStatement(
|
||||
[ts.factory.createToken(ts.SyntaxKind.DeclareKeyword)],
|
||||
ts.factory.createVariableDeclarationList(
|
||||
[ts.factory.createVariableDeclaration(
|
||||
ts.factory.createIdentifier('locales'),
|
||||
undefined,
|
||||
ts.factory.createTypeLiteralNode([ts.factory.createIndexSignature(
|
||||
undefined,
|
||||
[ts.factory.createParameterDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
ts.factory.createIdentifier('lang'),
|
||||
undefined,
|
||||
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
||||
undefined,
|
||||
)],
|
||||
ts.factory.createTypeReferenceNode(
|
||||
ts.factory.createIdentifier('Locale'),
|
||||
undefined,
|
||||
),
|
||||
)]),
|
||||
undefined,
|
||||
)],
|
||||
ts.NodeFlags.Const | ts.NodeFlags.Ambient | ts.NodeFlags.ContextFlags,
|
||||
),
|
||||
),
|
||||
ts.factory.createExportAssignment(
|
||||
undefined,
|
||||
true,
|
||||
ts.factory.createIdentifier('locales'),
|
||||
),
|
||||
];
|
||||
const printed = ts.createPrinter({
|
||||
newLine: ts.NewLineKind.LineFeed,
|
||||
}).printList(
|
||||
ts.ListFormat.MultiLine,
|
||||
ts.factory.createNodeArray(elements),
|
||||
ts.createSourceFile('index.d.ts', '', ts.ScriptTarget.ESNext, true, ts.ScriptKind.TS),
|
||||
);
|
||||
|
||||
fs.writeFileSync(`${__dirname}/index.d.ts`, `/* eslint-disable */
|
||||
// This file is generated by locales/generateDTS.js
|
||||
// Do not edit this file directly.
|
||||
${printed}`, 'utf-8');
|
||||
}
|
2145
locales/index.d.ts
vendored
2145
locales/index.d.ts
vendored
File diff suppressed because it is too large
Load diff
|
@ -59,7 +59,7 @@
|
|||
"@typescript-eslint/eslint-plugin": "5.59.5",
|
||||
"@typescript-eslint/parser": "5.59.5",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "12.12.0",
|
||||
"cypress": "12.13.0",
|
||||
"eslint": "8.40.0",
|
||||
"start-server-and-test": "2.0.0"
|
||||
},
|
||||
|
|
|
@ -63,9 +63,9 @@
|
|||
"@fastify/multipart": "7.6.0",
|
||||
"@fastify/static": "6.10.1",
|
||||
"@fastify/view": "7.4.1",
|
||||
"@nestjs/common": "9.4.1",
|
||||
"@nestjs/core": "9.4.1",
|
||||
"@nestjs/testing": "9.4.1",
|
||||
"@nestjs/common": "9.4.2",
|
||||
"@nestjs/core": "9.4.2",
|
||||
"@nestjs/testing": "9.4.2",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@sinonjs/fake-timers": "10.0.2",
|
||||
"@swc/cli": "0.1.62",
|
||||
|
@ -179,11 +179,11 @@
|
|||
"@types/jsonld": "1.5.8",
|
||||
"@types/jsrsasign": "10.5.8",
|
||||
"@types/mime-types": "2.1.1",
|
||||
"@types/node": "20.2.1",
|
||||
"@types/node": "20.2.3",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.8",
|
||||
"@types/oauth": "0.9.1",
|
||||
"@types/pg": "8.6.6",
|
||||
"@types/pg": "8.10.1",
|
||||
"@types/pug": "2.0.6",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/qrcode": "1.5.0",
|
||||
|
@ -197,7 +197,7 @@
|
|||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/unzipper": "0.10.5",
|
||||
"@types/unzipper": "0.10.6",
|
||||
"@types/uuid": "9.0.1",
|
||||
"@types/vary": "1.1.0",
|
||||
"@types/web-push": "3.3.2",
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as Redis from 'ioredis';
|
|||
import { DataSource } from 'typeorm';
|
||||
import { MeiliSearch } from 'meilisearch';
|
||||
import { DI } from './di-symbols.js';
|
||||
import { loadConfig } from './config.js';
|
||||
import { Config, loadConfig } from './config.js';
|
||||
import { createPostgresDataSource } from './postgres.js';
|
||||
import { RepositoryModule } from './models/RepositoryModule.js';
|
||||
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
|
||||
|
@ -25,7 +25,7 @@ const $db: Provider = {
|
|||
|
||||
const $meilisearch: Provider = {
|
||||
provide: DI.meilisearch,
|
||||
useFactory: (config) => {
|
||||
useFactory: (config: Config) => {
|
||||
if (config.meilisearch) {
|
||||
return new MeiliSearch({
|
||||
host: `${config.meilisearch.ssl ? 'https' : 'http' }://${config.meilisearch.host}:${config.meilisearch.port}`,
|
||||
|
@ -40,7 +40,7 @@ const $meilisearch: Provider = {
|
|||
|
||||
const $redis: Provider = {
|
||||
provide: DI.redis,
|
||||
useFactory: (config) => {
|
||||
useFactory: (config: Config) => {
|
||||
return new Redis.Redis({
|
||||
port: config.redis.port,
|
||||
host: config.redis.host,
|
||||
|
@ -55,7 +55,7 @@ const $redis: Provider = {
|
|||
|
||||
const $redisForPub: Provider = {
|
||||
provide: DI.redisForPub,
|
||||
useFactory: (config) => {
|
||||
useFactory: (config: Config) => {
|
||||
const redis = new Redis.Redis({
|
||||
port: config.redisForPubsub.port,
|
||||
host: config.redisForPubsub.host,
|
||||
|
@ -71,7 +71,7 @@ const $redisForPub: Provider = {
|
|||
|
||||
const $redisForSub: Provider = {
|
||||
provide: DI.redisForSub,
|
||||
useFactory: (config) => {
|
||||
useFactory: (config: Config) => {
|
||||
const redis = new Redis.Redis({
|
||||
port: config.redisForPubsub.port,
|
||||
host: config.redisForPubsub.host,
|
||||
|
|
|
@ -160,14 +160,16 @@
|
|||
<path d="M12 9v2m0 4v.01"></path>
|
||||
<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path>
|
||||
</svg>
|
||||
<h1>An error has occurred!</h1>
|
||||
<button class="button-big" onclick="location.reload();">
|
||||
<span class="button-label-big">Refresh</span>
|
||||
<h1>Failed to load<br>読み込みに失敗しました</h1>
|
||||
<button class="button-big" onclick="location.reload(true);">
|
||||
<span class="button-label-big">Reload / リロード</span>
|
||||
</button>
|
||||
<p class="dont-worry">Don't worry, it's (probably) not your fault.</p>
|
||||
<p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p>
|
||||
<p>Update your os and browser.</p>
|
||||
<p>Disable an adblocker.</p>
|
||||
<p><b>The following actions may solve the problem. / 以下を行うと解決する可能性があります。</b></p>
|
||||
<p>Clear the browser cache / ブラウザのキャッシュをクリアする</p>
|
||||
<p>Update your os and browser / ブラウザおよびOSを最新バージョンに更新する</p>
|
||||
<p>Disable an adblocker / アドブロッカーを無効にする</p>
|
||||
<details style="color: #86b300;">
|
||||
<summary>Other options / その他のオプション</summary>
|
||||
<a href="/flush">
|
||||
<button class="button-small">
|
||||
<span class="button-label-small">Clear preferences and cache</span>
|
||||
|
@ -185,12 +187,14 @@
|
|||
<span class="button-label-small">Start the repair tool</span>
|
||||
</button>
|
||||
</a>
|
||||
</details>
|
||||
<br>
|
||||
<div id="errors"></div>
|
||||
`;
|
||||
errorsElement = document.getElementById('errors');
|
||||
}
|
||||
const detailsElement = document.createElement('details');
|
||||
detailsElement.id = 'errorInfo';
|
||||
detailsElement.innerHTML = `
|
||||
<br>
|
||||
<summary>
|
||||
|
@ -247,7 +251,7 @@
|
|||
.button-label-big {
|
||||
color: #222;
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
font-size: 1.2em;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
|
@ -267,11 +271,6 @@
|
|||
font-size: 16px;
|
||||
}
|
||||
|
||||
.dont-worry,
|
||||
#msg {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.icon-warning {
|
||||
color: #dec340;
|
||||
height: 4rem;
|
||||
|
@ -279,14 +278,15 @@
|
|||
}
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
font-size: 1.5em;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: Fira, FiraCode, monospace;
|
||||
}
|
||||
|
||||
details {
|
||||
#errorInfo {
|
||||
background: #333;
|
||||
margin-bottom: 2rem;
|
||||
padding: 0.5rem 1rem;
|
||||
|
@ -296,16 +296,16 @@
|
|||
margin: auto;
|
||||
}
|
||||
|
||||
summary {
|
||||
#errorInfo summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
summary > * {
|
||||
#errorInfo summary > * {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
details {
|
||||
#errorInfo {
|
||||
width: 50%;
|
||||
}
|
||||
`)
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"@syuilo/aiscript": "0.13.3",
|
||||
"@tabler/icons-webfont": "2.17.0",
|
||||
"@vitejs/plugin-vue": "4.2.3",
|
||||
"@vue-macros/reactivity-transform": "0.3.7",
|
||||
"@vue-macros/reactivity-transform": "0.3.8",
|
||||
"@vue/compiler-sfc": "3.3.4",
|
||||
"autosize": "6.0.1",
|
||||
"broadcast-channel": "4.20.2",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"punycode": "2.3.0",
|
||||
"querystring": "0.2.1",
|
||||
"rndstr": "1.0.0",
|
||||
"rollup": "3.22.0",
|
||||
"rollup": "3.23.0",
|
||||
"s-age": "1.1.2",
|
||||
"sanitize-html": "2.10.0",
|
||||
"sass": "1.62.1",
|
||||
|
@ -77,37 +77,37 @@
|
|||
"vuedraggable": "next"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@storybook/addon-actions": "7.0.12",
|
||||
"@storybook/addon-essentials": "7.0.12",
|
||||
"@storybook/addon-interactions": "7.0.12",
|
||||
"@storybook/addon-links": "7.0.12",
|
||||
"@storybook/addon-storysource": "7.0.12",
|
||||
"@storybook/addons": "7.0.12",
|
||||
"@storybook/blocks": "7.0.12",
|
||||
"@storybook/core-events": "7.0.12",
|
||||
"@storybook/addon-actions": "7.0.15",
|
||||
"@storybook/addon-essentials": "7.0.15",
|
||||
"@storybook/addon-interactions": "7.0.15",
|
||||
"@storybook/addon-links": "7.0.15",
|
||||
"@storybook/addon-storysource": "7.0.15",
|
||||
"@storybook/addons": "7.0.15",
|
||||
"@storybook/blocks": "7.0.15",
|
||||
"@storybook/core-events": "7.0.15",
|
||||
"@storybook/jest": "0.1.0",
|
||||
"@storybook/manager-api": "7.0.12",
|
||||
"@storybook/preview-api": "7.0.12",
|
||||
"@storybook/react": "7.0.12",
|
||||
"@storybook/react-vite": "7.0.12",
|
||||
"@storybook/manager-api": "7.0.15",
|
||||
"@storybook/preview-api": "7.0.15",
|
||||
"@storybook/react": "7.0.15",
|
||||
"@storybook/react-vite": "7.0.15",
|
||||
"@storybook/testing-library": "0.1.0",
|
||||
"@storybook/theming": "7.0.12",
|
||||
"@storybook/types": "7.0.12",
|
||||
"@storybook/vue3": "7.0.12",
|
||||
"@storybook/vue3-vite": "7.0.12",
|
||||
"@storybook/theming": "7.0.15",
|
||||
"@storybook/types": "7.0.15",
|
||||
"@storybook/vue3": "7.0.15",
|
||||
"@storybook/vue3-vite": "7.0.15",
|
||||
"@testing-library/jest-dom": "5.16.5",
|
||||
"@testing-library/vue": "7.0.0",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/estree": "1.0.1",
|
||||
"@types/gulp": "4.0.10",
|
||||
"@types/gulp-rename": "2.0.2",
|
||||
"@types/matter-js": "0.18.3",
|
||||
"@types/matter-js": "0.18.4",
|
||||
"@types/micromatch": "4.0.2",
|
||||
"@types/node": "20.2.1",
|
||||
"@types/node": "20.2.3",
|
||||
"@types/punycode": "2.1.0",
|
||||
"@types/sanitize-html": "2.9.0",
|
||||
"@types/seedrandom": "3.0.5",
|
||||
"@types/testing-library__jest-dom": "^5.14.5",
|
||||
"@types/testing-library__jest-dom": "^5.14.6",
|
||||
"@types/throttle-debounce": "5.0.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/uuid": "9.0.1",
|
||||
|
@ -117,13 +117,13 @@
|
|||
"@typescript-eslint/parser": "5.59.5",
|
||||
"@vitest/coverage-c8": "0.31.1",
|
||||
"@vue/runtime-core": "3.3.4",
|
||||
"astring": "1.8.4",
|
||||
"astring": "1.8.5",
|
||||
"chokidar-cli": "3.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "12.12.0",
|
||||
"cypress": "12.13.0",
|
||||
"eslint": "8.40.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-vue": "9.13.0",
|
||||
"eslint-plugin-vue": "9.14.0",
|
||||
"fast-glob": "3.2.12",
|
||||
"happy-dom": "9.19.2",
|
||||
"micromatch": "3.1.10",
|
||||
|
@ -133,7 +133,7 @@
|
|||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"start-server-and-test": "2.0.0",
|
||||
"storybook": "7.0.12",
|
||||
"storybook": "7.0.15",
|
||||
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
|
||||
"summaly": "github:misskey-dev/summaly",
|
||||
"vite-plugin-turbosnap": "1.0.2",
|
||||
|
|
|
@ -5,7 +5,9 @@ import '@/style.scss';
|
|||
import { mainBoot } from './boot/main-boot';
|
||||
import { subBoot } from './boot/sub-boot';
|
||||
|
||||
if (['/share', '/auth', '/miauth'].includes(location.pathname)) {
|
||||
const subBootPaths = ['/share', '/auth', '/miauth', '/signup-complete'];
|
||||
|
||||
if (subBootPaths.some(i => location.pathname === i || location.pathname.startsWith(i + '/'))) {
|
||||
subBoot();
|
||||
} else {
|
||||
mainBoot();
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
>
|
||||
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
||||
|
||||
<form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit">
|
||||
<div class="main _gaps_m">
|
||||
<MkSpacer :marginMin="20" :marginMax="28">
|
||||
<form v-if="instance.enableEmail" @submit.prevent="onSubmit">
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
||||
<template #label>{{ i18n.ts.username }}</template>
|
||||
<template #prefix>@</template>
|
||||
|
@ -20,15 +21,15 @@
|
|||
<template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton>
|
||||
</div>
|
||||
<div class="sub">
|
||||
<MkA to="/about" class="_link">{{ i18n.ts._forgotPassword.ifNoEmail }}</MkA>
|
||||
<MkButton type="submit" rounded :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton>
|
||||
|
||||
<MkInfo>{{ i18n.ts._forgotPassword.ifNoEmail }}</MkInfo>
|
||||
</div>
|
||||
</form>
|
||||
<div v-else class="bafecedb">
|
||||
<div v-else>
|
||||
{{ i18n.ts._forgotPassword.contactAdmin }}
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkModalWindow>
|
||||
</template>
|
||||
|
||||
|
@ -37,6 +38,7 @@ import { } from 'vue';
|
|||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import * as os from '@/os';
|
||||
import { instance } from '@/instance';
|
||||
import { i18n } from '@/i18n';
|
||||
|
@ -62,20 +64,3 @@ async function onSubmit() {
|
|||
dialog.close();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bafeceda {
|
||||
> .main {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
> .sub {
|
||||
border-top: solid 0.5px var(--divider);
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.bafecedb {
|
||||
padding: 24px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<div v-show="props.modelValue.length != 0" class="skeikyzd">
|
||||
<Sortable :modelValue="props.modelValue" class="files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)">
|
||||
<div v-show="props.modelValue.length != 0" :class="$style.root">
|
||||
<Sortable :modelValue="props.modelValue" :class="$style.files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)">
|
||||
<template #item="{element}">
|
||||
<div class="file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)">
|
||||
<MkDriveFileThumbnail :data-id="element.id" class="thumbnail" :file="element" fit="cover"/>
|
||||
<div v-if="element.isSensitive" class="sensitive">
|
||||
<i class="ti ti-alert-triangle icon"></i>
|
||||
<div :class="$style.file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)">
|
||||
<MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover"/>
|
||||
<div v-if="element.isSensitive" :class="$style.sensitive">
|
||||
<i class="ti ti-alert-triangle" style="margin: auto;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Sortable>
|
||||
<p class="remain">{{ 16 - props.modelValue.length }}/16</p>
|
||||
<p :class="$style.remain">{{ 16 - props.modelValue.length }}/16</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -108,16 +108,18 @@ function showFileMenu(file, ev: MouseEvent) {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.skeikyzd {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
padding: 8px 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> .files {
|
||||
.files {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
> .file {
|
||||
.file {
|
||||
position: relative;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
|
@ -125,19 +127,16 @@ function showFileMenu(file, ev: MouseEvent) {
|
|||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
cursor: move;
|
||||
|
||||
&:hover > .remove {
|
||||
display: block;
|
||||
}
|
||||
|
||||
> .thumbnail {
|
||||
.thumbnail {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
> .sensitive {
|
||||
.sensitive {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
|
@ -147,21 +146,15 @@ function showFileMenu(file, ev: MouseEvent) {
|
|||
z-index: 2;
|
||||
background: rgba(17, 17, 17, .7);
|
||||
color: #fff;
|
||||
|
||||
> .icon {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .remain {
|
||||
.remain {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
font-size: 90%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div ref="rootEl" class="meijqfqm">
|
||||
<canvas :id="idForCanvas" ref="canvasEl" class="canvas" :width="width" height="300" @contextmenu.prevent="() => {}"></canvas>
|
||||
<div :id="idForTags" ref="tagsEl" class="tags">
|
||||
<div ref="rootEl" :class="$style.root">
|
||||
<canvas :id="idForCanvas" ref="canvasEl" style="display: block;" :width="width" height="300" @contextmenu.prevent="() => {}"></canvas>
|
||||
<div :id="idForTags" ref="tagsEl" :class="$style.tags">
|
||||
<ul>
|
||||
<slot></slot>
|
||||
</ul>
|
||||
|
@ -70,21 +70,17 @@ defineExpose({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.meijqfqm {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: relative;
|
||||
overflow: clip;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
|
||||
> .canvas {
|
||||
display: block;
|
||||
}
|
||||
|
||||
> .tags {
|
||||
.tags {
|
||||
position: absolute;
|
||||
top: 999px;
|
||||
left: 999px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -46,12 +46,6 @@ const onUserRemoved = () => {
|
|||
tlComponent.pagingComponent?.reload();
|
||||
};
|
||||
|
||||
const onChangeFollowing = () => {
|
||||
if (!tlComponent.pagingComponent?.backed) {
|
||||
tlComponent.pagingComponent?.reload();
|
||||
}
|
||||
};
|
||||
|
||||
let endpoint;
|
||||
let query;
|
||||
let connection;
|
||||
|
@ -79,8 +73,6 @@ if (props.src === 'antenna') {
|
|||
connection.on('note', prepend);
|
||||
|
||||
connection2 = stream.useChannel('main');
|
||||
connection2.on('follow', onChangeFollowing);
|
||||
connection2.on('unfollow', onChangeFollowing);
|
||||
} else if (props.src === 'local') {
|
||||
endpoint = 'notes/local-timeline';
|
||||
query = {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="adhpbeou">
|
||||
<div class="label" @click="focus"><slot name="label"></slot></div>
|
||||
<div class="content">
|
||||
<div>
|
||||
<div :class="$style.label" @click="focus"><slot name="label"></slot></div>
|
||||
<div :class="$style.content">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="caption"><slot name="caption"></slot></div>
|
||||
<div :class="$style.caption"><slot name="caption"></slot></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -16,9 +16,8 @@ function focus() {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.adhpbeou {
|
||||
> .label {
|
||||
<style lang="scss" module>
|
||||
.label {
|
||||
font-size: 0.85em;
|
||||
padding: 0 0 8px 0;
|
||||
user-select: none;
|
||||
|
@ -28,7 +27,7 @@ function focus() {
|
|||
}
|
||||
}
|
||||
|
||||
> .caption {
|
||||
.caption {
|
||||
font-size: 0.85em;
|
||||
padding: 8px 0 0 0;
|
||||
color: var(--fgTransparentWeak);
|
||||
|
@ -37,5 +36,4 @@ function focus() {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { markRaw } from 'vue';
|
||||
import type { Locale } from '../../../locales';
|
||||
import { locale } from '@/config';
|
||||
import { I18n } from '@/scripts/i18n';
|
||||
|
||||
export const i18n = markRaw(new I18n(locale));
|
||||
export const i18n = markRaw(new I18n<Locale>(locale));
|
||||
|
||||
export function updateI18n(newLocale) {
|
||||
i18n.ts = newLocale;
|
||||
|
|
|
@ -2,22 +2,28 @@
|
|||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700">
|
||||
<div v-if="tab === 'featured'" class="rknalgpo">
|
||||
<div v-if="tab === 'featured'">
|
||||
<MkPagination v-slot="{items}" :pagination="featuredPagesPagination">
|
||||
<MkPagePreview v-for="page in items" :key="page.id" class="ckltabjg" :page="page"/>
|
||||
<div class="_gaps">
|
||||
<MkPagePreview v-for="page in items" :key="page.id" :page="page"/>
|
||||
</div>
|
||||
</MkPagination>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'my'" class="rknalgpo my">
|
||||
<div v-else-if="tab === 'my'" class="_gaps">
|
||||
<MkButton class="new" @click="create()"><i class="ti ti-plus"></i></MkButton>
|
||||
<MkPagination v-slot="{items}" :pagination="myPagesPagination">
|
||||
<MkPagePreview v-for="page in items" :key="page.id" class="ckltabjg" :page="page"/>
|
||||
<div class="_gaps">
|
||||
<MkPagePreview v-for="page in items" :key="page.id" :page="page"/>
|
||||
</div>
|
||||
</MkPagination>
|
||||
</div>
|
||||
|
||||
<div v-else-if="tab === 'liked'" class="rknalgpo">
|
||||
<div v-else-if="tab === 'liked'">
|
||||
<MkPagination v-slot="{items}" :pagination="likedPagesPagination">
|
||||
<MkPagePreview v-for="like in items" :key="like.page.id" class="ckltabjg" :page="like.page"/>
|
||||
<div class="_gaps">
|
||||
<MkPagePreview v-for="like in items" :key="like.page.id" :page="like.page"/>
|
||||
</div>
|
||||
</MkPagination>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
|
@ -79,21 +85,3 @@ definePageMetadata(computed(() => ({
|
|||
icon: 'ti ti-note',
|
||||
})));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rknalgpo {
|
||||
&.my .ckltabjg:first-child {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.ckltabjg:not(:last-child) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.ckltabjg:not(:last-child) {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
</template>
|
||||
<template #default="{items}">
|
||||
<div class="_gaps">
|
||||
<div v-for="token in items" :key="token.id" class="_panel bfomjevm">
|
||||
<img v-if="token.iconUrl" class="icon" :src="token.iconUrl" alt=""/>
|
||||
<div class="body">
|
||||
<div class="name">{{ token.name }}</div>
|
||||
<div class="description">{{ token.description }}</div>
|
||||
<div v-for="token in items" :key="token.id" class="_panel" :class="$style.app">
|
||||
<img v-if="token.iconUrl" :class="$style.appIcon" :src="token.iconUrl" alt=""/>
|
||||
<div :class="$style.appBody">
|
||||
<div :class="$style.appName">{{ token.name }}</div>
|
||||
<div>{{ token.description }}</div>
|
||||
<MkKeyValue oneline>
|
||||
<template #key>{{ i18n.ts.installedDate }}</template>
|
||||
<template #value><MkTime :time="token.createdAt"/></template>
|
||||
|
@ -28,7 +28,7 @@
|
|||
<li v-for="p in token.permission" :key="p">{{ i18n.t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</details>
|
||||
<div class="actions">
|
||||
<div>
|
||||
<MkButton inline danger @click="revoke(token)"><i class="ti ti-trash"></i></MkButton>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,12 +75,13 @@ definePageMetadata({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bfomjevm {
|
||||
<style lang="scss" module>
|
||||
.app {
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
> .icon {
|
||||
.appIcon {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
margin: 0 12px 0 0;
|
||||
|
@ -89,13 +90,12 @@ definePageMetadata({
|
|||
border-radius: 8px;
|
||||
}
|
||||
|
||||
> .body {
|
||||
.appBody {
|
||||
width: calc(100% - 62px);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> .name {
|
||||
.appName {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,37 +1,83 @@
|
|||
<template>
|
||||
<div :class="$style.root">
|
||||
<MkAnimBg style="position: fixed; top: 0;"/>
|
||||
<div :class="$style.formContainer">
|
||||
<form :class="$style.form" class="_panel" @submit.prevent="submit()">
|
||||
<div :class="$style.banner">
|
||||
<i class="ti ti-user-check"></i>
|
||||
</div>
|
||||
<div class="_gaps_m" style="padding: 32px;">
|
||||
<div>{{ i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }) }}</div>
|
||||
<div>
|
||||
{{ i18n.ts.processing }}
|
||||
<MkButton gradate large rounded type="submit" :disabled="submitting" data-cy-admin-ok style="margin: 0 auto;">
|
||||
{{ submitting ? i18n.ts.processing : i18n.ts.gotIt }}<MkEllipsis v-if="submitting"/>
|
||||
</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||
import { login } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import * as os from '@/os';
|
||||
|
||||
let submitting = $ref(false);
|
||||
|
||||
const props = defineProps<{
|
||||
code: string;
|
||||
}>();
|
||||
|
||||
onMounted(async () => {
|
||||
await os.alert({
|
||||
type: 'info',
|
||||
text: i18n.t('clickToFinishEmailVerification', { ok: i18n.ts.gotIt }),
|
||||
});
|
||||
const res = await os.apiWithDialog('signup-pending', {
|
||||
function submit() {
|
||||
if (submitting) return;
|
||||
submitting = true;
|
||||
|
||||
os.api('signup-pending', {
|
||||
code: props.code,
|
||||
});
|
||||
login(res.i, '/');
|
||||
});
|
||||
}).then(res => {
|
||||
return login(res.i, '/');
|
||||
}).catch(() => {
|
||||
submitting = false;
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts.signup,
|
||||
icon: 'ti ti-user',
|
||||
os.alert({
|
||||
type: 'error',
|
||||
text: i18n.ts.somethingHappened,
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
}
|
||||
|
||||
.formContainer {
|
||||
min-height: 100svh;
|
||||
padding: 32px 32px 64px 32px;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border-radius: var(--radius);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
||||
overflow: clip;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
font-size: 26px;
|
||||
background-color: var(--accentedBg);
|
||||
color: var(--accent);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -34,7 +34,3 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -56,6 +56,3 @@ definePageMetadata(computed(() => user ? {
|
|||
avatar: user,
|
||||
} : null));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
|
|
@ -56,6 +56,3 @@ definePageMetadata(computed(() => user ? {
|
|||
avatar: user,
|
||||
} : null));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<div>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="user">
|
||||
<XHome v-if="tab === 'home'" :user="user"/>
|
||||
<XTimeline v-else-if="tab === 'notes'" :user="user"/>
|
||||
|
@ -16,7 +15,6 @@
|
|||
</div>
|
||||
<MkError v-else-if="error" @retry="fetchUser()"/>
|
||||
<MkLoading v-else/>
|
||||
</Transition>
|
||||
</div>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
@ -118,14 +116,3 @@ definePageMetadata(computed(() => user ? {
|
|||
},
|
||||
} : null));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.125s ease;
|
||||
}
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock class="mkw-clock">
|
||||
<div class="vubelbmv" :class="widgetProps.size">
|
||||
<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label a abbrev">{{ tzAbbrev }}</div>
|
||||
<MkContainer :naked="widgetProps.transparent" :showHeader="false" data-cy-mkw-clock>
|
||||
<div :class="[$style.root, $style[widgetProps.size]]">
|
||||
<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace" :class="[$style.label, $style.a]">{{ tzAbbrev }}</div>
|
||||
<MkAnalogClock
|
||||
class="clock"
|
||||
:class="$style.clock"
|
||||
:thickness="widgetProps.thickness"
|
||||
:offset="tzOffset"
|
||||
:graduations="widgetProps.graduations"
|
||||
|
@ -11,8 +11,8 @@
|
|||
:twentyfour="widgetProps.twentyFour"
|
||||
:sAnimation="widgetProps.sAnimation"
|
||||
/>
|
||||
<MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :showS="false" :offset="tzOffset"/>
|
||||
<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label d offset">{{ tzOffsetLabel }}</div>
|
||||
<MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" :class="[$style.label, $style.c]" class="_monospace" :showS="false" :offset="tzOffset"/>
|
||||
<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace" :class="[$style.label, $style.d]">{{ tzOffsetLabel }}</div>
|
||||
</div>
|
||||
</MkContainer>
|
||||
</template>
|
||||
|
@ -140,39 +140,10 @@ defineExpose<WidgetComponentExpose>({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vubelbmv {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: relative;
|
||||
|
||||
> .label {
|
||||
position: absolute;
|
||||
opacity: 0.7;
|
||||
|
||||
&.a {
|
||||
top: 14px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
&.b {
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
&.c {
|
||||
bottom: 14px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
&.d {
|
||||
bottom: 14px;
|
||||
right: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
> .clock {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&.small {
|
||||
padding: 12px;
|
||||
|
||||
|
@ -197,4 +168,33 @@ defineExpose<WidgetComponentExpose>({
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
position: absolute;
|
||||
opacity: 0.7;
|
||||
|
||||
&.a {
|
||||
top: 14px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
&.b {
|
||||
top: 14px;
|
||||
right: 14px;
|
||||
}
|
||||
|
||||
&.c {
|
||||
bottom: 14px;
|
||||
left: 14px;
|
||||
}
|
||||
|
||||
&.d {
|
||||
bottom: 14px;
|
||||
right: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.clock {
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -72,7 +72,3 @@ defineExpose<WidgetComponentExpose>({
|
|||
id: props.widget ? props.widget.id : null,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<template>
|
||||
<div data-cy-mkw-onlineUsers class="mkw-onlineUsers" :class="{ _panel: !widgetProps.transparent, pad: !widgetProps.transparent }">
|
||||
<I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" textTag="span" class="text">
|
||||
<template #n><b>{{ number(onlineUsersCount) }}</b></template>
|
||||
<div data-cy-mkw-onlineUsers :class="[$style.root, { _panel: !widgetProps.transparent, [$style.pad]: !widgetProps.transparent }]">
|
||||
<span :class="$style.text">
|
||||
<I18n v-if="onlineUsersCount" :src="i18n.ts.onlineUsersCount" textTag="span">
|
||||
<template #n><b style="color: #41b781;">{{ number(onlineUsersCount) }}</b></template>
|
||||
</I18n>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -55,22 +57,16 @@ defineExpose<WidgetComponentExpose>({
|
|||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mkw-onlineUsers {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
text-align: center;
|
||||
|
||||
&.pad {
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
> .text {
|
||||
::v-deep(b) {
|
||||
color: #41b781;
|
||||
}
|
||||
|
||||
::v-deep(span) {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
color: var(--fgTransparentWeak);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
<template>
|
||||
<svg class="hsalcinq" viewBox="0 0 1 1" preserveAspectRatio="none">
|
||||
<svg :class="$style.root" viewBox="0 0 1 1" preserveAspectRatio="none">
|
||||
<circle
|
||||
:r="r"
|
||||
cx="50%" cy="50%"
|
||||
fill="none"
|
||||
stroke-width="0.1"
|
||||
stroke="rgba(0, 0, 0, 0.05)"
|
||||
:class="$style.circle"
|
||||
/>
|
||||
<circle
|
||||
:r="r"
|
||||
|
@ -16,7 +17,7 @@
|
|||
stroke-width="0.1"
|
||||
:stroke="color"
|
||||
/>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle">{{ (value * 100).toFixed(0) }}%</text>
|
||||
<text x="50%" y="50%" dy="0.05" text-anchor="middle" :class="$style.text">{{ (value * 100).toFixed(0) }}%</text>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
|
@ -33,20 +34,20 @@ const color = $computed(() => `hsl(${180 - (props.value * 180)}, 80%, 70%)`);
|
|||
const strokeDashoffset = $computed(() => (1 - props.value) * (Math.PI * (r * 2)));
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.hsalcinq {
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
> circle {
|
||||
.circle {
|
||||
transform-origin: center;
|
||||
transform: rotate(-90deg);
|
||||
transition: stroke-dashoffset 0.5s ease;
|
||||
}
|
||||
|
||||
> text {
|
||||
.text {
|
||||
font-size: 0.15px;
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,6 +6,7 @@ import { type UserConfig, defineConfig } from 'vite';
|
|||
import ReactivityTransform from '@vue-macros/reactivity-transform/vite';
|
||||
|
||||
import locales from '../../locales';
|
||||
import generateDTS from '../../locales/generateDTS';
|
||||
import meta from '../../package.json';
|
||||
import pluginJson5 from './vite.json5';
|
||||
|
||||
|
@ -64,6 +65,10 @@ export function getConfig(): UserConfig {
|
|||
}),
|
||||
]
|
||||
: [],
|
||||
{
|
||||
name: 'locale:generateDTS',
|
||||
buildStart: generateDTS,
|
||||
},
|
||||
],
|
||||
|
||||
resolve: {
|
||||
|
|
1303
pnpm-lock.yaml
1303
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue