feat: 添加 Sarasa Mono 字体支持并优化样式

This commit is contained in:
2026-04-12 13:29:17 +08:00
parent c0c0cc19b2
commit af78359d94
5 changed files with 233 additions and 8 deletions

View File

@@ -7,6 +7,64 @@ require_once ("../include/my_func.inc.php");
<!DOCTYPE html> <!DOCTYPE html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel=stylesheet href='../include/hoj.css' type='text/css'> <link rel=stylesheet href='../include/hoj.css' type='text/css'>
<style>
@font-face {
font-family: 'Sarasa Mono SC Local';
src: local('等距更纱黑体 SC'),
local('Sarasa Mono SC'),
url('../template/syzoj/fonts/SarasaMonoSC-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
:root {
--hustoj-admin-font-family: 'Sarasa Mono SC Local', '等距更纱黑体 SC', 'Sarasa Mono SC', 'Sarasa Fixed SC', 'Sarasa Gothic SC', Consolas, 'Cascadia Mono', 'JetBrains Mono', 'Courier New', monospace;
--hustoj-admin-font-size: 26px;
--hustoj-admin-heading-size: 30px;
--hustoj-admin-subheading-size: 28px;
--hustoj-admin-line-height: 1.6;
}
body,
input,
textarea,
select,
button,
table,
pre,
code,
.btn,
.ui.button,
.ui.input input,
.ui.form textarea,
.ui.form select,
.ui.label,
.ui.segment,
.ui.message,
.ui.table,
.vditor,
.vditor-reset,
.vditor-reset * {
font-family: var(--hustoj-admin-font-family) !important;
font-size: var(--hustoj-admin-font-size) !important;
line-height: var(--hustoj-admin-line-height) !important;
}
h1,
h2,
h3,
.h-head,
.h2-head {
font-size: var(--hustoj-admin-heading-size) !important;
}
h4,
h5,
h6 {
font-size: var(--hustoj-admin-subheading-size) !important;
}
</style>
<script src="../template/syzoj/jquery.min.js"></script> <script src="../template/syzoj/jquery.min.js"></script>
<script> <script>
$("document").ready(function (){ $("document").ready(function (){

View File

@@ -36,7 +36,18 @@
return scriptSrc.replace(/\/include\/vditor-adapter\.js(?:[?#].*)?$/, '/ace'); return scriptSrc.replace(/\/include\/vditor-adapter\.js(?:[?#].*)?$/, '/ace');
} }
function getLocalSarasaFontUrl() {
var scriptSrc = currentScriptRef && currentScriptRef.src;
if (!scriptSrc) {
return 'template/syzoj/fonts/SarasaMonoSC-Regular.ttf';
}
return scriptSrc.replace(/\/include\/vditor-adapter\.js(?:[?#].*)?$/, '/template/syzoj/fonts/SarasaMonoSC-Regular.ttf');
}
function injectAdapterStyle() { function injectAdapterStyle() {
var sarasaFontUrl = getLocalSarasaFontUrl();
var style; var style;
if (styleInjected) { if (styleInjected) {
@@ -47,13 +58,19 @@
style.type = 'text/css'; style.type = 'text/css';
style.setAttribute('data-hustoj-vditor', 'adapter-style'); style.setAttribute('data-hustoj-vditor', 'adapter-style');
style.textContent = [ style.textContent = [
'@font-face{font-family:"Sarasa Mono SC Local";src:local("等距更纱黑体 SC"),local("Sarasa Mono SC"),url("' + sarasaFontUrl + '") format("truetype");font-weight:400;font-style:normal;font-display:swap;}',
'.hustoj-vditor-hidden{display:none !important;}', '.hustoj-vditor-hidden{display:none !important;}',
'.hustoj-vditor-wrapper{width:100%;margin:0 0 12px;}', '.hustoj-vditor-wrapper{width:100%;margin:0 0 12px;}',
'.hustoj-vditor-code{--hustoj-vditor-font-size:18px;text-align:left;}', '.hustoj-vditor-wrapper,.hustoj-vditor-preview,.hustoj-vditor-markdown,.hustoj-vditor-code{--hustoj-vditor-font-family:"Sarasa Mono SC Local","等距更纱黑体 SC","Sarasa Mono SC","Sarasa Fixed SC","Sarasa Gothic SC",Consolas,"Cascadia Mono","JetBrains Mono","Courier New",monospace;--hustoj-vditor-font-size:24px;--hustoj-vditor-preview-code-font-size:24px;}',
'.hustoj-vditor-markdown,.hustoj-vditor-markdown .vditor,.hustoj-vditor-markdown .vditor-content,.hustoj-vditor-markdown .vditor-ir,.hustoj-vditor-markdown .vditor-sv,.hustoj-vditor-markdown .vditor-reset,.hustoj-vditor-markdown .vditor-wysiwyg,.hustoj-vditor-markdown .vditor-sv__preview{text-align:left !important;}',
'.hustoj-vditor-markdown .vditor{margin-left:0 !important;margin-right:auto !important;}',
'.hustoj-vditor-markdown .vditor-toolbar{justify-content:flex-start;}',
'.hustoj-vditor-markdown .vditor-content,.hustoj-vditor-markdown .vditor-reset,.hustoj-vditor-markdown .vditor-reset *,.hustoj-vditor-markdown textarea{font-family:var(--hustoj-vditor-font-family) !important;}',
'.hustoj-vditor-code{text-align:left;}',
'.hustoj-vditor-code.ace_editor{position:relative;border:1px solid #d4d4d5;border-radius:6px;line-height:1.5;}', '.hustoj-vditor-code.ace_editor{position:relative;border:1px solid #d4d4d5;border-radius:6px;line-height:1.5;}',
'.hustoj-vditor-code .ace_scroller,', '.hustoj-vditor-code .ace_scroller,',
'.hustoj-vditor-code .ace_gutter,', '.hustoj-vditor-code .ace_gutter,',
'.hustoj-vditor-code .ace_content{font-family:Consolas,Monaco,"Courier New",monospace !important;font-size:var(--hustoj-vditor-font-size) !important;line-height:1.5 !important;}', '.hustoj-vditor-code .ace_content{font-family:var(--hustoj-vditor-font-family) !important;font-size:var(--hustoj-vditor-font-size) !important;line-height:1.5 !important;}',
'.hustoj-vditor-code .ace_gutter{background:#f8f8f8;color:#8a8a8a;}', '.hustoj-vditor-code .ace_gutter{background:#f8f8f8;color:#8a8a8a;}',
'.hustoj-vditor-dark.ace_editor{background:#272822;border-color:#4a4a4a;}', '.hustoj-vditor-dark.ace_editor{background:#272822;border-color:#4a4a4a;}',
'.hustoj-vditor-dark .ace_gutter{background:#2f3129;color:#bcbcbc;}', '.hustoj-vditor-dark .ace_gutter{background:#2f3129;color:#bcbcbc;}',
@@ -63,7 +80,7 @@
'.hustoj-vditor-code .vditor-reset,', '.hustoj-vditor-code .vditor-reset,',
'.hustoj-vditor-code .vditor-content,', '.hustoj-vditor-code .vditor-content,',
'.hustoj-vditor-code .vditor,', '.hustoj-vditor-code .vditor,',
'.hustoj-vditor-code textarea{text-align:left !important;font-family:Consolas,Monaco,"Courier New",monospace !important;font-size:var(--hustoj-vditor-font-size) !important;line-height:1.5 !important;}', '.hustoj-vditor-code textarea{text-align:left !important;font-family:var(--hustoj-vditor-font-family) !important;font-size:var(--hustoj-vditor-font-size) !important;line-height:1.5 !important;}',
'.hustoj-vditor-code .vditor-sv,', '.hustoj-vditor-code .vditor-sv,',
'.hustoj-vditor-code .vditor-ir{min-height:100%;}', '.hustoj-vditor-code .vditor-ir{min-height:100%;}',
'.hustoj-vditor-dark .vditor{background:#272822;border-color:#4a4a4a;}', '.hustoj-vditor-dark .vditor{background:#272822;border-color:#4a4a4a;}',
@@ -74,11 +91,13 @@
'.hustoj-vditor-mail .vditor-toolbar{border-bottom:1px solid #ddd;}', '.hustoj-vditor-mail .vditor-toolbar{border-bottom:1px solid #ddd;}',
'.hustoj-vditor-mail .vditor{height:100%;min-height:180px;}', '.hustoj-vditor-mail .vditor{height:100%;min-height:180px;}',
'.hustoj-vditor-preview .vditor-reset pre{position:relative;margin:16px 0;padding:16px 18px;border:1px solid #cfd7e6;border-radius:12px;background:linear-gradient(180deg,#f9fbff 0%,#f3f7ff 100%);box-shadow:0 8px 20px rgba(15,23,42,0.06);}', '.hustoj-vditor-preview .vditor-reset pre{position:relative;margin:16px 0;padding:16px 18px;border:1px solid #cfd7e6;border-radius:12px;background:linear-gradient(180deg,#f9fbff 0%,#f3f7ff 100%);box-shadow:0 8px 20px rgba(15,23,42,0.06);}',
'.hustoj-vditor-preview .vditor-reset pre code{display:block;font-size:15px;line-height:1.7;}', '.hustoj-vditor-preview .vditor-reset pre code{display:block;font-family:var(--hustoj-vditor-font-family) !important;font-size:var(--hustoj-vditor-preview-code-font-size) !important;line-height:1.7;}',
'.hustoj-vditor-preview .vditor-copy{display:block !important;position:absolute;top:12px;right:12px;z-index:2;}', '.hustoj-vditor-preview .vditor-reset pre div.vditor-copy{display:block !important;opacity:1 !important;visibility:visible !important;position:absolute;top:12px;right:12px;z-index:2;}',
'.hustoj-vditor-preview .vditor-copy span{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid #c8d3e6;border-radius:999px;background:rgba(255,255,255,0.96);box-shadow:0 4px 12px rgba(15,23,42,0.08);font-size:12px;font-weight:600;color:#2f4f7f;}', '.hustoj-vditor-preview .vditor-copy span{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid #c8d3e6;border-radius:999px;background:rgba(255,255,255,0.96);box-shadow:0 4px 12px rgba(15,23,42,0.08);font-size:12px;font-weight:600;color:#2f4f7f;position:static !important;}',
'.hustoj-vditor-preview .vditor-copy span::after{content:attr(aria-label);}', '.hustoj-vditor-preview .vditor-copy span::after{content:attr(aria-label);}',
'.hustoj-vditor-preview .vditor-copy svg{width:14px !important;height:14px !important;color:currentColor;}', '.hustoj-vditor-preview .vditor-copy svg{width:14px !important;height:14px !important;color:currentColor;}',
'.hustoj-vditor-preview .hustoj-vditor-sample-heading{display:flex;align-items:center;margin:24px 0 0;padding:12px 16px;border:1px solid #d6dde8;border-bottom:0;border-radius:14px 14px 0 0;background:#eef4ff;color:#274061;font-size:1.05em;font-weight:700;line-height:1.4;}',
'.hustoj-vditor-preview .vditor-reset pre.hustoj-vditor-sample-box{margin-top:0;border-top-left-radius:0;border-top-right-radius:0;border-top-color:#d6dde8;padding-top:52px;}',
'.hustoj-vditor-preview .vditor-reset .language-mermaid,', '.hustoj-vditor-preview .vditor-reset .language-mermaid,',
'.hustoj-vditor-preview .vditor-reset .language-flowchart{margin:18px 0;padding:14px;border:1px solid #d7dce5;border-radius:12px;background:#fff;overflow:auto;text-align:center;}', '.hustoj-vditor-preview .vditor-reset .language-flowchart{margin:18px 0;padding:14px;border:1px solid #d7dce5;border-radius:12px;background:#fff;overflow:auto;text-align:center;}',
'.hustoj-vditor-preview .vditor-reset .language-mermaid svg,', '.hustoj-vditor-preview .vditor-reset .language-mermaid svg,',
@@ -466,6 +485,8 @@
element.classList.add('hustoj-vditor-preview'); element.classList.add('hustoj-vditor-preview');
decorateSampleBlocks(element);
Array.prototype.forEach.call( Array.prototype.forEach.call(
element.querySelectorAll('.language-mermaid, .language-flowchart'), element.querySelectorAll('.language-mermaid, .language-flowchart'),
function (diagramContainer) { function (diagramContainer) {
@@ -497,6 +518,73 @@
); );
} }
function normalizeHeadingText(text) {
return String(text || '').replace(/\s+/g, ' ').trim();
}
function parseSampleHeading(text) {
var normalized = normalizeHeadingText(text).replace(/[:]+$/, '');
var match = normalized.match(/^(?:(?:样例|示例|sample|example)\s*)?(输入|输出|input|output)\s*([0-9]+)?$/i);
var kind;
if (!match) {
return null;
}
kind = match[1].toLowerCase();
if (kind === '输入' || kind === 'input') {
kind = 'input';
} else {
kind = 'output';
}
return {
kind: kind,
index: match[2] || ''
};
}
function getSiblingCodeBlock(heading) {
var sibling = heading ? heading.nextElementSibling : null;
while (sibling && sibling.tagName === 'P' && !normalizeHeadingText(sibling.textContent)) {
sibling = sibling.nextElementSibling;
}
if (!sibling || sibling.tagName !== 'PRE') {
return null;
}
return sibling;
}
function decorateSampleBlocks(element) {
Array.prototype.forEach.call(element.querySelectorAll('h1, h2, h3, h4, h5, h6'), function (heading) {
var sampleMeta = parseSampleHeading(heading.textContent);
var codeBlock;
if (!sampleMeta) {
return;
}
codeBlock = getSiblingCodeBlock(heading);
if (!codeBlock) {
return;
}
heading.classList.add('hustoj-vditor-sample-heading');
heading.setAttribute('data-hustoj-sample-kind', sampleMeta.kind);
if (sampleMeta.index) {
heading.setAttribute('data-hustoj-sample-index', sampleMeta.index);
}
codeBlock.classList.add('hustoj-vditor-sample-box');
codeBlock.setAttribute('data-hustoj-sample-kind', sampleMeta.kind);
if (sampleMeta.index) {
codeBlock.setAttribute('data-hustoj-sample-index', sampleMeta.index);
}
});
}
function renderMarkdownBlocks(target, options) { function renderMarkdownBlocks(target, options) {
var renderOptions = options || {}; var renderOptions = options || {};
@@ -732,7 +820,7 @@
state = { state = {
theme: options.theme || 'ace/theme/chrome', theme: options.theme || 'ace/theme/chrome',
fontSize: parseInt(options.fontSize, 10) || 18, fontSize: parseInt(options.fontSize, 10) || 24,
mode: normalizeMode(options.mode || ''), mode: normalizeMode(options.mode || ''),
wrap: true wrap: true
}; };

View File

@@ -1,10 +1,25 @@
@import url('../../bs3/bootstrap.min.css'); @import url('../../bs3/bootstrap.min.css');
@font-face {
font-family: 'Sarasa Mono SC Local';
src: local('等距更纱黑体 SC'),
local('Sarasa Mono SC'),
url('../fonts/SarasaMonoSC-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
:root { :root {
--hustoj-global-mono-font: "Sarasa Mono SC", "Sarasa Fixed SC", --hustoj-global-mono-font: 'Sarasa Mono SC Local', "Sarasa Mono SC", "Sarasa Fixed SC",
"Sarasa Gothic SC", Consolas, "Cascadia Mono", "Cascadia Code", "Sarasa Gothic SC", Consolas, "Cascadia Mono", "Cascadia Code",
"Fira Mono", "JetBrains Mono", "Liberation Mono", Menlo, Monaco, "Fira Mono", "JetBrains Mono", "Liberation Mono", Menlo, Monaco,
"Courier New", monospace; "Courier New", monospace;
--hustoj-global-font-size: 26px;
--hustoj-global-line-height: 1.6;
--hustoj-global-code-font-size: 24px;
--hustoj-global-heading-size: 30px;
--hustoj-global-subheading-size: 28px;
} }
.ui.header, .ui.header,
@@ -30,6 +45,8 @@ h4,
h5, h5,
body { body {
font-family: var(--hustoj-global-mono-font) !important; font-family: var(--hustoj-global-mono-font) !important;
font-size: var(--hustoj-global-font-size) !important;
line-height: var(--hustoj-global-line-height);
} }
a.black-link { a.black-link {
@@ -42,12 +59,29 @@ a.black-link:hover {
.font-content { .font-content {
font-family: var(--hustoj-global-mono-font) !important; font-family: var(--hustoj-global-mono-font) !important;
font-size: var(--hustoj-global-font-size) !important;
line-height: var(--hustoj-global-line-height);
} }
.markdown-edit { .markdown-edit {
font-family: var(--hustoj-global-mono-font) !important; font-family: var(--hustoj-global-mono-font) !important;
} }
h1,
.ui.header.huge,
.ui.header.large {
font-size: var(--hustoj-global-heading-size) !important;
}
h2,
h3,
h4,
h5,
.ui.header,
.ui.top.attached.block.header {
font-size: var(--hustoj-global-subheading-size) !important;
}
.ui.form textarea, .ui.form textarea,
.ui.form select, .ui.form select,
.ui.text.container, .ui.text.container,
@@ -72,6 +106,49 @@ a.black-link:hover {
.ace_line, .ace_line,
.ace_text-layer { .ace_text-layer {
font-family: var(--hustoj-global-mono-font) !important; font-family: var(--hustoj-global-mono-font) !important;
font-size: var(--hustoj-global-font-size) !important;
line-height: var(--hustoj-global-line-height) !important;
}
.ui.button,
.ui.input input,
.ui.form textarea,
.ui.form select,
.ui.message,
.ui.label,
.ui.dropdown,
.ui.table,
.ui.card > .content,
.ui.cards > .card > .content,
.ui.list > .item,
.ui.list .list > .item,
.ui.statistic > .value,
.ui.statistic > .label,
.vditor,
.vditor-reset,
.vditor-reset *,
pre,
code,
.ace_editor,
.ace_editor textarea,
.ace_content,
.ace_gutter,
.ace_line,
.ace_text-layer {
font-size: var(--hustoj-global-font-size) !important;
}
pre,
code,
.ace_editor,
.ace_editor textarea,
.ace_content,
.ace_gutter,
.ace_line,
.ace_text-layer,
.sample-box code,
.vditor-reset pre code {
font-size: var(--hustoj-global-code-font-size) !important;
} }
.padding { .padding {

Binary file not shown.

View File

@@ -697,6 +697,8 @@ if ($pr_flag) {
return HustOJVditor.renderMarkdownBlocks('.md').then(function () { return HustOJVditor.renderMarkdownBlocks('.md').then(function () {
addMarkdownInputOutputLabels(); addMarkdownInputOutputLabels();
styleMarkdownTables(); styleMarkdownTables();
$('.md .hustoj-vditor-sample-heading').addClass('ui top attached block header sample-header');
$('.md pre.hustoj-vditor-sample-box').addClass('ui bottom attached segment font-content sample-box');
}); });
<?php } ?> <?php } ?>
return Promise.resolve([]); return Promise.resolve([]);