core&ui: add dark theme support to manage_config

This commit is contained in:
undefined committed 2025-06-08 23:07:05 +08:00
1 parent 2305e168f0
commit b70b685b01
5 files changed
+36 -18

No files matched your search

@@ -13,7 +13,7 @@ const locales = {
}; };
function MonacoContainer({ function MonacoContainer({
config, setValue, setError, monaco, schema, editorCallback, size, config, setValue, setError, monaco, schema, editorCallback, size, dark,
}) { }) {
const [editor, setEditor] = React.useState<any>(null); const [editor, setEditor] = React.useState<any>(null);
const [model, setModel] = React.useState<any>(null); const [model, setModel] = React.useState<any>(null);
@@ -69,7 +69,7 @@ function MonacoContainer({
const model = monaco.editor.createModel(config, 'yaml', monaco.Uri.parse('hydro://system/setting.yaml')); const model = monaco.editor.createModel(config, 'yaml', monaco.Uri.parse('hydro://system/setting.yaml'));
setModel(model); setModel(model);
const e = monaco.editor.create(element, { const e = monaco.editor.create(element, {
theme: 'vs-light', theme: dark ? 'vs-dark' : 'vs-light',
lineNumbers: 'off', lineNumbers: 'off',
glyphMargin: true, glyphMargin: true,
lightbulb: { enabled: monaco.editor.ShowLightbulbIconMode.On }, lightbulb: { enabled: monaco.editor.ShowLightbulbIconMode.On },
@@ -151,13 +151,14 @@ export default function ConfigEditor({
const [size, setSize] = React.useState([50, 50]); const [size, setSize] = React.useState([50, 50]);
return (<div className="fullscreen-content" style={{ backgroundColor: 'white', zIndex: 10 }}> return (<div className="fullscreen-content" style={{ zIndex: 10 }}>
<Allotment onChange={setSize}> <Allotment onChange={setSize}>
<Allotment.Pane> <Allotment.Pane>
<MonacoContainer <MonacoContainer
editorCallback={registerAction} schema={schema} monaco={monaco} editorCallback={registerAction} schema={schema} monaco={monaco}
config={stringConfig} setValue={updateFromMonaco} setError={setInfo} config={stringConfig} setValue={updateFromMonaco} setError={setInfo}
size={size[0]} size={size[0]}
dark={document.documentElement.className.includes('theme--dark')}
/> />
<pre className="help-text">{info}</pre> <pre className="help-text">{info}</pre>
<button onClick={() => onSave(stringConfig)} className="rounded primary button">{i18n('Save All Changes')}</button> <button onClick={() => onSave(stringConfig)} className="rounded primary button">{i18n('Save All Changes')}</button>
+5 -8
View File
@@ -182,7 +182,7 @@ class SystemConfigHandler extends SystemHandler {
@requireSudo @requireSudo
async get() { async get() {
this.response.template = 'manage_config.html'; this.response.template = 'manage_config.html';
let value; let value = this.ctx.setting.configSource;
const processNode = (node: any, schema: Schema<any, any>, parent?: any, accessKey?: string) => { const processNode = (node: any, schema: Schema<any, any>, parent?: any, accessKey?: string) => {
if (['union', 'intersect'].includes(schema.type)) { if (['union', 'intersect'].includes(schema.type)) {
@@ -198,16 +198,13 @@ class SystemConfigHandler extends SystemHandler {
}; };
try { try {
try { const temp = yaml.load(this.ctx.setting.configSource);
value = Schema.intersect(this.ctx.setting.settings)(yaml.load(this.ctx.setting.configSource)); for (const schema of this.ctx.setting.settings) processNode(temp, schema);
} catch (e) { value = yaml.dump(temp);
value = yaml.load(this.ctx.setting.configSource);
}
for (const schema of this.ctx.setting.settings) processNode(value, schema);
} catch (e) { } } catch (e) { }
this.response.body = { this.response.body = {
schema: Schema.intersect(this.ctx.setting.settings).toJSON(), schema: Schema.intersect(this.ctx.setting.settings).toJSON(),
value: yaml.dump(value), value,
}; };
} }
+4 -5
View File
@@ -26,11 +26,6 @@ for (const country of countries) {
const timezones = Array.from(tzs).sort().map((tz) => [tz, tz]) as [string, string][]; const timezones = Array.from(tzs).sort().map((tz) => [tz, tz]) as [string, string][];
const langRange: Dictionary<string> = {}; const langRange: Dictionary<string> = {};
for (const lang in global.Hydro.locales) {
if (!global.Hydro.locales[lang].__interface) continue;
langRange[lang] = global.Hydro.locales[lang].__langname;
}
export const FLAG_HIDDEN = 1; export const FLAG_HIDDEN = 1;
export const FLAG_DISABLED = 2; export const FLAG_DISABLED = 2;
export const FLAG_SECRET = 4; export const FLAG_SECRET = 4;
@@ -364,6 +359,10 @@ export const langs: Record<string, LangConfig> = {};
export const inject = ['db']; export const inject = ['db'];
export async function apply(ctx: Context) { export async function apply(ctx: Context) {
logger.info('Ensuring settings'); logger.info('Ensuring settings');
for (const lang in global.Hydro.locales) {
if (!global.Hydro.locales[lang].__interface) continue;
langRange[lang] = global.Hydro.locales[lang].__langname;
}
const system = global.Hydro.model.system; const system = global.Hydro.model.system;
for (const setting of SYSTEM_SETTINGS) { for (const setting of SYSTEM_SETTINGS) {
if (!setting.value) continue; if (!setting.value) continue;
@@ -7,6 +7,10 @@ import { NamedPage } from 'vj/misc/Page';
import { i18n, request } from 'vj/utils'; import { i18n, request } from 'vj/utils';
const page = new NamedPage('manage_config', async () => { const page = new NamedPage('manage_config', async () => {
if (document.documentElement.className.includes('theme--dark')) {
document.documentElement.className += ' dark';
}
const [{ ConfigEditor, ComponentsProvider }, { load }] = await Promise.all([ const [{ ConfigEditor, ComponentsProvider }, { load }] = await Promise.all([
import('@hydrooj/components'), import('@hydrooj/components'),
import('vj/components/monaco/loader'), import('vj/components/monaco/loader'),
@@ -35,6 +39,7 @@ const page = new NamedPage('manage_config', async () => {
onSave={(value) => { onSave={(value) => {
request.post('', { value }).then(() => { request.post('', { value }).then(() => {
Notification.success(i18n('Changes saved successfully')); Notification.success(i18n('Changes saved successfully'));
window.location.reload();
}).catch((e) => { }).catch((e) => {
Notification.error(i18n('Failed to save changes:'), e.message); Notification.error(i18n('Failed to save changes:'), e.message);
}); });
@@ -25,7 +25,7 @@
<li class="footer__category__item"><a href="https://github.com/hydro-dev/Hydro" target="_blank">{{ _('Open Source') }}</a></li> <li class="footer__category__item"><a href="https://github.com/hydro-dev/Hydro" target="_blank">{{ _('Open Source') }}</a></li>
</ul></div> </ul></div>
</div> </div>
<div class="medium-3 large-2 columns footer__category expandable end"> <div class="medium-3 large-2 columns footer__category expandable">
<h1> <h1>
{{ _('Support') }} {{ _('Support') }}
<span class="expand-icon"> <span class="expand-icon">
@@ -34,7 +34,21 @@
</h1> </h1>
<div class="footer__category__expander"><ul class="footer__category__list"> <div class="footer__category__expander"><ul class="footer__category__list">
<li class="footer__category__item"><a href="{{ url('wiki_help') }}">{{ _('Help') }}</a></li> <li class="footer__category__item"><a href="{{ url('wiki_help') }}">{{ _('Help') }}</a></li>
<li class="footer__category__item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('QQ Group') }}</a></li> <li class="footer__category__item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Contact Us') }}</a></li>
</ul></div>
</div>
<div class="medium-3 large-2 columns footer__category expandable end">
<h1>
{{ _('About') }}
<span class="expand-icon">
<span class="icon icon-expand_more"></span>
</span>
</h1>
<div class="footer__category__expander"><ul class="footer__category__list">
<li class="footer__category__item"><a href="{{ url('wiki_about') }}">{{ _('About') }}</a></li>
<li class="footer__category__item"><a href="{{ url('wiki_about', anchor='privacy') }}">{{ _('Privacy') }}</a></li>
<li class="footer__category__item"><a href="{{ url('wiki_about', anchor='tos') }}">{{ _('Terms of Service') }}</a></li>
<li class="footer__category__item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Copyright Complaint') }}</a></li>
</ul></div> </ul></div>
</div> </div>
</div> </div>
@@ -42,11 +56,13 @@
<div class="footer__extra-link clearfix"> <div class="footer__extra-link clearfix">
<div class="footer__extra-left"> <div class="footer__extra-left">
<ol class="clearfix"> <ol class="clearfix">
{% if not show_topics|default(true) %}
<li class="footer__extra-link-item"><a href="{{ url('wiki_about') }}">{{ _('About') }}</a></li> <li class="footer__extra-link-item"><a href="{{ url('wiki_about') }}">{{ _('About') }}</a></li>
<li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Contact Us') }}</a></li> <li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Contact Us') }}</a></li>
<li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='privacy') }}">{{ _('Privacy') }}</a></li> <li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='privacy') }}">{{ _('Privacy') }}</a></li>
<li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='tos') }}">{{ _('Terms of Service') }}</a></li> <li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='tos') }}">{{ _('Terms of Service') }}</a></li>
<li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Copyright Complaint') }}</a></li> <li class="footer__extra-link-item"><a href="{{ url('wiki_about', anchor='contact') }}">{{ _('Copyright Complaint') }}</a></li>
{% endif %}
<li class="footer__extra-link-item nojs--hide" data-dropdown-target="#menu-footer-lang"> <li class="footer__extra-link-item nojs--hide" data-dropdown-target="#menu-footer-lang">
<span><span class="icon icon-global"></span> Language <span class="icon icon-expand_less"></span></span> <span><span class="icon icon-global"></span> Language <span class="icon icon-expand_less"></span></span>
<ol class="dropdown-target menu" id="menu-footer-lang"> <ol class="dropdown-target menu" id="menu-footer-lang">