Skip to content

Commit

Permalink
feat(frontend): ノート・ユーザータイムライン埋め込み (#13929)
Browse files Browse the repository at this point in the history
* fix

* navhookをbootに移動

* サーバーサイドのbootも分けるように

* 埋め込みページかどうかの判定は最初の一回だけに

* tooltipは出せるように

* fix design

* 埋め込み独自のtooltipを削除

* ロジックの分岐が多かったMkNoteDetailedを分離

* fix indent

* プレビュー用iframeにフォーカスが当たるのを修正

* popupの制御を出す側で行うように

* パラメータが逆になっていたのを修正

* Update MkEmbedCodeGenDialog.vue

* fix

* eliminate misskey-js lint warns

* fix

* add appropriate attributes to embed html

* enhance: サーバーサイドのembed系をさらに分離

* enhance: embed routerを分離(route定義をboot時に変更できるようにする改修を含む)

* type

* lint

* fix indent

* server-side styleを完全に分離

* Revert "refactor: 画面サイズのしきい値をconstにまとめる"

This reverts commit 05ca36f.

* fix

* revert all changes in base.pug

* embedドメインをまとめた

* embedドメインをまとめた

* prevent calling contextmenu in embed page by stopping at the caller

* fix import

* fix import

* improve directory structure

* fix import

* register timeline ui as a container

* wa-

* rename

* wa-

* Update EmMediaList.vue

* Update EmMediaList.vue

* Update EmMediaList.vue

* Update EmMediaImage.vue

* Update EmNote.vue

* revert mkmedialist changes

* 戻し漏れ

* wip

* tweak embed media ui

* revert original media components

* Update boot.embed.js

* rename

* wip

* Update MkNote.vue

* wip

* Update MkSubNoteContent.vue

* Update EmNote.vue

* Update packages/frontend/src/router/definition.ts

* Revert "Update packages/frontend/src/router/definition.ts"

This reverts commit 937ae44.

* refactor EmMediaImage

* fix import

* remove unused imports

* Update router.ts

* wip

* Update boot.ts

* wip

* wip

* wip

* wip

* Update EmNote.vue

* Update EmNote.vue

* Create EmA.vue

* Create EmAvatar.vue

* Update EmAvatar.vue

* wip

* wip

* wip

* Create EmImgWithBlurhash.vue

* Update EmImgWithBlurhash.vue

* Create EmPagination.vue

* wip

* Update boot.ts

* wip

* wip

* wi@p

* wip

* wip

* wiop

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update boot.ts

* wip

* Update MkMisskeyFlavoredMarkdown.ts

* wip

* wip

* wip

* wip

* wip

* Update post-message.ts

* wip

* Update EmNoteDetailed.vue

* Update EmNoteDetailed.vue

* Create instance.ts

* Update EmNoteDetailed.vue

* wip

* Update EmNoteDetailed.vue

* wip

* wip

* wip

* Update pnpm-lock.yaml

* wip

* wip

* wp

* wip

* Update ClientServerService.ts

* wip

* Update boot.ts

* Update vite.config.local-dev.ts

* Update vite.config.ts

* Create index.html

* wa-

* wip

* Update boot.ts

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Create EmLink.vue

* Create EmMention.vue

* Update EmMfm.ts

* wip

* wip

* wip

* wip

* Update vite.config.ts

* Update boot.ts

* Update EmA.vue

* うぃp

* wip

* wip

* Create EmError.vue

* wip

* Update MkEmbedCodeGenDialog.vue

* Update EmNote.vue

* wip

* wip

* Update user-timeline.vue

* Update check-spdx-license-id.yml

* wip

* wip

* style(frontend-shared): lint fixes on build.js

* fix(frontend-shared): include `*.{js,json}` files in js-built

* wip

* use alias

* refactor

* refactor

* Update scroll.ts

* refactor

* refactor

* refactor

* wip

* wip

* wip

* wip

* Update roles.vue

* Update branding.vue

* wip

* wip

* wip

* Update page.vue

* wip

* fix import

* add missing css variables

* 絵文字をtwemojiに変更

クライアントデフォルトにあわせるため

* force empoll readonly

* fix compiler error

* fix broken imports

* tweak button style

* run api extractor

* fix storybook theme preloads

* fix storybook instance imports

* Update preview.ts

* Update preview.ts

* Update preview.ts

* Revert "Update preview.ts"

This reverts commit 12bab1c.

* Revert "Update preview.ts"

This reverts commit 5c0ce01.

* Revert "Update preview.ts"

This reverts commit f486352.

* Revert "fix storybook instance imports"

This reverts commit ed8eabb.

* Revert "wip"

This reverts commit d3c1926.

* Revert "Update page.vue"

This reverts commit 27c7900.

* Revert "Update branding.vue"

This reverts commit c08ccb6.

* Revert "Update roles.vue"

This reverts commit 1488b67.

* Revert "wip"

This reverts commit aab1c76.

* refactor: use common media proxy

* fix imports

* fix

* fix: MediaProxyの初期化を保証する(storybook対策?)

* enhance(frontend-embed): improve embedParams provide

* fix(backend): MK_DEV_PREFER=backendのときにembed viteが読み込めないのを修正

* fix

* embed-pageを共通化

* fix import

* fix import

* fix import

* const.jsを共通化

(たぶんrevertしすぎた)

* fix type error

* fix duplicated import

* fix lint

* fix

* コメントとして残す

* sharedとembedをlint対象にする

* lint

* attempt to fix eslint (frontend-shared)

* lint fixes

---------

Co-authored-by: syuilo <[email protected]>
Co-authored-by: zyoshoka <[email protected]>
  • Loading branch information
3 people authored Sep 9, 2024
1 parent 0d0cd73 commit 2cbe1d1
Show file tree
Hide file tree
Showing 236 changed files with 9,470 additions and 454 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/check-spdx-license-id.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ jobs:
"packages/backend/migration"
"packages/backend/src"
"packages/backend/test"
"packages/frontend-shared/src"
"packages/frontend/.storybook"
"packages/frontend/@types"
"packages/frontend/lib"
"packages/frontend/public"
"packages/frontend/src"
"packages/frontend/test"
"packages/frontend-embed/src"
"packages/misskey-bubble-game/src"
"packages/misskey-reversi/src"
"packages/sw/src"
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:
paths:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-embed/**
- packages/sw/**
- packages/misskey-js/**
- packages/shared/eslint.config.js
Expand All @@ -16,6 +18,8 @@ on:
paths:
- packages/backend/**
- packages/frontend/**
- packages/frontend-shared/**
- packages/frontend-embed/**
- packages/sw/**
- packages/misskey-js/**
- packages/shared/eslint.config.js
Expand Down Expand Up @@ -45,6 +49,8 @@ jobs:
workspace:
- backend
- frontend
- frontend-shared
- frontend-embed
- sw
- misskey-js
env:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
-

### Client
- Feat: ノート単体・ユーザーのノート・クリップのノートの埋め込み機能
- 埋め込みコードやウェブサイトへの実装方法の詳細はMisskey Hubに掲載予定です
- サイズ制限を超過するファイルをアップロードしようとした際にエラーを出すように
- Enhance: アイコンデコレーション管理画面にプレビューを追加
- Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
COPY --link ["scripts", "./scripts"]
COPY --link ["packages/backend/package.json", "./packages/backend/"]
COPY --link ["packages/frontend-shared/package.json", "./packages/frontend-shared/"]
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
COPY --link ["packages/frontend-embed/package.json", "./packages/frontend-embed/"]
COPY --link ["packages/sw/package.json", "./packages/sw/"]
COPY --link ["packages/misskey-js/package.json", "./packages/misskey-js/"]
COPY --link ["packages/misskey-reversi/package.json", "./packages/misskey-reversi/"]
Expand Down
66 changes: 66 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5068,6 +5068,18 @@ export interface Locale extends ILocale {
* 作成したアンテナ
*/
"createdAntennas": string;
/**
* {x}から
*/
"fromX": ParameterizedString<"x">;
/**
* 埋め込みコードを生成
*/
"genEmbedCode": string;
/**
* このユーザーのノート一覧
*/
"noteOfThisUser": string;
/**
* これ以上このクリップにノートを追加できません。
*/
Expand Down Expand Up @@ -10196,6 +10208,60 @@ export interface Locale extends ILocale {
*/
"native": string;
};
"_embedCodeGen": {
/**
* 埋め込みコードをカスタマイズ
*/
"title": string;
/**
* ヘッダーを表示
*/
"header": string;
/**
* 自動で続きを読み込む(非推奨)
*/
"autoload": string;
/**
* 高さの最大値
*/
"maxHeight": string;
/**
* 0で最大値の設定が無効になります。ウィジェットが縦に伸び続けるのを防ぐために、何らかの値に指定してください。
*/
"maxHeightDescription": string;
/**
* 高さの最大値制限が無効(0)になっています。これが意図した変更ではない場合は、高さの最大値を何らかの値に設定してください。
*/
"maxHeightWarn": string;
/**
* プレビュー画面で表示可能な範囲を超えたため、実際に埋め込んだ際とは表示が異なります。
*/
"previewIsNotActual": string;
/**
* 角丸にする
*/
"rounded": string;
/**
* 外枠に枠線をつける
*/
"border": string;
/**
* プレビューに反映
*/
"applyToPreview": string;
/**
* 埋め込みコードを作成
*/
"generateCode": string;
/**
* コードが生成されました
*/
"codeGenerated": string;
/**
* 生成されたコードをウェブサイトに貼り付けてご利用ください。
*/
"codeGeneratedDescription": string;
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
18 changes: 18 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,9 @@ confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示
sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?"
createdLists: "作成したリスト"
createdAntennas: "作成したアンテナ"
fromX: "{x}から"
genEmbedCode: "埋め込みコードを生成"
noteOfThisUser: "このユーザーのノート一覧"
clipNoteLimitExceeded: "これ以上このクリップにノートを追加できません。"

_delivery:
Expand Down Expand Up @@ -2718,3 +2721,18 @@ _contextMenu:
app: "アプリケーション"
appWithShift: "Shiftキーでアプリケーション"
native: "ブラウザのUI"

_embedCodeGen:
title: "埋め込みコードをカスタマイズ"
header: "ヘッダーを表示"
autoload: "自動で続きを読み込む(非推奨)"
maxHeight: "高さの最大値"
maxHeightDescription: "0で最大値の設定が無効になります。ウィジェットが縦に伸び続けるのを防ぐために、何らかの値に指定してください。"
maxHeightWarn: "高さの最大値制限が無効(0)になっています。これが意図した変更ではない場合は、高さの最大値を何らかの値に設定してください。"
previewIsNotActual: "プレビュー画面で表示可能な範囲を超えたため、実際に埋め込んだ際とは表示が異なります。"
rounded: "角丸にする"
border: "外枠に枠線をつける"
applyToPreview: "プレビューに反映"
generateCode: "埋め込みコードを作成"
codeGenerated: "コードが生成されました"
codeGeneratedDescription: "生成されたコードをウェブサイトに貼り付けてご利用ください。"
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
},
"packageManager": "[email protected]",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
"packages/frontend-embed",
"packages/backend",
"packages/sw",
"packages/misskey-js",
Expand Down
31 changes: 31 additions & 0 deletions packages/backend/assets/embed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: MIT
*/
//@ts-check
(() => {
/** @type {NodeListOf<HTMLIFrameElement>} */
const els = document.querySelectorAll('iframe[data-misskey-embed-id]');

window.addEventListener('message', function (event) {
els.forEach((el) => {
if (event.source !== el.contentWindow) {
return;
}

const id = el.dataset.misskeyEmbedId;

if (event.data.type === 'misskey:embed:ready') {
el.contentWindow?.postMessage({
type: 'misskey:embedParent:registerIframeId',
payload: {
iframeId: id,
}
}, '*');
}
if (event.data.type === 'misskey:embed:changeHeight' && event.data.iframeId === id) {
el.style.height = event.data.payload.height + 'px';
}
});
});
})();
24 changes: 17 additions & 7 deletions packages/backend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ export type Config = {
authUrl: string;
driveUrl: string;
userAgent: string;
clientEntry: string;
clientManifestExists: boolean;
frontendEntry: string;
frontendManifestExists: boolean;
frontendEmbedEntry: string;
frontendEmbedManifestExists: boolean;
mediaProxy: string;
externalMediaProxyEnabled: boolean;
videoThumbnailGenerator: string | null;
Expand Down Expand Up @@ -196,10 +198,16 @@ const path = process.env.MISSKEY_CONFIG_YML

export function loadConfig(): Config {
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../built/meta.json`, 'utf-8'));
const clientManifestExists = fs.existsSync(_dirname + '/../../../built/_vite_/manifest.json');
const clientManifest = clientManifestExists ?
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8'))

const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json');
const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json');
const frontendManifest = frontendManifestExists ?
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8'))
: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } };
const frontendEmbedManifest = frontendEmbedManifestExists ?
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8'))
: { 'src/boot.ts': { file: 'src/boot.ts' } };

const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source;

const url = tryCreateUrl(config.url ?? process.env.MISSKEY_URL ?? '');
Expand Down Expand Up @@ -270,8 +278,10 @@ export function loadConfig(): Config {
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
: null,
userAgent: `Misskey/${version} (${config.url})`,
clientEntry: clientManifest['src/_boot_.ts'],
clientManifestExists: clientManifestExists,
frontendEntry: frontendManifest['src/_boot_.ts'],
frontendManifestExists: frontendManifestExists,
frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'],
frontendEmbedManifestExists: frontendEmbedManifestExists,
perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000,
perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500,
deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7),
Expand Down
46 changes: 41 additions & 5 deletions packages/backend/src/server/web/ClientServerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ const staticAssets = `${_dirname}/../../../assets/`;
const clientAssets = `${_dirname}/../../../../frontend/assets/`;
const assets = `${_dirname}/../../../../../built/_frontend_dist_/`;
const swAssets = `${_dirname}/../../../../../built/_sw_dist_/`;
const viteOut = `${_dirname}/../../../../../built/_vite_/`;
const frontendViteOut = `${_dirname}/../../../../../built/_frontend_vite_/`;
const frontendEmbedViteOut = `${_dirname}/../../../../../built/_frontend_embed_vite_/`;
const tarball = `${_dirname}/../../../../../built/tarball/`;

@Injectable()
Expand Down Expand Up @@ -277,15 +278,22 @@ export class ClientServerService {
});

//#region vite assets
if (this.config.clientManifestExists) {
if (this.config.frontendEmbedManifestExists) {
fastify.register((fastify, options, done) => {
fastify.register(fastifyStatic, {
root: viteOut,
root: frontendViteOut,
prefix: '/vite/',
maxAge: ms('30 days'),
immutable: true,
decorateReply: false,
});
fastify.register(fastifyStatic, {
root: frontendEmbedViteOut,
prefix: '/embed_vite/',
maxAge: ms('30 days'),
immutable: true,
decorateReply: false,
});
fastify.addHook('onRequest', handleRequestRedirectToOmitSearch);
done();
});
Expand All @@ -296,6 +304,13 @@ export class ClientServerService {
prefix: '/vite',
rewritePrefix: '/vite',
});

const embedPort = (process.env.EMBED_VITE_PORT ?? '5174');
fastify.register(fastifyProxy, {
upstream: 'http://localhost:' + embedPort,
prefix: '/embed_vite',
rewritePrefix: '/embed_vite',
});
}
//#endregion

Expand Down Expand Up @@ -425,6 +440,13 @@ export class ClientServerService {
// Manifest
fastify.get('/manifest.json', async (request, reply) => await this.manifestHandler(reply));

// Embed Javascript
fastify.get('/embed.js', async (request, reply) => {
return await reply.sendFile('/embed.js', staticAssets, {
maxAge: ms('1 day'),
});
});

fastify.get('/robots.txt', async (request, reply) => {
return await reply.sendFile('/robots.txt', staticAssets);
});
Expand Down Expand Up @@ -762,7 +784,7 @@ export class ClientServerService {
});
//#endregion

//region noindex pages
//#region noindex pages
// Tags
fastify.get<{ Params: { clip: string; } }>('/tags/:tag', async (request, reply) => {
return await renderBase(reply, { noindex: true });
Expand All @@ -772,7 +794,20 @@ export class ClientServerService {
fastify.get<{ Params: { clip: string; } }>('/user-tags/:tag', async (request, reply) => {
return await renderBase(reply, { noindex: true });
});
//endregion
//#endregion

//#region embed pages
fastify.get('/embed/*', async (request, reply) => {
const meta = await this.metaService.fetch();

reply.removeHeader('X-Frame-Options');

reply.header('Cache-Control', 'public, max-age=3600');
return await reply.view('base-embed', {
title: meta.name ?? 'Misskey',
...await this.generateCommonPugData(meta),
});
});

fastify.get('/_info_card_', async (request, reply) => {
const meta = await this.metaService.fetch(true);
Expand All @@ -787,6 +822,7 @@ export class ClientServerService {
originalNotesCount: await this.notesRepository.countBy({ userHost: IsNull() }),
});
});
//#endregion

fastify.get('/bios', async (request, reply) => {
return await reply.view('bios', {
Expand Down
Loading

0 comments on commit 2cbe1d1

Please sign in to comment.