- use visible box-shadowing
- add translation for ZH - light/darkmode switcher
This commit is contained in:
1 parent
2214845361
commit
9200aac276
2 files changed
+218
-22
No files matched your search
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600">
|
||||
<rect width="900" height="600" fill="#EE1C25"/>
|
||||
<path id="star" d="M0,-1 L0.225,-0.309 L0.951,-0.309 L0.363,0.118 L0.588,0.809 L0,0.382 L-0.588,0.809 L-0.363,0.118 L-0.951,-0.309 L-0.225,-0.309 Z" fill="#FFDE00"/>
|
||||
<use href="#star" transform="translate(150,150) scale(90)"/>
|
||||
<use href="#star" transform="translate(300,60) scale(30)"/>
|
||||
<use href="#star" transform="translate(360,120) scale(30)"/>
|
||||
<use href="#star" transform="translate(360,210) scale(30)"/>
|
||||
<use href="#star" transform="translate(300,270) scale(30)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 602 B |
+209
-22
@@ -7,7 +7,11 @@
|
||||
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -108,7 +112,7 @@
|
||||
padding: 32px;
|
||||
background: white;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.10);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.30), 0 12px 40px rgba(0, 0, 0, 0.45);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -233,58 +237,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
/*
|
||||
* Dark-Theme über die Klasse "dark" am html-Element.
|
||||
* JS setzt sie anhand der gespeicherten Wahl oder der
|
||||
* System-Einstellung (siehe detectTheme).
|
||||
*/
|
||||
:root.dark body {
|
||||
background: #181818;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.card {
|
||||
:root.dark .card {
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
.lang-dropdown {
|
||||
:root.dark .lang-dropdown {
|
||||
background: #242424;
|
||||
}
|
||||
|
||||
.lang-dropdown button:hover {
|
||||
:root.dark .lang-dropdown button:hover {
|
||||
background: #303030;
|
||||
}
|
||||
|
||||
.lang-dropdown button.active {
|
||||
:root.dark .lang-dropdown button.active {
|
||||
background: #1a3a5a;
|
||||
}
|
||||
|
||||
p {
|
||||
:root.dark p {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
:root.dark .secondary {
|
||||
background: #444;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.status, .download {
|
||||
:root.dark .status,
|
||||
:root.dark .download {
|
||||
background: #303030;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
:root.dark .spinner {
|
||||
border-color: #555;
|
||||
border-top-color: #ddd;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group textarea {
|
||||
:root.dark .form-group label {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
:root.dark .form-group input,
|
||||
:root.dark .form-group textarea {
|
||||
background: #303030;
|
||||
border-color: #555;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.success-message {
|
||||
:root.dark .success-message {
|
||||
background: #1a3a5a;
|
||||
color: #99ccff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -306,8 +318,18 @@
|
||||
<button type="button" data-lang="en"><img class="lang-flag" src="assets/uk.svg" alt="">English</button>
|
||||
<button type="button" data-lang="de"><img class="lang-flag" src="assets/de.svg" alt="">Deutsch</button>
|
||||
<button type="button" data-lang="fr"><img class="lang-flag" src="assets/fr.svg" alt="">Français</button>
|
||||
<button type="button" data-lang="zh"><img class="lang-flag" src="assets/cn.svg" alt="">中文</button>
|
||||
</div>
|
||||
</div>
|
||||
<button id="themeButton" class="button secondary" type="button" aria-label="Toggle dark mode">
|
||||
<svg id="themeIconMoon" class="theme-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/>
|
||||
</svg>
|
||||
<svg id="themeIconSun" class="theme-icon hidden" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="4"/>
|
||||
<path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/>
|
||||
</svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
@@ -831,6 +853,89 @@
|
||||
organizerRequired: "Veuillez entrer un email d'organisateur",
|
||||
organizerInvalid: "Veuillez entrer une adresse email d'organisateur valide"
|
||||
}
|
||||
},
|
||||
|
||||
zh: {
|
||||
pageTitle: "Jitsi 会议",
|
||||
impressum: "法律声明",
|
||||
|
||||
launcher: {
|
||||
title: "Jitsi 会议",
|
||||
meetingPrefix: "会议",
|
||||
meetingSuffix: "即将打开。",
|
||||
openButton: "加入会议"
|
||||
},
|
||||
|
||||
starting: {
|
||||
title: "正在启动 Jitsi Meet …",
|
||||
status: "正在打开 Jitsi Meet 桌面客户端。"
|
||||
},
|
||||
|
||||
fallback: {
|
||||
title: "无法打开 Jitsi Meet",
|
||||
description: "Jitsi Meet 桌面客户端可能尚未启动。",
|
||||
retryButton: "重试"
|
||||
},
|
||||
|
||||
downloads: {
|
||||
windows: {
|
||||
title: "适用于 Windows 的 Jitsi Meet",
|
||||
description: "请安装 Jitsi Meet 桌面客户端,然后再次尝试打开会议。",
|
||||
button: "下载 Windows 版 Jitsi"
|
||||
},
|
||||
|
||||
macos: {
|
||||
title: "适用于 macOS 的 Jitsi Meet",
|
||||
description: "请安装 Jitsi Meet 桌面客户端,然后再次尝试打开会议。",
|
||||
button: "下载 macOS 版 Jitsi"
|
||||
},
|
||||
|
||||
linux: {
|
||||
title: "适用于 Linux 的 Jitsi Meet",
|
||||
description: "请安装 Jitsi Meet 桌面客户端,然后再次尝试打开会议。",
|
||||
button: "下载 Linux 版 Jitsi"
|
||||
},
|
||||
|
||||
other: {
|
||||
title: "Jitsi Meet 桌面版",
|
||||
description: "没有为您的操作系统配置桌面版下载。"
|
||||
}
|
||||
},
|
||||
|
||||
browser: {
|
||||
title: "在浏览器中加入",
|
||||
description: "您也可以直接通过浏览器加入会议。",
|
||||
button: "在浏览器中加入"
|
||||
},
|
||||
|
||||
error: {
|
||||
title: "未指定会议",
|
||||
description: "请使用参数指定会议",
|
||||
descriptionSuffix: "。",
|
||||
invalidTitle: "会议名称无效",
|
||||
invalidDescription: "仅允许使用字母、数字和连字符:"
|
||||
},
|
||||
|
||||
creator: {
|
||||
title: "创建新会议",
|
||||
meetingNameLabel: "会议名称",
|
||||
meetingDescriptionLabel: "描述",
|
||||
meetingStartLabel: "开始日期和时间",
|
||||
meetingEndLabel: "结束日期和时间",
|
||||
meetingOrganizerLabel: "组织者邮箱",
|
||||
createButton: "创建会议",
|
||||
cancelButton: "取消",
|
||||
successMessage: "会议已创建!请下载您的日历文件。",
|
||||
downloadButton: "下载 ICS 文件",
|
||||
createNewButton: "创建新会议",
|
||||
meetingNameRequired: "请输入会议名称",
|
||||
meetingNameInvalid: "会议名称只能包含字母、数字和连字符",
|
||||
startTimeRequired: "请选择开始时间",
|
||||
endTimeRequired: "请选择结束时间",
|
||||
endAfterStart: "结束时间必须晚于开始时间",
|
||||
organizerRequired: "请输入组织者邮箱",
|
||||
organizerInvalid: "请输入有效的组织者邮箱地址"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -940,13 +1045,15 @@
|
||||
const LANGUAGE_NAMES = {
|
||||
en: "English",
|
||||
de: "Deutsch",
|
||||
fr: "Français"
|
||||
fr: "Français",
|
||||
zh: "中文"
|
||||
};
|
||||
|
||||
const LANGUAGE_FLAGS = {
|
||||
en: "assets/uk.svg",
|
||||
de: "assets/de.svg",
|
||||
fr: "assets/fr.svg"
|
||||
fr: "assets/fr.svg",
|
||||
zh: "assets/cn.svg"
|
||||
};
|
||||
|
||||
function updateLanguageMenu() {
|
||||
@@ -997,6 +1104,66 @@
|
||||
langButton.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* THEME
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
const THEME_KEY = "jitsiLauncherTheme";
|
||||
|
||||
function savedTheme() {
|
||||
try {
|
||||
const saved = localStorage.getItem(THEME_KEY);
|
||||
|
||||
if (saved === "dark" || saved === "light") {
|
||||
return saved;
|
||||
}
|
||||
} catch (error) {
|
||||
/*
|
||||
* localStorage kann z.B. im Privat-Modus blockiert sein.
|
||||
*/
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function systemIsDark() {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
}
|
||||
|
||||
function detectTheme() {
|
||||
/*
|
||||
* Gespeicherte Wahl hat Vorrang, sonst System-Einstellung.
|
||||
*/
|
||||
return savedTheme() || (systemIsDark() ? "dark" : "light");
|
||||
}
|
||||
|
||||
let currentTheme = detectTheme();
|
||||
|
||||
function updateThemeToggle() {
|
||||
themeIconSun.classList.toggle("hidden", currentTheme !== "dark");
|
||||
themeIconMoon.classList.toggle("hidden", currentTheme === "dark");
|
||||
}
|
||||
|
||||
function applyTheme() {
|
||||
document.documentElement.classList.toggle("dark", currentTheme === "dark");
|
||||
updateThemeToggle();
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
currentTheme = currentTheme === "dark" ? "light" : "dark";
|
||||
|
||||
try {
|
||||
localStorage.setItem(THEME_KEY, currentTheme);
|
||||
} catch (error) {
|
||||
/*
|
||||
* localStorage kann z.B. im Privat-Modus blockiert sein.
|
||||
*/
|
||||
}
|
||||
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* BACKGROUND IMAGE
|
||||
* ============================================================
|
||||
@@ -1079,6 +1246,11 @@
|
||||
const logoBar = document.getElementById("logoBar");
|
||||
const logoImage = document.getElementById("logoImage");
|
||||
|
||||
/* Theme DOM elements */
|
||||
const themeButton = document.getElementById("themeButton");
|
||||
const themeIconSun = document.getElementById("themeIconSun");
|
||||
const themeIconMoon = document.getElementById("themeIconMoon");
|
||||
|
||||
/* ============================================================
|
||||
* GET ROOM FROM QUERY-PARAMETER
|
||||
* ============================================================
|
||||
@@ -1683,10 +1855,6 @@ END:VCALENDAR`;
|
||||
* Kein room-Parameter: Meldungen ausblenden,
|
||||
* nur den Create-Button anzeigen.
|
||||
*/
|
||||
/*
|
||||
* Kein room-Parameter: keine Fehlermeldung,
|
||||
* nur den Create-Button anzeigen.
|
||||
*/
|
||||
if (room === null) {
|
||||
missingRoomTitle.classList.add("hidden");
|
||||
missingRoomError.classList.add("hidden");
|
||||
@@ -1827,12 +1995,31 @@ END:VCALENDAR`;
|
||||
}
|
||||
);
|
||||
|
||||
/* Theme events */
|
||||
themeButton.addEventListener(
|
||||
"click",
|
||||
toggleTheme
|
||||
);
|
||||
|
||||
/*
|
||||
* Ohne gespeicherte Wahl dem System folgen.
|
||||
*/
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", () => {
|
||||
if (savedTheme() === null) {
|
||||
currentTheme = systemIsDark() ? "dark" : "light";
|
||||
applyTheme();
|
||||
}
|
||||
});
|
||||
|
||||
/* ============================================================
|
||||
* START
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
applyTranslations();
|
||||
applyTheme();
|
||||
applyBackgroundImage();
|
||||
applyLogo();
|
||||
updateLanguageMenu();
|
||||
|
||||
Reference in new issue
Block a user