Skip to content

Commit

Permalink
feat(tms): サーバーカスタムCSS
Browse files Browse the repository at this point in the history
  • Loading branch information
taiyme committed Feb 15, 2025
1 parent 3b898fa commit 656a416
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 15 deletions.
16 changes: 16 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10957,6 +10957,10 @@ export interface Locale extends ILocale {
* taiymeについて
*/
readonly "aboutTaiyme": string;
/**
* taiyme限定
*/
readonly "taiymeOnly": string;
/**
* taiyme限定機能
*/
Expand Down Expand Up @@ -11152,6 +11156,18 @@ export interface Locale extends ILocale {
};
};
readonly "_admin": {
/**
* サーバーカスタムCSS
*/
readonly "serverCustomCss": string;
/**
* この設定は必ず知識のある方が行ってください。不適切な設定を行うと、管理者を含むすべてのユーザーのクライアントが正常に使用できなくなる恐れがあります。
*/
readonly "serverCustomCssDescription1": string;
/**
* カスタムCSSの適用を一時的に無効にするには、URLの末尾に「?customcss=false」と付けてアクセスしてください。
*/
readonly "serverCustomCssDescription2": string;
/**
* ソースコードが公開されているリポジトリがある場合、そのURLを記入します。taiymeを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/taiyme/misskey と記入します。
*/
Expand Down
4 changes: 4 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2932,6 +2932,7 @@ _tms:
taiy: "taiy"
taiyme: "taiyme"
aboutTaiyme: "taiymeについて"
taiymeOnly: "taiyme限定"
taiymeFeatures: "taiyme限定機能"
taiymeFeaturesDescription: "これらの機能はtaiymeで独自実装したものです。"
poweredByTaiyme: "{name}は、Misskeyの派生であるtaiymeを使用したサーバーのひとつです。"
Expand Down Expand Up @@ -2985,6 +2986,9 @@ _tms:
label: "長押しによるコンテキストメニューイベントの発行を防ぐ"
caption: "長押しを含む操作が中断される問題を解消します。"
_admin:
serverCustomCss: "サーバーカスタムCSS"
serverCustomCssDescription1: "この設定は必ず知識のある方が行ってください。不適切な設定を行うと、管理者を含むすべてのユーザーのクライアントが正常に使用できなくなる恐れがあります。"
serverCustomCssDescription2: "カスタムCSSの適用を一時的に無効にするには、URLの末尾に「?customcss=false」と付けてアクセスしてください。"
repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。taiymeを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/taiyme/misskey と記入します。"
_search:
searchScopeAll: "全て"
Expand Down
17 changes: 17 additions & 0 deletions packages/backend/migration/1739404800000-TaiymeServerCustomCss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/

1739442551466
export class TaiymeServerCustomCss1739404800000 {
name = 'TaiymeServerCustomCss1739404800000';

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "taiymeServerCustomCss" character varying(8192)`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "taiymeServerCustomCss"`);
}
}
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/MetaEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class MetaEntityService {
maxNoteTextLength: MAX_NOTE_TEXT_LENGTH,
defaultLightTheme,
defaultDarkTheme,
taiymeServerCustomCss: instance.taiymeServerCustomCss,
ads: ads.map(ad => ({
id: ad.id,
url: ad.url,
Expand Down
6 changes: 6 additions & 0 deletions packages/backend/src/models/Meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,12 @@ export class MiMeta {
})
public defaultDarkTheme: string | null;

@Column('varchar', {
length: 8192,
nullable: true,
})
public taiymeServerCustomCss: string | null;

@Column('boolean', {
default: false,
})
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/models/json-schema/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export const packedMetaLiteSchema = {
type: 'string',
optional: false, nullable: true,
},
taiymeServerCustomCss: {
type: 'string',
optional: false, nullable: true,
},
disableRegistration: {
type: 'boolean',
optional: false, nullable: false,
Expand Down
5 changes: 5 additions & 0 deletions packages/backend/src/server/api/endpoints/admin/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
taiymeServerCustomCss: {
type: 'string',
optional: false, nullable: true,
},
description: {
type: 'string',
optional: false, nullable: true,
Expand Down Expand Up @@ -591,6 +595,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
logoImageUrl: instance.logoImageUrl,
defaultLightTheme: instance.defaultLightTheme,
defaultDarkTheme: instance.defaultDarkTheme,
taiymeServerCustomCss: instance.taiymeServerCustomCss,
enableEmail: instance.enableEmail,
enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const paramDef = {
description: { type: 'string', nullable: true },
defaultLightTheme: { type: 'string', nullable: true },
defaultDarkTheme: { type: 'string', nullable: true },
taiymeServerCustomCss: { type: 'string', nullable: true },
cacheRemoteFiles: { type: 'boolean' },
cacheRemoteSensitiveFiles: { type: 'boolean' },
emailRequiredForSignup: { type: 'boolean' },
Expand Down Expand Up @@ -303,6 +304,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
set.defaultDarkTheme = ps.defaultDarkTheme;
}

if (ps.taiymeServerCustomCss !== undefined) {
set.taiymeServerCustomCss = ps.taiymeServerCustomCss;
}

if (ps.cacheRemoteFiles !== undefined) {
set.cacheRemoteFiles = ps.cacheRemoteFiles;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/backend/src/server/web/boot.embed.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@
//#endregion

async function addStyle(styleText) {
let css = document.createElement('style');
css.appendChild(document.createTextNode(styleText));
document.head.appendChild(css);
const styleTag = document.createElement('style');
styleTag.textContent = styleText;
document.head.appendChild(styleTag);
}

async function renderError(code) {
Expand Down
24 changes: 16 additions & 8 deletions packages/backend/src/server/web/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,25 @@
document.documentElement.style.backgroundImage = `url(${wallpaper})`;
}

const customCss = localStorage.getItem('customCss');
if (customCss && customCss.length > 0) {
const style = document.createElement('style');
style.innerHTML = customCss;
document.head.appendChild(style);
const availableCustomCss = (() => {
const params = new URLSearchParams(window.location.search);
return ['true', 'yes', 'on', 't', '1'].includes(params.get('customcss')?.toLowerCase() ?? 'true');
})();

if (availableCustomCss) {
const customCss = localStorage.getItem('customCss');
if (customCss && customCss.length > 0) {
const styleTag = document.createElement('style');
styleTag.id = 'user_custom_css';
styleTag.textContent = customCss;
document.head.appendChild(styleTag);
}
}

async function addStyle(styleText) {
let css = document.createElement('style');
css.appendChild(document.createTextNode(styleText));
document.head.appendChild(css);
const styleTag = document.createElement('style');
styleTag.textContent = styleText;
document.head.appendChild(styleTag);
}

async function renderError(code, details) {
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend-embed/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

--MI-margin: var(--MI-marginFull);

--TMS_THEME-fgOnAccent: #fff;
--TMS_THEME-accent: #336ecc;

--TMS-hsl-base-h: 1;
--TMS-hsl-base-s: 1;
--TMS-hsl-base-l: 1;
Expand Down
61 changes: 61 additions & 0 deletions packages/frontend-shared/js/tms/apply-custom-css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/

import { url as configUrl } from '@@/js/config.js';

const availableCustomCss = (() => {
const params = new URLSearchParams(window.location.search);
return ['true', 'yes', 'on', 't', '1'].includes(params.get('customcss')?.toLowerCase() ?? 'true');
})();

export function applyCustomCss({ serverCustomCss, userCustomCss }: {
readonly serverCustomCss?: string | null;
readonly userCustomCss?: string | null;
}) {
if (!availableCustomCss) return;
if (serverCustomCss === undefined && userCustomCss === undefined) return;

let serverStyleTag = document.getElementById('server_custom_css');
if (serverCustomCss !== undefined) {
if (serverCustomCss === null || serverCustomCss === '') {
serverStyleTag?.remove();
serverStyleTag = null;
} else {
if (serverStyleTag == null) {
serverStyleTag = document.createElement('style');
serverStyleTag.id = 'server_custom_css';
}
serverStyleTag.textContent = serverCustomCss;
}
}

let userStyleTag = document.getElementById('user_custom_css');
if (userCustomCss !== undefined) {
if (userCustomCss === null || userCustomCss === '') {
userStyleTag?.remove();
userStyleTag = null;
} else {
if (userStyleTag == null) {
userStyleTag = document.createElement('style');
userStyleTag.id = 'user_custom_css';
}
userStyleTag.textContent = userCustomCss;
}
}

if (serverStyleTag != null) {
document.head.appendChild(serverStyleTag);
}
if (userStyleTag != null) {
document.head.appendChild(userStyleTag);
}

if (serverStyleTag != null || userStyleTag != null) {
const url = new URL(configUrl);
url.searchParams.set('customcss', 'false');
console.log(`Custom CSS has been applied. To temporarily disable it, please visit ${url.href}.`);
console.log(`カスタムCSSが適用されました。一時的に無効にするには ${url.href} にアクセスします。`);
}
}
9 changes: 9 additions & 0 deletions packages/frontend/src/boot/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { computed, watch, version as vueVersion, App } from 'vue';
import { compareVersions } from 'compare-versions';
import { version, lang, updateLocale, locale, commitHash } from '@@/js/config.js';
import { applyCustomCss } from '@@/js/tms/apply-custom-css.js';
import widgets from '@/widgets/index.js';
import directives from '@/directives/index.js';
import components from '@/components/index.js';
Expand Down Expand Up @@ -140,6 +141,14 @@ export async function common(createVue: () => App<Element>) {
miLocalStorage.setItem('v', instance.version);
});

//#region taiymeServerCustomCss
fetchInstanceMetaPromise.then(() => {
applyCustomCss({
serverCustomCss: instance.taiymeServerCustomCss,
});
});
//#endregion

//#region loginId
const params = new URLSearchParams(location.search);
const loginId = params.get('loginId');
Expand Down
8 changes: 4 additions & 4 deletions packages/frontend/src/components/MkRange.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
closed: () => dispose(),
});

const style = document.createElement('style');
style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }'));
document.head.appendChild(style);
const styleTag = document.createElement('style');
styleTag.textContent = '* { cursor: grabbing !important; } body * { pointer-events: none !important; }';
document.head.appendChild(styleTag);

const thumbWidth = getThumbWidth();

Expand All @@ -172,7 +172,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) {
let beforeValue = finalValue.value;

const onMouseup = () => {
document.head.removeChild(style);
document.head.removeChild(styleTag);
tooltipForDragShowing.value = false;
window.removeEventListener('mousemove', onDrag);
window.removeEventListener('touchmove', onDrag);
Expand Down
15 changes: 15 additions & 0 deletions packages/frontend/src/pages/admin/branding.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</MkTextarea>

<MkCodeEditor v-model="taiymeServerCustomCss" lang="css">
<template #label>
<span>{{ i18n.ts._tms._admin.serverCustomCss }}</span>
<span class="_taiymeOnly">{{ i18n.ts._tms.taiymeOnly }}</span>
</template>
<template #caption>
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._tms._admin.serverCustomCssDescription1 }}</div>
<div><i class="ti ti-alert-triangle" style="color: var(--MI_THEME-warn);"></i> {{ i18n.ts._tms._admin.serverCustomCssDescription2 }}</div>
</template>
</MkCodeEditor>

<MkInput v-model="repositoryUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.repositoryUrl }}</template>
Expand Down Expand Up @@ -114,6 +125,7 @@ import { instance, fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
import MkCodeEditor from '@/components/MkCodeEditor.vue';
import MkColorInput from '@/components/MkColorInput.vue';

const iconUrl = ref<string | null>(null);
Expand All @@ -124,6 +136,7 @@ const backgroundImageUrl = ref<string | null>(null);
const themeColor = ref<string | null>(null);
const defaultLightTheme = ref<string | null>(null);
const defaultDarkTheme = ref<string | null>(null);
const taiymeServerCustomCss = ref<string | null>(null);
const serverErrorImageUrl = ref<string | null>(null);
const infoImageUrl = ref<string | null>(null);
const notFoundImageUrl = ref<string | null>(null);
Expand All @@ -141,6 +154,7 @@ async function init() {
themeColor.value = meta.themeColor;
defaultLightTheme.value = meta.defaultLightTheme;
defaultDarkTheme.value = meta.defaultDarkTheme;
taiymeServerCustomCss.value = meta.taiymeServerCustomCss;
serverErrorImageUrl.value = meta.serverErrorImageUrl;
infoImageUrl.value = meta.infoImageUrl;
notFoundImageUrl.value = meta.notFoundImageUrl;
Expand All @@ -159,6 +173,7 @@ function save() {
themeColor: themeColor.value === '' ? null : themeColor.value,
defaultLightTheme: defaultLightTheme.value === '' ? null : defaultLightTheme.value,
defaultDarkTheme: defaultDarkTheme.value === '' ? null : defaultDarkTheme.value,
taiymeServerCustomCss: taiymeServerCustomCss.value === '' ? null : taiymeServerCustomCss.value,
infoImageUrl: infoImageUrl.value === '' ? null : infoImageUrl.value,
notFoundImageUrl: notFoundImageUrl.value === '' ? null : notFoundImageUrl.value,
serverErrorImageUrl: serverErrorImageUrl.value === '' ? null : serverErrorImageUrl.value,
Expand Down
15 changes: 15 additions & 0 deletions packages/frontend/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

--MI-margin: var(--MI-marginFull);

--TMS_THEME-fgOnAccent: #fff;
--TMS_THEME-accent: #336ecc;

--TMS-hsl-base-h: 1;
--TMS-hsl-base-s: 1;
--TMS-hsl-base-l: 1;
Expand Down Expand Up @@ -391,6 +394,18 @@ rt {
line-height: 1;
}

._taiymeOnly {
margin-left: 0.7em;
font-size: 65%;
padding: 3px 4px;
color: var(--TMS_THEME-fgOnAccent);
background-color: var(--TMS_THEME-accent);
border-radius: 4px;
vertical-align: top;
display: inline-block;
line-height: 1;
}

._table {
> ._row {
display: flex;
Expand Down
Loading

0 comments on commit 656a416

Please sign in to comment.