From 2398a8013ddaf0b28df9b8433a62f63aee4abe03 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:19:36 +0900 Subject: [PATCH] wip --- packages/embed/.gitignore | 1 + packages/embed/eslint.config.js | 95 ++++ packages/embed/package.json | 141 ++++++ .../src/_embed_boot_.ts => embed/src/boot.ts} | 5 +- .../src}/components/EmMediaBanner.vue | 0 .../src}/components/EmMediaImage.vue | 0 .../src}/components/EmMediaList.vue | 0 .../src}/components/EmMediaVideo.vue | 0 .../embed => embed/src}/components/EmNote.vue | 0 .../src}/components/EmNoteDetailed.vue | 0 .../src}/components/EmNotes.vue | 0 .../src}/components/EmTimelineContainer.vue | 0 .../src/embed => embed/src}/pages/clip.vue | 0 .../src/embed => embed/src}/pages/note.vue | 0 .../src/embed => embed/src}/pages/tag.vue | 0 .../src}/pages/user-timeline.vue | 0 .../src/embed => embed/src}/router.ts | 0 packages/embed/src/style.scss | 433 ++++++++++++++++++ .../{frontend/src/embed => embed/src}/ui.vue | 0 packages/embed/tsconfig.json | 53 +++ packages/embed/vue-shims.d.ts | 6 + packages/frontend/src/embed/style.scss | 19 - 22 files changed, 731 insertions(+), 22 deletions(-) create mode 100644 packages/embed/.gitignore create mode 100644 packages/embed/eslint.config.js create mode 100644 packages/embed/package.json rename packages/{frontend/src/_embed_boot_.ts => embed/src/boot.ts} (94%) rename packages/{frontend/src/embed => embed/src}/components/EmMediaBanner.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmMediaImage.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmMediaList.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmMediaVideo.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmNote.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmNoteDetailed.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmNotes.vue (100%) rename packages/{frontend/src/embed => embed/src}/components/EmTimelineContainer.vue (100%) rename packages/{frontend/src/embed => embed/src}/pages/clip.vue (100%) rename packages/{frontend/src/embed => embed/src}/pages/note.vue (100%) rename packages/{frontend/src/embed => embed/src}/pages/tag.vue (100%) rename packages/{frontend/src/embed => embed/src}/pages/user-timeline.vue (100%) rename packages/{frontend/src/embed => embed/src}/router.ts (100%) create mode 100644 packages/embed/src/style.scss rename packages/{frontend/src/embed => embed/src}/ui.vue (100%) create mode 100644 packages/embed/tsconfig.json create mode 100644 packages/embed/vue-shims.d.ts delete mode 100644 packages/frontend/src/embed/style.scss diff --git a/packages/embed/.gitignore b/packages/embed/.gitignore new file mode 100644 index 0000000000..1aa0ac14e8 --- /dev/null +++ b/packages/embed/.gitignore @@ -0,0 +1 @@ +/storybook-static diff --git a/packages/embed/eslint.config.js b/packages/embed/eslint.config.js new file mode 100644 index 0000000000..dd8f03dac5 --- /dev/null +++ b/packages/embed/eslint.config.js @@ -0,0 +1,95 @@ +import globals from 'globals'; +import tsParser from '@typescript-eslint/parser'; +import parser from 'vue-eslint-parser'; +import pluginVue from 'eslint-plugin-vue'; +import pluginMisskey from '@misskey-dev/eslint-plugin'; +import sharedConfig from '../shared/eslint.config.js'; + +export default [ + ...sharedConfig, + { + files: ['src/**/*.vue'], + ...pluginMisskey.configs.typescript, + }, + ...pluginVue.configs['flat/recommended'], + { + files: ['src/**/*.{ts,vue}'], + languageOptions: { + globals: { + ...Object.fromEntries(Object.entries(globals.node).map(([key]) => [key, 'off'])), + ...globals.browser, + + // Node.js + module: false, + require: false, + __dirname: false, + + // Misskey + _DEV_: false, + _LANGS_: false, + _VERSION_: false, + _ENV_: false, + _PERF_PREFIX_: false, + _DATA_TRANSFER_DRIVE_FILE_: false, + _DATA_TRANSFER_DRIVE_FOLDER_: false, + _DATA_TRANSFER_DECK_COLUMN_: false, + }, + parser, + parserOptions: { + extraFileExtensions: ['.vue'], + parser: tsParser, + project: ['./tsconfig.json'], + sourceType: 'module', + tsconfigRootDir: import.meta.dirname, + }, + }, + rules: { + '@typescript-eslint/no-empty-interface': ['error', { + allowSingleExtends: true, + }], + // window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため + // e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため + 'id-denylist': ['error', 'window', 'e'], + 'no-shadow': ['warn'], + 'vue/attributes-order': ['error', { + alphabetical: false, + }], + 'vue/no-use-v-if-with-v-for': ['error', { + allowUsingIterationVar: false, + }], + 'vue/no-ref-as-operand': 'error', + 'vue/no-multi-spaces': ['error', { + ignoreProperties: false, + }], + 'vue/no-v-html': 'warn', + 'vue/order-in-components': 'error', + 'vue/html-indent': ['warn', 'tab', { + attribute: 1, + baseIndent: 0, + closeBracket: 0, + alignAttributesVertically: true, + ignores: [], + }], + 'vue/html-closing-bracket-spacing': ['warn', { + startTag: 'never', + endTag: 'never', + selfClosingTag: 'never', + }], + 'vue/multi-word-component-names': 'warn', + 'vue/require-v-for-key': 'warn', + 'vue/no-unused-components': 'warn', + 'vue/no-unused-vars': 'warn', + 'vue/no-dupe-keys': 'warn', + 'vue/valid-v-for': 'warn', + 'vue/return-in-computed-property': 'warn', + 'vue/no-setup-props-reactivity-loss': 'warn', + 'vue/max-attributes-per-line': 'off', + 'vue/html-self-closing': 'off', + 'vue/singleline-html-element-content-newline': 'off', + 'vue/v-on-event-hyphenation': ['error', 'never', { + autofix: true, + }], + 'vue/attribute-hyphenation': ['error', 'never'], + }, + }, +]; diff --git a/packages/embed/package.json b/packages/embed/package.json new file mode 100644 index 0000000000..dad545a9c2 --- /dev/null +++ b/packages/embed/package.json @@ -0,0 +1,141 @@ +{ + "name": "embed", + "private": true, + "type": "module", + "scripts": { + "watch": "vite", + "dev": "vite --config vite.config.local-dev.ts --debug hmr", + "build": "vite build", + "storybook-dev": "nodemon --verbose --watch src --ext \"mdx,ts,vue\" --ignore \"*.stories.ts\" --exec \"pnpm build-storybook-pre && pnpm exec storybook dev -p 6006 --ci\"", + "build-storybook-pre": "(tsc -p .storybook || echo done.) && node .storybook/generate.js && node .storybook/preload-locale.js && node .storybook/preload-theme.js", + "build-storybook": "pnpm build-storybook-pre && storybook build --webpack-stats-json storybook-static", + "chromatic": "chromatic", + "test": "vitest --run --globals", + "test-and-coverage": "vitest --run --coverage --globals", + "typecheck": "vue-tsc --noEmit", + "eslint": "eslint --quiet \"src/**/*.{ts,vue}\"", + "lint": "pnpm typecheck && pnpm eslint" + }, + "dependencies": { + "@discordapp/twemoji": "15.0.3", + "@github/webauthn-json": "2.1.1", + "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", + "@misskey-dev/browser-image-resizer": "2024.1.0", + "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "5.0.7", + "@rollup/pluginutils": "5.1.0", + "@syuilo/aiscript": "0.19.0", + "@tabler/icons-webfont": "3.3.0", + "@twemoji/parser": "15.1.1", + "@vitejs/plugin-vue": "5.1.0", + "@vue/compiler-sfc": "3.4.37", + "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.11", + "astring": "1.8.6", + "broadcast-channel": "7.0.0", + "buraha": "0.0.1", + "canvas-confetti": "1.9.3", + "chart.js": "4.4.3", + "chartjs-adapter-date-fns": "3.0.0", + "chartjs-chart-matrix": "2.0.1", + "chartjs-plugin-gradient": "0.6.1", + "chartjs-plugin-zoom": "2.0.1", + "chromatic": "11.5.6", + "compare-versions": "6.1.1", + "cropperjs": "2.0.0-rc.1", + "date-fns": "2.30.0", + "escape-regexp": "0.0.1", + "estree-walker": "3.0.3", + "eventemitter3": "5.0.1", + "idb-keyval": "6.2.1", + "insert-text-at-cursor": "0.3.0", + "is-file-animated": "1.0.2", + "json5": "2.2.3", + "matter-js": "0.19.0", + "mfm-js": "0.24.0", + "misskey-bubble-game": "workspace:*", + "misskey-js": "workspace:*", + "misskey-reversi": "workspace:*", + "photoswipe": "5.4.4", + "punycode": "2.3.1", + "rollup": "4.19.1", + "sanitize-html": "2.13.0", + "sass": "1.77.8", + "shiki": "1.12.0", + "strict-event-emitter-types": "2.0.0", + "textarea-caret": "3.1.0", + "three": "0.167.0", + "throttle-debounce": "5.0.2", + "tinycolor2": "1.6.0", + "tsc-alias": "1.8.10", + "tsconfig-paths": "4.2.0", + "typescript": "5.5.4", + "uuid": "10.0.0", + "v-code-diff": "1.12.0", + "vite": "5.3.5", + "vue": "3.4.37", + "vuedraggable": "next" + }, + "devDependencies": { + "@misskey-dev/summaly": "5.1.0", + "@storybook/addon-actions": "8.2.6", + "@storybook/addon-essentials": "8.2.6", + "@storybook/addon-interactions": "8.2.6", + "@storybook/addon-links": "8.2.6", + "@storybook/addon-mdx-gfm": "8.2.6", + "@storybook/addon-storysource": "8.2.6", + "@storybook/blocks": "8.2.6", + "@storybook/components": "8.2.6", + "@storybook/core-events": "8.2.6", + "@storybook/manager-api": "8.2.6", + "@storybook/preview-api": "8.2.6", + "@storybook/react": "8.2.6", + "@storybook/react-vite": "8.2.6", + "@storybook/test": "8.2.6", + "@storybook/theming": "8.2.6", + "@storybook/types": "8.2.6", + "@storybook/vue3": "8.2.6", + "@storybook/vue3-vite": "8.1.11", + "@testing-library/vue": "8.1.0", + "@types/escape-regexp": "0.0.3", + "@types/estree": "1.0.5", + "@types/matter-js": "0.19.7", + "@types/micromatch": "4.0.9", + "@types/node": "20.14.12", + "@types/punycode": "2.1.4", + "@types/sanitize-html": "2.11.0", + "@types/seedrandom": "3.0.8", + "@types/throttle-debounce": "5.0.2", + "@types/tinycolor2": "1.4.6", + "@types/uuid": "10.0.0", + "@types/ws": "8.5.11", + "@typescript-eslint/eslint-plugin": "7.17.0", + "@typescript-eslint/parser": "7.17.0", + "@vitest/coverage-v8": "1.6.0", + "@vue/runtime-core": "3.4.37", + "acorn": "8.12.1", + "cross-env": "7.0.3", + "cypress": "13.13.1", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-vue": "9.27.0", + "fast-glob": "3.3.2", + "happy-dom": "10.0.3", + "intersection-observer": "0.12.2", + "micromatch": "4.0.7", + "msw": "2.3.4", + "msw-storybook-addon": "2.0.3", + "nodemon": "3.1.4", + "prettier": "3.3.3", + "react": "18.3.1", + "react-dom": "18.3.1", + "seedrandom": "3.0.5", + "start-server-and-test": "2.0.4", + "storybook": "8.2.6", + "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", + "vite-plugin-turbosnap": "1.0.3", + "vitest": "1.6.0", + "vitest-fetch-mock": "0.2.2", + "vue-component-type-helpers": "2.0.29", + "vue-eslint-parser": "9.4.3", + "vue-tsc": "2.0.29" + } +} diff --git a/packages/frontend/src/_embed_boot_.ts b/packages/embed/src/boot.ts similarity index 94% rename from packages/frontend/src/_embed_boot_.ts rename to packages/embed/src/boot.ts index 13ee965fed..c9248e0dcd 100644 --- a/packages/frontend/src/_embed_boot_.ts +++ b/packages/embed/src/boot.ts @@ -7,7 +7,6 @@ import 'vite/modulepreload-polyfill'; import '@/style.scss'; -import '@/embed/style.scss'; import { createApp, defineAsyncComponent } from 'vue'; import type { CommonBootOptions } from '@/boot/common.js'; import { common } from '@/boot/common.js'; @@ -15,7 +14,7 @@ import { setIframeId, postMessageToParentWindow } from '@/scripts/post-message.j import { parseEmbedParams } from '@/scripts/embed-page.js'; import { defaultStore } from '@/store.js'; import { useRouter } from '@/router/supplier.js'; -import { createEmbedRouter } from '@/embed/router.js'; +import { createEmbedRouter } from '@/router.js'; const bootOptions: Partial = { routerFactory: createEmbedRouter, @@ -52,7 +51,7 @@ window.addEventListener('message', setIframeIdHandler); // 起動 common(() => createApp( - defineAsyncComponent(() => import('@/embed/ui.vue')), + defineAsyncComponent(() => import('@/ui.vue')), ), bootOptions).then(async ({ app }) => { //#region Embed Provide app.provide('EMBED_PAGE', true); diff --git a/packages/frontend/src/embed/components/EmMediaBanner.vue b/packages/embed/src/components/EmMediaBanner.vue similarity index 100% rename from packages/frontend/src/embed/components/EmMediaBanner.vue rename to packages/embed/src/components/EmMediaBanner.vue diff --git a/packages/frontend/src/embed/components/EmMediaImage.vue b/packages/embed/src/components/EmMediaImage.vue similarity index 100% rename from packages/frontend/src/embed/components/EmMediaImage.vue rename to packages/embed/src/components/EmMediaImage.vue diff --git a/packages/frontend/src/embed/components/EmMediaList.vue b/packages/embed/src/components/EmMediaList.vue similarity index 100% rename from packages/frontend/src/embed/components/EmMediaList.vue rename to packages/embed/src/components/EmMediaList.vue diff --git a/packages/frontend/src/embed/components/EmMediaVideo.vue b/packages/embed/src/components/EmMediaVideo.vue similarity index 100% rename from packages/frontend/src/embed/components/EmMediaVideo.vue rename to packages/embed/src/components/EmMediaVideo.vue diff --git a/packages/frontend/src/embed/components/EmNote.vue b/packages/embed/src/components/EmNote.vue similarity index 100% rename from packages/frontend/src/embed/components/EmNote.vue rename to packages/embed/src/components/EmNote.vue diff --git a/packages/frontend/src/embed/components/EmNoteDetailed.vue b/packages/embed/src/components/EmNoteDetailed.vue similarity index 100% rename from packages/frontend/src/embed/components/EmNoteDetailed.vue rename to packages/embed/src/components/EmNoteDetailed.vue diff --git a/packages/frontend/src/embed/components/EmNotes.vue b/packages/embed/src/components/EmNotes.vue similarity index 100% rename from packages/frontend/src/embed/components/EmNotes.vue rename to packages/embed/src/components/EmNotes.vue diff --git a/packages/frontend/src/embed/components/EmTimelineContainer.vue b/packages/embed/src/components/EmTimelineContainer.vue similarity index 100% rename from packages/frontend/src/embed/components/EmTimelineContainer.vue rename to packages/embed/src/components/EmTimelineContainer.vue diff --git a/packages/frontend/src/embed/pages/clip.vue b/packages/embed/src/pages/clip.vue similarity index 100% rename from packages/frontend/src/embed/pages/clip.vue rename to packages/embed/src/pages/clip.vue diff --git a/packages/frontend/src/embed/pages/note.vue b/packages/embed/src/pages/note.vue similarity index 100% rename from packages/frontend/src/embed/pages/note.vue rename to packages/embed/src/pages/note.vue diff --git a/packages/frontend/src/embed/pages/tag.vue b/packages/embed/src/pages/tag.vue similarity index 100% rename from packages/frontend/src/embed/pages/tag.vue rename to packages/embed/src/pages/tag.vue diff --git a/packages/frontend/src/embed/pages/user-timeline.vue b/packages/embed/src/pages/user-timeline.vue similarity index 100% rename from packages/frontend/src/embed/pages/user-timeline.vue rename to packages/embed/src/pages/user-timeline.vue diff --git a/packages/frontend/src/embed/router.ts b/packages/embed/src/router.ts similarity index 100% rename from packages/frontend/src/embed/router.ts rename to packages/embed/src/router.ts diff --git a/packages/embed/src/style.scss b/packages/embed/src/style.scss new file mode 100644 index 0000000000..02b09633e7 --- /dev/null +++ b/packages/embed/src/style.scss @@ -0,0 +1,433 @@ +@charset "utf-8"; + +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +html { + background-color: transparent; + color-scheme: light dark; + color: var(--fg); + accent-color: var(--accent); + overflow: clip; + overflow-wrap: break-word; + font-family: 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif; + font-size: 14px; + line-height: 1.35; + text-size-adjust: 100%; + tab-size: 2; + -webkit-text-size-adjust: 100%; + + &, * { + scrollbar-color: var(--scrollbarHandle) transparent; + scrollbar-width: thin; + + &::-webkit-scrollbar { + width: 6px; + height: 6px; + } + + &::-webkit-scrollbar-track { + background: inherit; + } + + &::-webkit-scrollbar-thumb { + background: var(--scrollbarHandle); + + &:hover { + background: var(--scrollbarHandleHover); + } + + &:active { + background: var(--accent); + } + } + } + + &:not(.embed) { + &.f-1 { + font-size: 15px; + } + + &.f-2 { + font-size: 16px; + } + + &.f-3 { + font-size: 17px; + } + + &.useSystemFont { + font-family: system-ui; + } + } +} + +html, body { + height: 100%; + touch-action: manipulation; + margin: 0; + padding: 0; + scroll-behavior: smooth; +} + +#misskey_app { + height: 100%; +} + +a { + text-decoration: none; + cursor: pointer; + color: inherit; + tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; + + &:focus-visible { + outline-offset: 2px; + } + + &:hover { + text-decoration: underline; + } + + &[target="_blank"] { + -webkit-touch-callout: default; + } +} + +rt { + white-space: initial; +} + +:focus-visible { + outline: var(--focus) solid 2px; + outline-offset: -2px; + + &:hover { + text-decoration: none; + } +} + +.ti { + width: 1.28em; + vertical-align: -12%; + line-height: 1em; + + &::before { + font-size: 128%; + } +} + +.ti-fw { + display: inline-block; + text-align: center; +} + +._button { + @extend ._noSelect; + appearance: none; + display: inline-block; + padding: 0; + margin: 0; // for Safari + background: none; + border: none; + cursor: pointer; + color: inherit; + touch-action: manipulation; + tap-highlight-color: transparent; + -webkit-tap-highlight-color: transparent; + font-size: 1em; + font-family: inherit; + line-height: inherit; + max-width: 100%; + + &:disabled { + opacity: 0.5; + cursor: default; + } +} + +._buttonPrimary { + @extend ._button; + color: var(--fgOnAccent); + background: var(--accent); + + &:not(:disabled):hover { + background: hsl(from var(--accent) h s calc(l + 5)); + } + + &:not(:disabled):active { + background: hsl(from var(--accent) h s calc(l - 5)); + } +} + +._buttonGradate { + @extend ._buttonPrimary; + color: var(--fgOnAccent); + background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB)); + + &:not(:disabled):hover { + background: linear-gradient(90deg, hsl(from var(--accent) h s calc(l + 5)), hsl(from var(--accent) h s calc(l + 5))); + } + + &:not(:disabled):active { + background: linear-gradient(90deg, hsl(from var(--accent) h s calc(l + 5)), hsl(from var(--accent) h s calc(l + 5))); + } +} + +._help { + color: var(--accent); + cursor: help; +} + +._textButton { + @extend ._button; + color: var(--accent); + + &:focus-visible { + outline-offset: 2px; + } + + &:not(:disabled):hover { + text-decoration: underline; + } +} + +._panel { + background: var(--panel); + border-radius: var(--radius); + overflow: clip; +} + +._margin { + margin: var(--margin) 0; +} + +._gaps_m { + display: flex; + flex-direction: column; + gap: 1.5em; +} + +._gaps_s { + display: flex; + flex-direction: column; + gap: 0.75em; +} + +._gaps { + display: flex; + flex-direction: column; + gap: var(--margin); +} + +._buttons { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +._buttonsCenter { + @extend ._buttons; + + justify-content: center; +} + +._borderButton { + @extend ._button; + display: block; + width: 100%; + padding: 10px; + box-sizing: border-box; + text-align: center; + border: solid 0.5px var(--divider); + border-radius: var(--radius); + + &:active { + border-color: var(--accent); + } +} + +._popup { + background: var(--popup); + border-radius: var(--radius); + contain: content; +} + +._acrylic { + background: var(--acrylicPanel); + -webkit-backdrop-filter: var(--blur, blur(15px)); + backdrop-filter: var(--blur, blur(15px)); +} + +._fullinfo { + padding: 64px 32px; + text-align: center; + + > img { + vertical-align: bottom; + height: 128px; + margin-bottom: 16px; + border-radius: 16px; + } +} + +._link { + color: var(--link); +} + +._caption { + font-size: 0.8em; + opacity: 0.7; +} + +._monospace { + font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace !important; +} + +// MFM ----------------------------- + +._mfm_blur_ { + filter: blur(6px); + transition: filter 0.3s; + + &:hover { + filter: blur(0px); + } +} + +.mfm-x2 { + --mfm-zoom-size: 200%; +} + +.mfm-x3 { + --mfm-zoom-size: 400%; +} + +.mfm-x4 { + --mfm-zoom-size: 600%; +} + +.mfm-x2, .mfm-x3, .mfm-x4 { + font-size: var(--mfm-zoom-size); + + .mfm-x2, .mfm-x3, .mfm-x4 { + /* only half effective */ + font-size: calc(var(--mfm-zoom-size) / 2 + 50%); + + .mfm-x2, .mfm-x3, .mfm-x4 { + /* disabled */ + font-size: 100%; + } + } +} + +._mfm_rainbow_fallback_ { + background-image: linear-gradient(to right, rgb(255, 0, 0) 0%, rgb(255, 165, 0) 17%, rgb(255, 255, 0) 33%, rgb(0, 255, 0) 50%, rgb(0, 255, 255) 67%, rgb(0, 0, 255) 83%, rgb(255, 0, 255) 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +@keyframes mfm-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +@keyframes mfm-spinX { + 0% { transform: perspective(128px) rotateX(0deg); } + 100% { transform: perspective(128px) rotateX(360deg); } +} + +@keyframes mfm-spinY { + 0% { transform: perspective(128px) rotateY(0deg); } + 100% { transform: perspective(128px) rotateY(360deg); } +} + +@keyframes mfm-jump { + 0% { transform: translateY(0); } + 25% { transform: translateY(-16px); } + 50% { transform: translateY(0); } + 75% { transform: translateY(-8px); } + 100% { transform: translateY(0); } +} + +@keyframes mfm-bounce { + 0% { transform: translateY(0) scale(1, 1); } + 25% { transform: translateY(-16px) scale(1, 1); } + 50% { transform: translateY(0) scale(1, 1); } + 75% { transform: translateY(0) scale(1.5, 0.75); } + 100% { transform: translateY(0) scale(1, 1); } +} + +// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-twitch { + 0% { transform: translate(7px, -2px) } + 5% { transform: translate(-3px, 1px) } + 10% { transform: translate(-7px, -1px) } + 15% { transform: translate(0px, -1px) } + 20% { transform: translate(-8px, 6px) } + 25% { transform: translate(-4px, -3px) } + 30% { transform: translate(-4px, -6px) } + 35% { transform: translate(-8px, -8px) } + 40% { transform: translate(4px, 6px) } + 45% { transform: translate(-3px, 1px) } + 50% { transform: translate(2px, -10px) } + 55% { transform: translate(-7px, 0px) } + 60% { transform: translate(-2px, 4px) } + 65% { transform: translate(3px, -8px) } + 70% { transform: translate(6px, 7px) } + 75% { transform: translate(-7px, -2px) } + 80% { transform: translate(-7px, -8px) } + 85% { transform: translate(9px, 3px) } + 90% { transform: translate(-3px, -2px) } + 95% { transform: translate(-10px, 2px) } + 100% { transform: translate(-2px, -6px) } +} + +// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`; +// let css = ''; +// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; } +@keyframes mfm-shake { + 0% { transform: translate(-3px, -1px) rotate(-8deg) } + 5% { transform: translate(0px, -1px) rotate(-10deg) } + 10% { transform: translate(1px, -3px) rotate(0deg) } + 15% { transform: translate(1px, 1px) rotate(11deg) } + 20% { transform: translate(-2px, 1px) rotate(1deg) } + 25% { transform: translate(-1px, -2px) rotate(-2deg) } + 30% { transform: translate(-1px, 2px) rotate(-3deg) } + 35% { transform: translate(2px, 1px) rotate(6deg) } + 40% { transform: translate(-2px, -3px) rotate(-9deg) } + 45% { transform: translate(0px, -1px) rotate(-12deg) } + 50% { transform: translate(1px, 2px) rotate(10deg) } + 55% { transform: translate(0px, -3px) rotate(8deg) } + 60% { transform: translate(1px, -1px) rotate(8deg) } + 65% { transform: translate(0px, -1px) rotate(-7deg) } + 70% { transform: translate(-1px, -3px) rotate(6deg) } + 75% { transform: translate(0px, -2px) rotate(4deg) } + 80% { transform: translate(-2px, -1px) rotate(3deg) } + 85% { transform: translate(1px, -3px) rotate(-10deg) } + 90% { transform: translate(1px, 0px) rotate(3deg) } + 95% { transform: translate(-2px, 0px) rotate(-3deg) } + 100% { transform: translate(2px, 1px) rotate(2deg) } +} + +@keyframes mfm-rubberBand { + from { transform: scale3d(1, 1, 1); } + 30% { transform: scale3d(1.25, 0.75, 1); } + 40% { transform: scale3d(0.75, 1.25, 1); } + 50% { transform: scale3d(1.15, 0.85, 1); } + 65% { transform: scale3d(0.95, 1.05, 1); } + 75% { transform: scale3d(1.05, 0.95, 1); } + to { transform: scale3d(1, 1, 1); } +} + +@keyframes mfm-rainbow { + 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); } + 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); } +} diff --git a/packages/frontend/src/embed/ui.vue b/packages/embed/src/ui.vue similarity index 100% rename from packages/frontend/src/embed/ui.vue rename to packages/embed/src/ui.vue diff --git a/packages/embed/tsconfig.json b/packages/embed/tsconfig.json new file mode 100644 index 0000000000..fe4d202894 --- /dev/null +++ b/packages/embed/tsconfig.json @@ -0,0 +1,53 @@ +{ + "compilerOptions": { + "allowJs": true, + "noEmitOnError": false, + "noImplicitAny": false, + "noImplicitReturns": true, + "noUnusedParameters": false, + "noUnusedLocals": false, + "noFallthroughCasesInSwitch": true, + "declaration": false, + "sourceMap": false, + "target": "ES2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "removeComments": false, + "noLib": false, + "strict": true, + "strictNullChecks": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "useDefineForClassFields": true, + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "typeRoots": [ + "./@types", + "./node_modules/@types", + "./node_modules/@vue-macros", + "./node_modules" + ], + "types": [ + "vite/client", + "vitest/importMeta", + ], + "lib": [ + "esnext", + "dom", + "dom.iterable" + ], + "jsx": "preserve" + }, + "compileOnSave": false, + "include": [ + "./**/*.ts", + "./**/*.vue" + ], + "exclude": [ + ".storybook/**/*" + ] +} diff --git a/packages/embed/vue-shims.d.ts b/packages/embed/vue-shims.d.ts new file mode 100644 index 0000000000..eba994772d --- /dev/null +++ b/packages/embed/vue-shims.d.ts @@ -0,0 +1,6 @@ +/* eslint-disable */ +declare module "*.vue" { + import { defineComponent } from "vue"; + const component: ReturnType; + export default component; +} diff --git a/packages/frontend/src/embed/style.scss b/packages/frontend/src/embed/style.scss deleted file mode 100644 index 60b3e538fb..0000000000 --- a/packages/frontend/src/embed/style.scss +++ /dev/null @@ -1,19 +0,0 @@ -@charset "utf-8"; - -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * - * SPDX-License-Identifier: AGPL-3.0-only - */ - -html.embed { - background-color: transparent; - color-scheme: light dark; - overflow: hidden; -} - -html.embed, -html.embed body, -html.embed #misskey_app { - height: 100%; -}