diff options
| author | Julia <julia@insertdomain.name> | 2025-03-02 19:54:32 +0000 |
|---|---|---|
| committer | Julia <julia@insertdomain.name> | 2025-03-02 19:54:32 +0000 |
| commit | 9e13c375c5ef4103ad5ee87fea583b154e9e16f3 (patch) | |
| tree | fe9e7b1a474e22fb0c37bd68cfd260f7ba39be74 /packages/frontend-embed/src | |
| parent | merge: pin corepack version (!885) (diff) | |
| parent | bump version (diff) | |
| download | sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.gz sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.bz2 sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.zip | |
merge: 2025.2.2 (!927)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/927
Approved-by: Marie <github@yuugi.dev>
Approved-by: Julia <julia@insertdomain.name>
Diffstat (limited to 'packages/frontend-embed/src')
| -rw-r--r-- | packages/frontend-embed/src/boot.ts | 20 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmAcct.vue | 2 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmMention.vue | 2 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmNote.vue | 9 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmNoteDetailed.vue | 9 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmNoteSimple.vue | 11 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmNoteSub.vue | 11 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmNotes.vue | 3 | ||||
| -rw-r--r-- | packages/frontend-embed/src/components/EmUrl.vue | 2 | ||||
| -rw-r--r-- | packages/frontend-embed/src/index.html | 38 | ||||
| -rw-r--r-- | packages/frontend-embed/src/theme.ts | 23 |
11 files changed, 63 insertions, 67 deletions
diff --git a/packages/frontend-embed/src/boot.ts b/packages/frontend-embed/src/boot.ts index 71a3156311..7c8336ce3f 100644 --- a/packages/frontend-embed/src/boot.ts +++ b/packages/frontend-embed/src/boot.ts @@ -15,11 +15,11 @@ import { applyTheme, assertIsTheme } from '@/theme.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; import { DI } from '@/di.js'; import { serverMetadata } from '@/server-metadata.js'; -import { url } from '@@/js/config.js'; +import { url, version, locale, lang, updateLocale, langsVersion } from '@@/js/config.js'; import { parseEmbedParams } from '@@/js/embed-page.js'; import { postMessageToParentWindow, setIframeId } from '@/post-message.js'; import { serverContext } from '@/server-context.js'; -import { i18n } from '@/i18n.js'; +import { i18n, updateI18n } from '@/i18n.js'; import type { Theme } from '@/theme.js'; @@ -69,6 +69,22 @@ if (embedParams.colorMode === 'dark') { } //#endregion +//#region Detect language & fetch translations +const localeVersion = localStorage.getItem('localeVersion'); +const localeOutdated = (localeVersion == null || localeVersion !== langsVersion || locale == null); +if (localeOutdated) { + const res = await window.fetch(`/assets/locales/${lang}.${langsVersion}.json`); + if (res.status === 200) { + const newLocale = await res.text(); + const parsedNewLocale = JSON.parse(newLocale); + localStorage.setItem('locale', newLocale); + localStorage.setItem('localeVersion', langsVersion); + updateLocale(parsedNewLocale); + updateI18n(parsedNewLocale); + } +} +//#endregion + // サイズの制限 document.documentElement.style.maxWidth = '500px'; diff --git a/packages/frontend-embed/src/components/EmAcct.vue b/packages/frontend-embed/src/components/EmAcct.vue index 6856b8272e..ff794d9b6e 100644 --- a/packages/frontend-embed/src/components/EmAcct.vue +++ b/packages/frontend-embed/src/components/EmAcct.vue @@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import * as Misskey from 'misskey-js'; -import { toUnicode } from 'punycode/'; +import { toUnicode } from 'punycode.js'; import { host as hostRaw } from '@@/js/config.js'; defineProps<{ diff --git a/packages/frontend-embed/src/components/EmMention.vue b/packages/frontend-embed/src/components/EmMention.vue index a71364237d..b5aaa95894 100644 --- a/packages/frontend-embed/src/components/EmMention.vue +++ b/packages/frontend-embed/src/components/EmMention.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { toUnicode } from 'punycode'; +import { toUnicode } from 'punycode.js'; import { } from 'vue'; import tinycolor from 'tinycolor2'; import { host as localHost } from '@@/js/config.js'; diff --git a/packages/frontend-embed/src/components/EmNote.vue b/packages/frontend-embed/src/components/EmNote.vue index 025c4c0734..bf96c557ea 100644 --- a/packages/frontend-embed/src/components/EmNote.vue +++ b/packages/frontend-embed/src/components/EmNote.vue @@ -46,11 +46,11 @@ SPDX-License-Identifier: AGPL-3.0-only <EmNoteHeader :note="appearNote" :mini="true"/> <EmInstanceTicker v-if="appearNote.user.instance != null" :instance="appearNote.user.instance"/> <div style="container-type: inline-size;"> - <p v-if="appearNote.cw != null" :class="$style.cw"> - <EmMfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'" :isBlock="true"/> + <p v-if="mergedCW != null" :class="$style.cw"> + <EmMfm v-if="mergedCW != ''" style="margin-right: 8px;" :text="mergedCW" :author="appearNote.user" :nyaize="'respect'" :isBlock="true"/> <button style="display: block; width: 100%; margin: 4px 0;" class="_buttonGray _buttonRounded" @click="showContent = !showContent">{{ showContent ? i18n.ts._cw.hide : i18n.ts._cw.show }}</button> </p> - <div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> + <div v-show="mergedCW == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]"> <div :class="$style.text"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <EmA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></EmA> @@ -109,6 +109,7 @@ import * as mfm from '@transfem-org/sfm-js'; import * as Misskey from 'misskey-js'; import { shouldCollapsed } from '@@/js/collapsed.js'; import { url } from '@@/js/config.js'; +import { computeMergedCw } from '@@/js/compute-merged-cw.js'; import I18n from '@/components/I18n.vue'; import EmNoteSub from '@/components/EmNoteSub.vue'; import EmNoteHeader from '@/components/EmNoteHeader.vue'; @@ -154,6 +155,8 @@ const parsed = computed(() => appearNote.value.text ? mfm.parse(appearNote.value const isLong = shouldCollapsed(appearNote.value, []); const collapsed = ref(appearNote.value.cw == null && isLong); const isDeleted = ref(false); + +const mergedCW = computed(() => computeMergedCw(appearNote.value)); </script> <style lang="scss" module> diff --git a/packages/frontend-embed/src/components/EmNoteDetailed.vue b/packages/frontend-embed/src/components/EmNoteDetailed.vue index c4ea9b4f2e..0961b36e35 100644 --- a/packages/frontend-embed/src/components/EmNoteDetailed.vue +++ b/packages/frontend-embed/src/components/EmNoteDetailed.vue @@ -58,11 +58,11 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </header> <div :class="[$style.noteContent, { [$style.contentCollapsed]: collapsed }]"> - <p v-if="appearNote.cw != null" :class="$style.cw"> - <EmMfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :nyaize="'respect'" :isBlock="true"/> + <p v-if="mergedCW != null" :class="$style.cw"> + <EmMfm v-if="mergedCW != ''" style="margin-right: 8px;" :text="mergedCW" :author="appearNote.user" :nyaize="'respect'" :isBlock="true"/> <button style="display: block; width: 100%; margin: 4px 0;" class="_buttonGray _buttonRounded" @click="showContent = !showContent">{{ showContent ? i18n.ts._cw.hide : i18n.ts._cw.show }}</button> </p> - <div v-show="appearNote.cw == null || showContent"> + <div v-show="mergedCW == null || showContent"> <span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span> <EmA v-if="appearNote.replyId" :class="$style.noteReplyTarget" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></EmA> <EmMfm @@ -130,6 +130,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, inject, ref } from 'vue'; import * as mfm from '@transfem-org/sfm-js'; import * as Misskey from 'misskey-js'; +import { computeMergedCw } from '@@/js/compute-merged-cw.js'; import I18n from '@/components/I18n.vue'; import EmMediaList from '@/components/EmMediaList.vue'; import EmNoteSub from '@/components/EmNoteSub.vue'; @@ -175,6 +176,8 @@ const isDeleted = ref(false); const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null; const isLong = shouldCollapsed(appearNote.value, []); const collapsed = ref(appearNote.value.cw == null && isLong); + +const mergedCW = computed(() => computeMergedCw(appearNote.value)); </script> <style lang="scss" module> diff --git a/packages/frontend-embed/src/components/EmNoteSimple.vue b/packages/frontend-embed/src/components/EmNoteSimple.vue index 83e73f9870..688758edb6 100644 --- a/packages/frontend-embed/src/components/EmNoteSimple.vue +++ b/packages/frontend-embed/src/components/EmNoteSimple.vue @@ -9,11 +9,11 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.main"> <EmNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> - <p v-if="note.cw != null" :class="$style.cw"> - <EmMfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis" :isBlock="true"/> + <p v-if="mergedCW != null" :class="$style.cw"> + <EmMfm v-if="mergedCW != ''" style="margin-right: 8px;" :text="mergedCW" :author="note.user" :nyaize="'respect'" :emojiUrls="note.emojis" :isBlock="true"/> <button style="display: block; width: 100%;" class="_buttonGray _buttonRounded" @click="showContent = !showContent">{{ showContent ? i18n.ts._cw.hide : i18n.ts._cw.show }}</button> </p> - <div v-show="note.cw == null || showContent"> + <div v-show="mergedCW == null || showContent"> <EmSubNoteContent :class="$style.text" :note="note"/> </div> </div> @@ -22,8 +22,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { computed, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { computeMergedCw } from '@@/js/compute-merged-cw.js'; import { i18n } from '@/i18n.js'; import EmAvatar from '@/components/EmAvatar.vue'; import EmNoteHeader from '@/components/EmNoteHeader.vue'; @@ -35,6 +36,8 @@ const props = defineProps<{ }>(); const showContent = ref(false); + +const mergedCW = computed(() => computeMergedCw(props.note)); </script> <style lang="scss" module> diff --git a/packages/frontend-embed/src/components/EmNoteSub.vue b/packages/frontend-embed/src/components/EmNoteSub.vue index cc379e8281..629f0bffcd 100644 --- a/packages/frontend-embed/src/components/EmNoteSub.vue +++ b/packages/frontend-embed/src/components/EmNoteSub.vue @@ -11,11 +11,11 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.body"> <EmNoteHeader :class="$style.header" :note="note" :mini="true"/> <div> - <p v-if="note.cw != null" :class="$style.cw"> - <EmMfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :nyaize="'respect'" :isBlock="true"/> + <p v-if="mergedCW != null" :class="$style.cw"> + <EmMfm v-if="mergedCW != ''" style="margin-right: 8px;" :text="mergedCW" :author="note.user" :nyaize="'respect'" :isBlock="true"/> <button style="display: block; width: 100%;" class="_buttonGray _buttonRounded" @click="showContent = !showContent">{{ showContent ? i18n.ts._cw.hide : i18n.ts._cw.show }}</button> </p> - <div v-show="note.cw == null || showContent"> + <div v-show="mergedCW == null || showContent"> <EmSubNoteContent :class="$style.text" :note="note"/> </div> </div> @@ -31,8 +31,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { computed, ref } from 'vue'; import * as Misskey from 'misskey-js'; +import { computeMergedCw } from '@@/js/compute-merged-cw.js'; import EmA from '@/components/EmA.vue'; import EmAvatar from '@/components/EmAvatar.vue'; import EmNoteHeader from '@/components/EmNoteHeader.vue'; @@ -55,6 +56,8 @@ const props = withDefaults(defineProps<{ const showContent = ref(false); const replies = ref<Misskey.entities.Note[]>([]); +const mergedCW = computed(() => computeMergedCw(props.note)); + if (props.detail) { misskeyApi('notes/children', { noteId: props.note.id, diff --git a/packages/frontend-embed/src/components/EmNotes.vue b/packages/frontend-embed/src/components/EmNotes.vue index 4211261e19..4e0ae005df 100644 --- a/packages/frontend-embed/src/components/EmNotes.vue +++ b/packages/frontend-embed/src/components/EmNotes.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template #default="{ items: notes }"> <div :class="[$style.root]"> - <EmNote v-for="note in notes" :key="note._featuredId_ || note._prId_ || note.id" :class="$style.note" :note="note"/> + <EmNote v-for="note in notes" :key="note._featuredId_ || note._prId_ || note.id" :class="$style.note" :note="note as Misskey.entities.Note"/> </div> </template> </EmPagination> @@ -24,6 +24,7 @@ import { useTemplateRef } from 'vue'; import EmNote from '@/components/EmNote.vue'; import EmPagination, { Paging } from '@/components/EmPagination.vue'; import { i18n } from '@/i18n.js'; +import * as Misskey from 'misskey-js'; withDefaults(defineProps<{ pagination: Paging; diff --git a/packages/frontend-embed/src/components/EmUrl.vue b/packages/frontend-embed/src/components/EmUrl.vue index 94424cab28..2dbbe90858 100644 --- a/packages/frontend-embed/src/components/EmUrl.vue +++ b/packages/frontend-embed/src/components/EmUrl.vue @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; -import { toUnicode as decodePunycode } from 'punycode/'; +import { toUnicode as decodePunycode } from 'punycode.js'; import EmA from './EmA.vue'; import { url as local } from '@@/js/config.js'; diff --git a/packages/frontend-embed/src/index.html b/packages/frontend-embed/src/index.html deleted file mode 100644 index d94ada5ea8..0000000000 --- a/packages/frontend-embed/src/index.html +++ /dev/null @@ -1,38 +0,0 @@ -<!-- - SPDX-FileCopyrightText: syuilo and misskey-project - SPDX-License-Identifier: AGPL-3.0-only ---> - -<!-- - 開発モードのviteはこのファイルを起点にサーバーを起動します。 - このファイルに書かれた [t]js のリンクと (s)cssのリンクと、その依存関係にあるファイルはビルドされます ---> - -<!DOCTYPE html> -<html> -<head> - <meta charset="UTF-8" /> - <title>[DEV] Loading...</title> - <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> - <meta - http-equiv="Content-Security-Policy" - content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/; - worker-src 'self'; - script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh https://cdn.jsdelivr.net; - style-src 'self' 'unsafe-inline'; - img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000; - media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000; - connect-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000 https://newassets.hcaptcha.com; - frame-src *;" - /> - <meta property="og:site_name" content="[DEV BUILD] Sharkey" /> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel='stylesheet' href='/assets/phosphor-icons/bold/style.css'> - <link rel='stylesheet' href='/static-assets/fonts/sharkey-icons/style.css'> -</head> - -<body> -<div id="sharkey_app"></div> -<script type="module" src="./boot.ts"></script> -</body> -</html> diff --git a/packages/frontend-embed/src/theme.ts b/packages/frontend-embed/src/theme.ts index 4664ad4880..680ab80167 100644 --- a/packages/frontend-embed/src/theme.ts +++ b/packages/frontend-embed/src/theme.ts @@ -75,16 +75,21 @@ function compile(theme: Theme): Record<string, string> { return getColor(theme.props[val]); } else if (val[0] === ':') { // func const parts = val.split('<'); - const func = parts.shift().substring(1); - const arg = parseFloat(parts.shift()); - const color = getColor(parts.join('<')); + const funcTxt = parts.shift(); + const argTxt = parts.shift(); - switch (func) { - case 'darken': return color.darken(arg); - case 'lighten': return color.lighten(arg); - case 'alpha': return color.setAlpha(arg); - case 'hue': return color.spin(arg); - case 'saturate': return color.saturate(arg); + if (funcTxt && argTxt) { + const func = funcTxt.substring(1); + const arg = parseFloat(argTxt); + const color = getColor(parts.join('<')); + + switch (func) { + case 'darken': return color.darken(arg); + case 'lighten': return color.lighten(arg); + case 'alpha': return color.setAlpha(arg); + case 'hue': return color.spin(arg); + case 'saturate': return color.saturate(arg); + } } } |