summaryrefslogtreecommitdiff
path: root/packages/frontend-shared
diff options
context:
space:
mode:
authorかっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>2024-09-10 18:39:53 +0900
committerGitHub <noreply@github.com>2024-09-10 18:39:53 +0900
commit837a8e15d893a670ab2ce51b3ec87e6b62a51da7 (patch)
tree0b651782db2bf440f1c789606d6367226f2e2253 /packages/frontend-shared
parentDev: cypressをdev containerで実行可に(e2e-dev-container) (#14526) (diff)
downloadsharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.tar.gz
sharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.tar.bz2
sharkey-837a8e15d893a670ab2ce51b3ec87e6b62a51da7.zip
refactor(frontend): frontend-embed/src/to-be-sharedを共通化 (#14536)
* refactor(frontend): shouldCollapsedを共通化 * refactor(frontend): config.js, worker-multi-dispatch.js, intl-const.jsを共通化 * fix(frontend-shared): fix type error * refactor(frontend): is-link.jsと、同一の振る舞いをする記述を共通化 * fix * fix lint * lint fixes
Diffstat (limited to 'packages/frontend-shared')
-rw-r--r--packages/frontend-shared/@types/global.d.ts25
-rw-r--r--packages/frontend-shared/eslint.config.js6
-rw-r--r--packages/frontend-shared/js/collapsed.ts22
-rw-r--r--packages/frontend-shared/js/config.ts28
-rw-r--r--packages/frontend-shared/js/emoji-base.ts4
-rw-r--r--packages/frontend-shared/js/intl-const.ts51
-rw-r--r--packages/frontend-shared/js/is-link.ts12
-rw-r--r--packages/frontend-shared/js/worker-multi-dispatch.ts86
-rw-r--r--packages/frontend-shared/tsconfig.json7
9 files changed, 238 insertions, 3 deletions
diff --git a/packages/frontend-shared/@types/global.d.ts b/packages/frontend-shared/@types/global.d.ts
new file mode 100644
index 0000000000..4b8d679e75
--- /dev/null
+++ b/packages/frontend-shared/@types/global.d.ts
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type FIXME = any;
+
+declare const _LANGS_: string[][];
+declare const _VERSION_: string;
+declare const _ENV_: string;
+declare const _DEV_: boolean;
+declare const _PERF_PREFIX_: string;
+declare const _DATA_TRANSFER_DRIVE_FILE_: string;
+declare const _DATA_TRANSFER_DRIVE_FOLDER_: string;
+declare const _DATA_TRANSFER_DECK_COLUMN_: string;
+
+// for dev-mode
+declare const _LANGS_FULL_: string[][];
+
+// TagCanvas
+interface Window {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ TagCanvas: any;
+}
diff --git a/packages/frontend-shared/eslint.config.js b/packages/frontend-shared/eslint.config.js
index a15fb29e37..cd4641a270 100644
--- a/packages/frontend-shared/eslint.config.js
+++ b/packages/frontend-shared/eslint.config.js
@@ -14,7 +14,11 @@ export default [
},
...pluginVue.configs['flat/recommended'],
{
- files: ['js/**/*.{ts,vue}', '**/*.vue'],
+ files: [
+ '@types/**/*.ts',
+ 'js/**/*.ts',
+ '**/*.vue',
+ ],
languageOptions: {
globals: {
...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])),
diff --git a/packages/frontend-shared/js/collapsed.ts b/packages/frontend-shared/js/collapsed.ts
new file mode 100644
index 0000000000..af1f88cb73
--- /dev/null
+++ b/packages/frontend-shared/js/collapsed.ts
@@ -0,0 +1,22 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import * as Misskey from 'misskey-js';
+
+export function shouldCollapsed(note: Misskey.entities.Note, urls: string[]): boolean {
+ const collapsed = note.cw == null && (
+ (note.text != null && (
+ (note.text.includes('$[x2')) ||
+ (note.text.includes('$[x3')) ||
+ (note.text.includes('$[x4')) ||
+ (note.text.includes('$[scale')) ||
+ (note.text.split('\n').length > 9) ||
+ (note.text.length > 500) ||
+ (urls.length >= 4)
+ )) || (note.files != null && note.files.length >= 5)
+ );
+
+ return collapsed;
+}
diff --git a/packages/frontend-shared/js/config.ts b/packages/frontend-shared/js/config.ts
new file mode 100644
index 0000000000..ae1dcae10b
--- /dev/null
+++ b/packages/frontend-shared/js/config.ts
@@ -0,0 +1,28 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import type { Locale } from '../../../locales/index.js';
+
+// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+const address = new URL(document.querySelector<HTMLMetaElement>('meta[property="instance_url"]')?.content || location.href);
+const siteName = document.querySelector<HTMLMetaElement>('meta[property="og:site_name"]')?.content;
+
+export const host = address.host;
+export const hostname = address.hostname;
+export const url = address.origin;
+export const apiUrl = location.origin + '/api';
+export const wsOrigin = location.origin;
+export const lang = localStorage.getItem('lang') ?? 'en-US';
+export const langs = _LANGS_;
+const preParseLocale = localStorage.getItem('locale');
+export let locale: Locale = preParseLocale ? JSON.parse(preParseLocale) : null;
+export const version = _VERSION_;
+export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName;
+export const ui = localStorage.getItem('ui');
+export const debug = localStorage.getItem('debug') === 'true';
+
+export function updateLocale(newLocale: Locale): void {
+ locale = newLocale;
+}
diff --git a/packages/frontend-shared/js/emoji-base.ts b/packages/frontend-shared/js/emoji-base.ts
index a01540a3e4..5fbbc4ea84 100644
--- a/packages/frontend-shared/js/emoji-base.ts
+++ b/packages/frontend-shared/js/emoji-base.ts
@@ -19,7 +19,7 @@ export function char2fluentEmojiFilePath(char: string): string {
// Fluent Emojiは国旗非対応 https://github.com/microsoft/fluentui-emoji/issues/25
if (codes[0]?.startsWith('1f1')) return char2twemojiFilePath(char);
if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f');
- codes = codes.filter(x => x && x.length);
- const fileName = codes.map(x => x!.padStart(4, '0')).join('-');
+ codes = codes.filter(x => x != null && x.length > 0);
+ const fileName = (codes as string[]).map(x => x.padStart(4, '0')).join('-');
return `${fluentEmojiPngBase}/${fileName}.png`;
}
diff --git a/packages/frontend-shared/js/intl-const.ts b/packages/frontend-shared/js/intl-const.ts
new file mode 100644
index 0000000000..33b65b6e9b
--- /dev/null
+++ b/packages/frontend-shared/js/intl-const.ts
@@ -0,0 +1,51 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { lang } from '@@/js/config.js';
+
+// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
+export const versatileLang = (lang ?? 'ja-JP').replace('ja-KS', 'ja-JP');
+
+let _dateTimeFormat: Intl.DateTimeFormat;
+try {
+ _dateTimeFormat = new Intl.DateTimeFormat(versatileLang, {
+ year: 'numeric',
+ month: 'numeric',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ });
+} catch (err) {
+ console.warn(err);
+ if (_DEV_) console.log('[Intl] Fallback to en-US');
+
+ // Fallback to en-US
+ _dateTimeFormat = new Intl.DateTimeFormat('en-US', {
+ year: 'numeric',
+ month: 'numeric',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric',
+ second: 'numeric',
+ });
+}
+export const dateTimeFormat = _dateTimeFormat;
+
+export const timeZone = dateTimeFormat.resolvedOptions().timeZone;
+
+export const hemisphere = /^(australia|pacific|antarctica|indian)\//i.test(timeZone) ? 'S' : 'N';
+
+let _numberFormat: Intl.NumberFormat;
+try {
+ _numberFormat = new Intl.NumberFormat(versatileLang);
+} catch (err) {
+ console.warn(err);
+ if (_DEV_) console.log('[Intl] Fallback to en-US');
+
+ // Fallback to en-US
+ _numberFormat = new Intl.NumberFormat('en-US');
+}
+export const numberFormat = _numberFormat;
diff --git a/packages/frontend-shared/js/is-link.ts b/packages/frontend-shared/js/is-link.ts
new file mode 100644
index 0000000000..946f86400e
--- /dev/null
+++ b/packages/frontend-shared/js/is-link.ts
@@ -0,0 +1,12 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export function isLink(el: HTMLElement) {
+ if (el.tagName === 'A') return true;
+ if (el.parentElement) {
+ return isLink(el.parentElement);
+ }
+ return false;
+}
diff --git a/packages/frontend-shared/js/worker-multi-dispatch.ts b/packages/frontend-shared/js/worker-multi-dispatch.ts
new file mode 100644
index 0000000000..5d393ed1ed
--- /dev/null
+++ b/packages/frontend-shared/js/worker-multi-dispatch.ts
@@ -0,0 +1,86 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+function defaultUseWorkerNumber(prev: number) {
+ return prev + 1;
+}
+
+type WorkerNumberGetter = (prev: number, totalWorkers: number) => number;
+
+export class WorkerMultiDispatch<POST = unknown, RETURN = unknown> {
+ private symbol = Symbol('WorkerMultiDispatch');
+ private workers: Worker[] = [];
+ private terminated = false;
+ private prevWorkerNumber = 0;
+ private getUseWorkerNumber: WorkerNumberGetter;
+ private finalizationRegistry: FinalizationRegistry<symbol>;
+
+ constructor(workerConstructor: () => Worker, concurrency: number, getUseWorkerNumber = defaultUseWorkerNumber) {
+ this.getUseWorkerNumber = getUseWorkerNumber;
+ for (let i = 0; i < concurrency; i++) {
+ this.workers.push(workerConstructor());
+ }
+
+ this.finalizationRegistry = new FinalizationRegistry(() => {
+ this.terminate();
+ });
+ this.finalizationRegistry.register(this, this.symbol);
+
+ if (_DEV_) console.log('WorkerMultiDispatch: Created', this);
+ }
+
+ public postMessage(message: POST, options?: Transferable[] | StructuredSerializeOptions, useWorkerNumber: WorkerNumberGetter = this.getUseWorkerNumber) {
+ let workerNumber = useWorkerNumber(this.prevWorkerNumber, this.workers.length);
+ workerNumber = Math.abs(Math.round(workerNumber)) % this.workers.length;
+ if (_DEV_) console.log('WorkerMultiDispatch: Posting message to worker', workerNumber, useWorkerNumber);
+ this.prevWorkerNumber = workerNumber;
+
+ // 不毛だがunionをoverloadに突っ込めない
+ // https://stackoverflow.com/questions/66507585/overload-signatures-union-types-and-no-overload-matches-this-call-error
+ // https://github.com/microsoft/TypeScript/issues/14107
+ if (Array.isArray(options)) {
+ this.workers[workerNumber].postMessage(message, options);
+ } else {
+ this.workers[workerNumber].postMessage(message, options);
+ }
+ return workerNumber;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public addListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) {
+ this.workers.forEach(worker => {
+ worker.addEventListener('message', callback, options);
+ });
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ public removeListener(callback: (this: Worker, ev: MessageEvent<RETURN>) => any, options?: boolean | AddEventListenerOptions) {
+ this.workers.forEach(worker => {
+ worker.removeEventListener('message', callback, options);
+ });
+ }
+
+ public terminate() {
+ this.terminated = true;
+ if (_DEV_) console.log('WorkerMultiDispatch: Terminating', this);
+ this.workers.forEach(worker => {
+ worker.terminate();
+ });
+ this.workers = [];
+ this.finalizationRegistry.unregister(this);
+ }
+
+ public isTerminated() {
+ return this.terminated;
+ }
+
+ public getWorkers() {
+ return this.workers;
+ }
+
+ public getSymbol() {
+ return this.symbol;
+ }
+}
diff --git a/packages/frontend-shared/tsconfig.json b/packages/frontend-shared/tsconfig.json
index fa0b765534..09a8ff76aa 100644
--- a/packages/frontend-shared/tsconfig.json
+++ b/packages/frontend-shared/tsconfig.json
@@ -16,7 +16,13 @@
"experimentalDecorators": true,
"noImplicitReturns": true,
"esModuleInterop": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./*"],
+ "@@/*": ["./*"]
+ },
"typeRoots": [
+ "./@types",
"./node_modules/@types"
],
"lib": [
@@ -25,6 +31,7 @@
]
},
"include": [
+ "@types/**/*.ts",
"js/**/*"
],
"exclude": [