summaryrefslogtreecommitdiff
path: root/packages/frontend
diff options
context:
space:
mode:
authorFineArchs <133759614+FineArchs@users.noreply.github.com>2024-10-07 09:46:04 +0900
committerGitHub <noreply@github.com>2024-10-07 09:46:04 +0900
commited89b4bd94fae695959b006122603bb28b94dbc9 (patch)
tree0ba00da50f08976446f7713ec3c761ae91ad2a14 /packages/frontend
parentNew Crowdin updates (#14695) (diff)
downloadmisskey-ed89b4bd94fae695959b006122603bb28b94dbc9.tar.gz
misskey-ed89b4bd94fae695959b006122603bb28b94dbc9.tar.bz2
misskey-ed89b4bd94fae695959b006122603bb28b94dbc9.zip
refactor: 拡張機能インストールのページの一部をコンポーネントとして分離 (#14654)
* create MkExtensionInstaller.vue * annotation * add fallbacks * storybook * update annotations * Update MkExtensionInstaller.vue * use additonalInfo slot
Diffstat (limited to 'packages/frontend')
-rw-r--r--packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts83
-rw-r--r--packages/frontend/src/components/MkExtensionInstaller.vue146
-rw-r--r--packages/frontend/src/pages/install-extensions.vue117
3 files changed, 250 insertions, 96 deletions
diff --git a/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts
new file mode 100644
index 0000000000..6763f7c546
--- /dev/null
+++ b/packages/frontend/src/components/MkExtensionInstaller.stories.impl.ts
@@ -0,0 +1,83 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { StoryObj } from '@storybook/vue3';
+import MkExtensionInstaller from './MkExtensionInstaller.vue';
+import lightTheme from '@@/themes/_light.json5';
+
+export const Plugin = {
+ render(args) {
+ return {
+ components: {
+ MkExtensionInstaller,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkExtensionInstaller v-bind="props" />',
+ };
+ },
+ args: {
+ extension: {
+ type: 'plugin',
+ raw: '"do nothing"',
+ meta: {
+ name: 'do nothing plugin',
+ version: '1.0',
+ author: 'syuilo and misskey-project',
+ description: 'a plugin that does nothing',
+ permissions: ['read:account'],
+ config: {
+ 'doNothing': true,
+ },
+ },
+ },
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkExtensionInstaller>;
+
+export const Theme = {
+ render(args) {
+ return {
+ components: {
+ MkExtensionInstaller,
+ },
+ setup() {
+ return {
+ args,
+ };
+ },
+ computed: {
+ props() {
+ return {
+ ...this.args,
+ };
+ },
+ },
+ template: '<MkExtensionInstaller v-bind="props" />',
+ };
+ },
+ args: {
+ extension: {
+ type: 'theme',
+ raw: JSON.stringify(lightTheme),
+ meta: lightTheme,
+ },
+ },
+ parameters: {
+ layout: 'centered',
+ },
+} satisfies StoryObj<typeof MkExtensionInstaller>;
diff --git a/packages/frontend/src/components/MkExtensionInstaller.vue b/packages/frontend/src/components/MkExtensionInstaller.vue
new file mode 100644
index 0000000000..0f7acd69e7
--- /dev/null
+++ b/packages/frontend/src/components/MkExtensionInstaller.vue
@@ -0,0 +1,146 @@
+<!--
+SPDX-FileCopyrightText: syuilo and misskey-project
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<div class="_gaps_m" :class="$style.extInstallerRoot">
+ <div :class="$style.extInstallerIconWrapper">
+ <i v-if="isPlugin" class="ti ti-plug"></i>
+ <i v-else-if="isTheme" class="ti ti-palette"></i>
+ <!-- 拡張用? -->
+ <i v-else class="ti ti-download"></i>
+ </div>
+ <h2 :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].title }}</h2>
+ <div :class="$style.extInstallerNormDesc">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</div>
+ <MkInfo v-if="isPlugin" :warn="true">{{ i18n.ts._plugin.installWarn }}</MkInfo>
+ <FormSection>
+ <template #label>{{ i18n.ts._externalResourceInstaller[`_${extension.type}`].metaTitle }}</template>
+ <div class="_gaps_s">
+ <FormSplit>
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.name }}</template>
+ <template #value>{{ extension.meta.name }}</template>
+ </MkKeyValue>
+ <MkKeyValue>
+ <template #key>{{ i18n.ts.author }}</template>
+ <template #value>{{ extension.meta.author }}</template>
+ </MkKeyValue>
+ </FormSplit>
+ <MkKeyValue v-if="isPlugin">
+ <template #key>{{ i18n.ts.description }}</template>
+ <template #value>{{ extension.meta.description ?? i18n.ts.none }}</template>
+ </MkKeyValue>
+ <MkKeyValue v-if="isPlugin">
+ <template #key>{{ i18n.ts.version }}</template>
+ <template #value>{{ extension.meta.version }}</template>
+ </MkKeyValue>
+ <MkKeyValue v-if="isPlugin">
+ <template #key>{{ i18n.ts.permission }}</template>
+ <template #value>
+ <ul v-if="extension.meta.permissions && extension.meta.permissions.length > 0" :class="$style.extInstallerKVList">
+ <li v-for="permission in extension.meta.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
+ </ul>
+ <template v-else>{{ i18n.ts.none }}</template>
+ </template>
+ </MkKeyValue>
+ <MkKeyValue v-if="isTheme">
+ <template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template>
+ <template #value>{{ i18n.ts[extension.meta.base ?? 'none'] }}</template>
+ </MkKeyValue>
+ <MkFolder>
+ <template #icon><i class="ti ti-code"></i></template>
+ <template #label>{{ i18n.ts._plugin.viewSource }}</template>
+
+ <MkCode :code="extension.raw"/>
+ </MkFolder>
+ </div>
+ </FormSection>
+ <slot name="additionalInfo"/>
+ <div class="_buttonsCenter">
+ <MkButton primary @click="emits('confirm')"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton>
+ </div>
+</div>
+</template>
+
+<script lang="ts">
+export type Extension = {
+ type: 'plugin';
+ raw: string;
+ meta: {
+ name: string;
+ version: string;
+ author: string;
+ description?: string;
+ permissions?: string[];
+ config?: Record<string, any>;
+ };
+} | {
+ type: 'theme';
+ raw: string;
+ meta: {
+ name: string;
+ author: string;
+ base?: 'light' | 'dark';
+ };
+};
+</script>
+<script lang="ts" setup>
+import { computed } from 'vue';
+import MkButton from '@/components/MkButton.vue';
+import FormSection from '@/components/form/section.vue';
+import FormSplit from '@/components/form/split.vue';
+import MkCode from '@/components/MkCode.vue';
+import MkInfo from '@/components/MkInfo.vue';
+import MkFolder from '@/components/MkFolder.vue';
+import MkKeyValue from '@/components/MkKeyValue.vue';
+import { i18n } from '@/i18n.js';
+
+const isPlugin = computed(() => props.extension.type === 'plugin');
+const isTheme = computed(() => props.extension.type === 'theme');
+
+const props = defineProps<{
+ extension: Extension;
+}>();
+
+const emits = defineEmits<{
+ (ev: 'confirm'): void;
+}>();
+</script>
+
+<style lang="scss" module>
+.extInstallerRoot {
+ border-radius: var(--radius);
+ background: var(--panel);
+ padding: 1.5rem;
+}
+
+.extInstallerIconWrapper {
+ width: 48px;
+ height: 48px;
+ font-size: 24px;
+ line-height: 48px;
+ text-align: center;
+ border-radius: 50%;
+ margin-left: auto;
+ margin-right: auto;
+
+ background-color: var(--accentedBg);
+ color: var(--accent);
+}
+
+.extInstallerTitle {
+ font-size: 1.2rem;
+ text-align: center;
+ margin: 0;
+}
+
+.extInstallerNormDesc {
+ text-align: center;
+}
+
+.extInstallerKVList {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+</style>
diff --git a/packages/frontend/src/pages/install-extensions.vue b/packages/frontend/src/pages/install-extensions.vue
index 4bee437f65..83f16fce68 100644
--- a/packages/frontend/src/pages/install-extensions.vue
+++ b/packages/frontend/src/pages/install-extensions.vue
@@ -8,76 +8,26 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="500">
<MkLoading v-if="uiPhase === 'fetching'"/>
- <div v-else-if="uiPhase === 'confirm' && data" class="_gaps_m" :class="$style.extInstallerRoot">
- <div :class="$style.extInstallerIconWrapper">
- <i v-if="data.type === 'plugin'" class="ti ti-plug"></i>
- <i v-else-if="data.type === 'theme'" class="ti ti-palette"></i>
- <i v-else class="ti ti-download"></i>
- </div>
- <h2 :class="$style.extInstallerTitle">{{ i18n.ts._externalResourceInstaller[`_${data.type}`].title }}</h2>
- <div :class="$style.extInstallerNormDesc">{{ i18n.ts._externalResourceInstaller.checkVendorBeforeInstall }}</div>
- <MkInfo v-if="data.type === 'plugin'" :warn="true">{{ i18n.ts._plugin.installWarn }}</MkInfo>
- <FormSection>
- <template #label>{{ i18n.ts._externalResourceInstaller[`_${data.type}`].metaTitle }}</template>
- <div class="_gaps_s">
- <FormSplit>
+ <MkExtensionInstaller v-else-if="uiPhase === 'confirm' && data" :extension="data" @confirm="install()">
+ <template #additionalInfo>
+ <FormSection>
+ <template #label>{{ i18n.ts._externalResourceInstaller._vendorInfo.title }}</template>
+ <div class="_gaps_s">
<MkKeyValue>
- <template #key>{{ i18n.ts.name }}</template>
- <template #value>{{ data.meta?.name }}</template>
+ <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.endpoint }}</template>
+ <template #value><MkUrl :url="url" :showUrlPreview="false"></MkUrl></template>
</MkKeyValue>
<MkKeyValue>
- <template #key>{{ i18n.ts.author }}</template>
- <template #value>{{ data.meta?.author }}</template>
+ <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.hashVerify }}</template>
+ <template #value>
+ <!-- この画面が出ている時点でハッシュの検証には成功している -->
+ <i class="ti ti-check" style="color: var(--accent)"></i>
+ </template>
</MkKeyValue>
- </FormSplit>
- <MkKeyValue v-if="data.type === 'plugin'">
- <template #key>{{ i18n.ts.description }}</template>
- <template #value>{{ data.meta?.description }}</template>
- </MkKeyValue>
- <MkKeyValue v-if="data.type === 'plugin'">
- <template #key>{{ i18n.ts.version }}</template>
- <template #value>{{ data.meta?.version }}</template>
- </MkKeyValue>
- <MkKeyValue v-if="data.type === 'plugin'">
- <template #key>{{ i18n.ts.permission }}</template>
- <template #value>
- <ul :class="$style.extInstallerKVList">
- <li v-for="permission in data.meta?.permissions" :key="permission">{{ i18n.ts._permissions[permission] }}</li>
- </ul>
- </template>
- </MkKeyValue>
- <MkKeyValue v-if="data.type === 'theme' && data.meta?.base">
- <template #key>{{ i18n.ts._externalResourceInstaller._meta.base }}</template>
- <template #value>{{ i18n.ts[data.meta.base] }}</template>
- </MkKeyValue>
- <MkFolder>
- <template #icon><i class="ti ti-code"></i></template>
- <template #label>{{ i18n.ts._plugin.viewSource }}</template>
-
- <MkCode :code="data.raw ?? ''"/>
- </MkFolder>
- </div>
- </FormSection>
- <FormSection>
- <template #label>{{ i18n.ts._externalResourceInstaller._vendorInfo.title }}</template>
- <div class="_gaps_s">
- <MkKeyValue>
- <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.endpoint }}</template>
- <template #value><MkUrl :url="url ?? ''" :showUrlPreview="false"></MkUrl></template>
- </MkKeyValue>
- <MkKeyValue>
- <template #key>{{ i18n.ts._externalResourceInstaller._vendorInfo.hashVerify }}</template>
- <template #value>
- <!--この画面が出ている時点でハッシュの検証には成功している-->
- <i class="ti ti-check" style="color: var(--accent)"></i>
- </template>
- </MkKeyValue>
- </div>
- </FormSection>
- <div class="_buttonsCenter">
- <MkButton primary @click="install()"><i class="ti ti-check"></i> {{ i18n.ts.install }}</MkButton>
- </div>
- </div>
+ </div>
+ </FormSection>
+ </template>
+ </MkExtensionInstaller>
<div v-else-if="uiPhase === 'error'" class="_gaps_m" :class="[$style.extInstallerRoot, $style.error]">
<div :class="$style.extInstallerIconWrapper">
<i class="ti ti-circle-x"></i>
@@ -96,14 +46,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, computed, onActivated, onDeactivated, nextTick } from 'vue';
import MkLoading from '@/components/global/MkLoading.vue';
+import MkExtensionInstaller, { type Extension } from '@/components/MkExtensionInstaller.vue';
import MkButton from '@/components/MkButton.vue';
-import FormSection from '@/components/form/section.vue';
-import FormSplit from '@/components/form/split.vue';
-import MkCode from '@/components/MkCode.vue';
-import MkUrl from '@/components/global/MkUrl.vue';
-import MkInfo from '@/components/MkInfo.vue';
-import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
+import MkUrl from '@/components/global/MkUrl.vue';
+import FormSection from '@/components/form/section.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { AiScriptPluginMeta, parsePluginMeta, installPlugin } from '@/scripts/install-plugin.js';
@@ -124,24 +71,7 @@ const errorKV = ref<{
const url = ref<string | null>(null);
const hash = ref<string | null>(null);
-const data = ref<{
- type: 'plugin' | 'theme';
- raw: string;
- meta?: {
- // Plugin & Theme Common
- name: string;
- author: string;
-
- // Plugin
- description?: string;
- version?: string;
- permissions?: string[];
- config?: Record<string, any>;
-
- // Theme
- base?: 'light' | 'dark';
- };
-} | null>(null);
+const data = ref<Extension | null>(null);
function goBack(): void {
history.back();
@@ -227,7 +157,7 @@ async function fetch() {
data.value = {
type: 'theme',
meta: {
- description,
+ // description, // 使用されていない
...meta,
},
raw: res.data,
@@ -353,9 +283,4 @@ definePageMetadata(() => ({
.extInstallerNormDesc {
text-align: center;
}
-
-.extInstallerKVList {
- margin-top: 0;
- margin-bottom: 0;
-}
</style>