84 lines
5.1 KiB
Vue
84 lines
5.1 KiB
Vue
<!-- SPEC: PJ2026-010405 云端控制台. -->
|
||
<!-- Implementation reference: draft-2026-07-13-p0-cloud-console. -->
|
||
|
||
<script setup lang="ts">
|
||
import { computed, onMounted, ref } from "vue";
|
||
import { fetchText } from "@/api";
|
||
import ContentViewer from "@/components/common/ContentViewer.vue";
|
||
import EmptyState from "@/components/common/EmptyState.vue";
|
||
import PageCommandBar from "@/components/layout/PageCommandBar.vue";
|
||
import StatusStrip from "@/components/layout/StatusStrip.vue";
|
||
|
||
const help = ref("");
|
||
const loading = ref(true);
|
||
const error = ref<string | null>(null);
|
||
const helpStatusItems = computed(() => [
|
||
{ id: "source", label: "Source", value: "/help.md" },
|
||
{ id: "render", label: "Render", value: "sanitized Markdown" },
|
||
{ id: "state", label: "State", value: loading.value ? "loading" : error.value ? "error" : "ready", tone: error.value ? "error" as const : loading.value ? "info" as const : "ok" as const }
|
||
]);
|
||
|
||
onMounted(async () => {
|
||
const response = await fetchText("/help.md", { timeoutMs: 8000 });
|
||
help.value = response.ok ? response.data ?? "" : "";
|
||
error.value = response.ok ? null : response.error ?? "帮助内容加载失败";
|
||
loading.value = false;
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<section class="route-stack help-page">
|
||
<PageCommandBar eyebrow="System" title="帮助" description="同源加载仓库维护的帮助文档,以可阅读的 Markdown 呈现。" />
|
||
<StatusStrip :items="helpStatusItems" label="帮助内容状态" />
|
||
<EmptyState v-if="loading" title="正在加载帮助" description="读取 Cloud Web 同源 help.md。" />
|
||
<EmptyState v-else-if="error" title="帮助内容不可用" :description="error" />
|
||
<section v-else class="help-workspace">
|
||
<ContentViewer class="help-document" :content="help" mode="markdown" title="HWLAB 帮助" filename="help.md" :line-numbers="false" />
|
||
<aside class="help-context">
|
||
<span>DOCUMENT CONTRACT</span>
|
||
<h2>可阅读,不执行</h2>
|
||
<p>Markdown 来自同源静态资源,渲染前经过 HTML 清理。代码块和长路径在文档区内部滚动,不扩张页面宽度。</p>
|
||
<dl><div><dt>Cookie</dt><dd>不展示</dd></div><div><dt>Secret</dt><dd>不读取</dd></div><div><dt>外链</dt><dd>由文档声明</dd></div></dl>
|
||
</aside>
|
||
</section>
|
||
</section>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.help-page { min-width: 0; }
|
||
.help-status-strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid #cbd6dc; border-radius: 8px; overflow: hidden; background: #18343c; color: #f0ffff; box-shadow: inset 3px 0 #20afa8; }
|
||
.help-status-strip div { display: grid; gap: 5px; min-width: 0; padding: 10px 13px; border-left: 1px solid rgba(211, 240, 238, .15); }
|
||
.help-status-strip div:first-child { border-left: 0; }
|
||
.help-status-strip span,
|
||
.help-context > span { color: #80d4ce; font: 850 9px/1 ui-monospace, monospace; letter-spacing: .12em; }
|
||
.help-status-strip strong { overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
||
.help-workspace { display: grid; grid-template-columns: minmax(0, 1fr) minmax(250px, 310px); gap: 12px; min-height: 0; }
|
||
.help-document,
|
||
.help-context { min-width: 0; border: 1px solid #cfd9de; border-radius: 9px; background: #fff; }
|
||
.help-document { padding: clamp(18px, 3vw, 34px); color: #293c45; font-size: 13px; line-height: 1.75; box-shadow: inset 3px 0 #20aaa4; }
|
||
.help-document :deep(h1) { margin: 0 0 22px; color: #142c35; font-size: 27px; letter-spacing: -.02em; }
|
||
.help-document :deep(h2) { margin: 30px 0 12px; border-bottom: 1px solid #dbe4e8; padding-bottom: 7px; color: #173b42; font-size: 18px; }
|
||
.help-document :deep(h3) { margin: 22px 0 8px; color: #23555a; font-size: 15px; }
|
||
.help-document :deep(p),
|
||
.help-document :deep(li) { color: #4f626c; }
|
||
.help-document :deep(code) { border-radius: 4px; background: #e9f0f1; padding: 2px 5px; color: #155e61; font: 11px/1.5 ui-monospace, monospace; overflow-wrap: anywhere; }
|
||
.help-document :deep(pre) { max-width: 100%; overflow: auto; border: 1px solid #2f5058; border-radius: 7px; background: #172d34; padding: 12px; color: #e8ffff; }
|
||
.help-document :deep(pre code) { background: transparent; padding: 0; color: inherit; }
|
||
.help-document :deep(a) { color: #087f7a; font-weight: 700; }
|
||
.help-context { position: sticky; top: 0; align-self: start; padding: 15px; background: linear-gradient(150deg, #18343c, #224851); color: #efffff; }
|
||
.help-context h2 { margin: 6px 0 0; font-size: 17px; }
|
||
.help-context p { color: #bfd2d2; font-size: 11px; line-height: 1.65; }
|
||
.help-context dl { display: grid; gap: 0; margin: 13px 0 0; }
|
||
.help-context dl div { display: flex; justify-content: space-between; gap: 10px; border-top: 1px solid rgba(216, 240, 238, .17); padding: 8px 0; font-size: 10px; }
|
||
.help-context dd { margin: 0; color: #92d9d4; font-weight: 750; }
|
||
@media (max-width: 880px) {
|
||
.help-workspace { grid-template-columns: 1fr; }
|
||
.help-context { position: static; }
|
||
}
|
||
@media (max-width: 560px) {
|
||
.help-status-strip { grid-template-columns: 1fr; }
|
||
.help-status-strip div { border-left: 0; border-top: 1px solid rgba(211, 240, 238, .15); }
|
||
.help-status-strip div:first-child { border-top: 0; }
|
||
}
|
||
</style>
|