chore: 初始化项目骨架

This commit is contained in:
SkyJourney
2026-07-25 16:51:16 +08:00
commit ec48bce0a6
26 changed files with 3806 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="可配置、可主题化的 Markdown PDF 导出工具"
/>
<title>Markdown PDF 导出器</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+22
View File
@@ -0,0 +1,22 @@
{
"name": "@md-to-pdf/web",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"typecheck": "tsc -b --pretty false"
},
"dependencies": {
"@md-to-pdf/core": "0.1.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"vite": "^7.2.4"
}
}
+61
View File
@@ -0,0 +1,61 @@
import { defaultExportConfig, paperFormatLabels } from "@md-to-pdf/core";
const capabilities = [
"Markdown 本地预览",
"Chromium PDF 下载",
"纸张与页边距",
"页眉、页脚与页码",
"可扩展 CSS 主题"
];
export function App() {
return (
<main className="shell">
<section className="intro" aria-labelledby="page-title">
<p className="eyebrow"></p>
<h1 id="page-title">Markdown PDF </h1>
<p className="summary">
使 HTML CSS Chromium PDF
</p>
<div className="status">
<span className="status-dot" aria-hidden="true" />
</div>
</section>
<section className="panel" aria-labelledby="config-title">
<div>
<p className="panel-label"></p>
<h2 id="config-title">{defaultExportConfig.name}</h2>
</div>
<dl className="facts">
<div>
<dt></dt>
<dd>{paperFormatLabels[defaultExportConfig.paper.format]}</dd>
</div>
<div>
<dt></dt>
<dd>
{defaultExportConfig.paper.orientation === "portrait"
? "纵向"
: "横向"}
</dd>
</div>
<div>
<dt></dt>
<dd>{defaultExportConfig.themeId}</dd>
</div>
</dl>
</section>
<section className="capabilities" aria-label="规划能力">
{capabilities.map((item, index) => (
<article key={item}>
<span>{String(index + 1).padStart(2, "0")}</span>
<p>{item}</p>
</article>
))}
</section>
</main>
);
}
+16
View File
@@ -0,0 +1,16 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";
import "./styles.css";
const rootElement = document.getElementById("root");
if (!rootElement) {
throw new Error("未找到应用挂载节点");
}
createRoot(rootElement).render(
<StrictMode>
<App />
</StrictMode>
);
+194
View File
@@ -0,0 +1,194 @@
:root {
color: #1d2522;
background:
radial-gradient(circle at 12% 10%, rgb(197 225 210 / 45%), transparent 30rem),
#f2f0e9;
font-family:
Inter, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-width: 320px;
min-height: 100vh;
}
button,
input,
select,
textarea {
font: inherit;
}
.shell {
width: min(1120px, calc(100% - 40px));
margin: 0 auto;
padding: 88px 0;
}
.intro {
max-width: 760px;
}
.eyebrow,
.panel-label {
margin: 0 0 14px;
color: #34705a;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.16em;
text-transform: uppercase;
}
h1,
h2,
p {
margin-top: 0;
}
h1 {
max-width: 700px;
margin-bottom: 22px;
font-family: Georgia, "Songti SC", serif;
font-size: clamp(3rem, 8vw, 6.4rem);
font-weight: 500;
letter-spacing: -0.055em;
line-height: 0.94;
}
.summary {
max-width: 610px;
margin-bottom: 28px;
color: #56615d;
font-size: 1.15rem;
line-height: 1.7;
}
.status {
display: inline-flex;
align-items: center;
gap: 10px;
color: #315a4b;
font-size: 0.9rem;
font-weight: 650;
}
.status-dot {
width: 9px;
height: 9px;
border-radius: 50%;
background: #3da073;
box-shadow: 0 0 0 5px rgb(61 160 115 / 13%);
}
.panel {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(420px, 1.25fr);
gap: 48px;
align-items: end;
margin-top: 80px;
padding: 34px;
border: 1px solid rgb(41 64 55 / 14%);
border-radius: 20px;
background: rgb(255 255 255 / 58%);
box-shadow: 0 24px 60px rgb(49 67 59 / 8%);
backdrop-filter: blur(18px);
}
.panel h2 {
margin-bottom: 0;
font-family: Georgia, "Songti SC", serif;
font-size: clamp(1.8rem, 4vw, 3rem);
font-weight: 500;
}
.facts {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin: 0;
}
.facts div {
padding: 18px;
border-radius: 13px;
background: #e6ebe6;
}
.facts dt {
margin-bottom: 7px;
color: #6b756f;
font-size: 0.75rem;
}
.facts dd {
margin: 0;
font-weight: 700;
}
.capabilities {
display: grid;
grid-template-columns: repeat(5, 1fr);
margin-top: 20px;
border-top: 1px solid rgb(41 64 55 / 16%);
}
.capabilities article {
min-height: 132px;
padding: 20px 16px;
border-right: 1px solid rgb(41 64 55 / 16%);
}
.capabilities article:last-child {
border-right: 0;
}
.capabilities span {
color: #7e8983;
font-family: Georgia, serif;
font-size: 0.75rem;
}
.capabilities p {
margin: 42px 0 0;
font-size: 0.92rem;
font-weight: 650;
line-height: 1.45;
}
@media (max-width: 760px) {
.shell {
width: min(100% - 28px, 1120px);
padding: 48px 0;
}
.panel {
grid-template-columns: 1fr;
margin-top: 56px;
padding: 24px;
}
.facts {
grid-template-columns: 1fr;
}
.capabilities {
grid-template-columns: 1fr;
}
.capabilities article {
min-height: auto;
border-right: 0;
border-bottom: 1px solid rgb(41 64 55 / 16%);
}
.capabilities p {
margin-top: 16px;
}
}
+25
View File
@@ -0,0 +1,25 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"target": "ES2022",
"useDefineForClassFields": true,
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"allowJs": false,
"module": "ESNext",
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"noEmit": true
},
"include": [
"src",
"vite.config.ts"
]
}
+12
View File
@@ -0,0 +1,12 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
proxy: {
"/api": "http://localhost:3001"
}
}
});