Skip to content

Commit ec2e377

Browse files
Start adding styles to markdown
1 parent a929764 commit ec2e377

5 files changed

Lines changed: 325 additions & 13 deletions

File tree

frontend/kubecloud-v2/assets/scss/vuetify.scss

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,145 @@
1111

1212
.rounded-xl {
1313
border-radius: 18px !important;
14-
}
14+
}
15+
16+
// markdown styles
17+
.markdown {
18+
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
19+
Roboto, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif;
20+
line-height: 1.7;
21+
color: #c9d1d9;
22+
background-color: #0d1117;
23+
max-width: 900px;
24+
margin: 0 auto;
25+
padding: 24px;
26+
word-wrap: break-word;
27+
28+
/* Headings */
29+
h1,
30+
h2,
31+
h3,
32+
h4,
33+
h5,
34+
h6 {
35+
color: #e6edf3;
36+
font-weight: 600;
37+
margin: 24px 0 16px;
38+
line-height: 1.25;
39+
}
40+
41+
h1 {
42+
font-size: 2.2em;
43+
border-bottom: 1px solid #30363d;
44+
padding-bottom: 0.3em;
45+
}
46+
47+
h2 {
48+
font-size: 1.7em;
49+
border-bottom: 1px solid #30363d;
50+
padding-bottom: 0.3em;
51+
}
52+
53+
h3 { font-size: 1.4em; }
54+
h4 { font-size: 1.2em; }
55+
56+
/* Paragraphs */
57+
p {
58+
margin: 0 0 16px;
59+
}
60+
61+
/* Links */
62+
a {
63+
color: #58a6ff;
64+
text-decoration: none;
65+
}
66+
67+
a:hover {
68+
text-decoration: underline;
69+
}
70+
71+
/* Lists */
72+
ul,
73+
ol {
74+
margin: 0 0 16px 24px;
75+
}
76+
77+
li {
78+
margin: 6px 0;
79+
}
80+
81+
/* Blockquotes */
82+
blockquote {
83+
margin: 16px 0;
84+
padding: 0.75em 1em;
85+
color: #8b949e;
86+
background: #161b22;
87+
border-left: 4px solid #30363d;
88+
}
89+
90+
/* Inline code */
91+
code {
92+
font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
93+
font-size: 0.95em;
94+
background: #161b22;
95+
color: #e6edf3;
96+
padding: 0.2em 0.4em;
97+
border-radius: 6px;
98+
}
99+
100+
/* Code blocks */
101+
pre {
102+
background: #010409;
103+
color: #c9d1d9;
104+
padding: 16px;
105+
overflow: auto;
106+
border-radius: 10px;
107+
margin: 16px 0;
108+
border: 1px solid #30363d;
109+
}
110+
111+
pre code {
112+
background: none;
113+
padding: 0;
114+
color: inherit;
115+
}
116+
117+
/* Tables */
118+
table {
119+
border-collapse: collapse;
120+
width: 100%;
121+
margin: 16px 0;
122+
}
123+
124+
th,
125+
td {
126+
border: 1px solid #30363d;
127+
padding: 8px 12px;
128+
}
129+
130+
th {
131+
background: #161b22;
132+
font-weight: 600;
133+
}
134+
135+
/* Images */
136+
img {
137+
max-width: 100%;
138+
display: block;
139+
margin: 16px auto;
140+
border-radius: 8px;
141+
}
142+
143+
/* Horizontal rule */
144+
hr {
145+
border: none;
146+
border-top: 1px solid #30363d;
147+
margin: 24px 0;
148+
}
149+
150+
/* Selection */
151+
::selection {
152+
background: #264f78;
153+
}
154+
155+
}

frontend/kubecloud-v2/composables/docs.ts

Lines changed: 177 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export interface Doc {
1414
}
1515

1616
export const useDocs = createGlobalState(() => {
17+
// const router = useRouter()
18+
1719
return useAsyncState(async () => {
1820
const res = await fetch("/docs/docs.yaml")
1921
const data = await res.text()
@@ -24,21 +26,187 @@ export const useDocs = createGlobalState(() => {
2426
.then(res => res.text())),
2527
)
2628

27-
marked.use({
28-
renderer: {
29-
blockquote({ tokens }) {
30-
const text = this.parser.parse(tokens)
31-
return `<blockquote class="d-block px-4 py-6 border-s-lg border-primary bg-surface mb-4 overflow-auto" style="--v-border-opacity: 1;">${text}</blockquote>`
32-
},
33-
},
34-
})
29+
const renderer = new marked.Renderer()
30+
31+
renderer.heading = function ({ depth, tokens }) {
32+
const content = this.parser.parseInline(tokens)
33+
const lv = Math.min(depth + 3, 6)
34+
return `<h${lv} class="text-h${lv} mb-2">${content}</h${lv}>`
35+
}
36+
37+
renderer.paragraph = function ({ tokens }) {
38+
const content = this.parser.parseInline(tokens)
39+
return `<p class="text-body-1 text-accent mt-2 mb-4">${content}</p>`
40+
}
41+
42+
renderer.listitem = function (x) {
43+
// console.log(x.tokens)
44+
45+
// return "item"
46+
const content = this.parser.parse(x.tokens)
47+
return `<li class="text-body-1 text-accent">${content}</li>`
48+
}
49+
50+
renderer.list = function ({ ordered, items }) {
51+
const tag = ordered ? "ol" : "ul"
52+
const body = items.map(item => this.listitem(item)).join("")
53+
return `<${tag} class="mt-2 mb-4 pl-4" style="list-style-type: square">${body}</${tag}>`
54+
}
55+
56+
renderer.link = function ({ href, tokens }) {
57+
const content = this.parser.parseInline(tokens)
58+
59+
// if (href.startsWith("/")) {
60+
// const a = document.createElement("a")
61+
// a.href = href
62+
// a.textContent = content
63+
// a.addEventListener("click", (e) => {
64+
// e.preventDefault()
65+
// console.log(e)
66+
// })
67+
// return a.outerHTML
68+
// }
69+
70+
;(window as any).xonClick = function (e: Event, _: HTMLAnchorElement) {
71+
e.preventDefault()
72+
// console.log({ event, target })
73+
}
74+
75+
return `<a class="text-link" href="${href}" onclick="xonClick(event, this);">${content}</a>`
76+
}
77+
78+
renderer.codespan = function ({ text }) {
79+
return `<code
80+
class="text-primary text-body-1 border border-primary py-1 px-2 rounded"
81+
style="background-color: rgba(var(--v-theme-primary), var(--v-border-opacity))"
82+
>${text}</code>`
83+
}
84+
85+
/* Headings */
86+
// renderer.heading = ({ text, depth: level }) => {
87+
// return `<h${level} class="md-heading text-h${Math.min(level + 3, 6)}">${text}</h${level}>`
88+
// }
89+
90+
/* Paragraphs */
91+
// renderer.paragraph = (text) => {
92+
// return `<p class="md-paragraph">${text}</p>`
93+
// }
94+
95+
/* Links */
96+
// renderer.link = ({ href, title, text }) => {
97+
// const t = title ? ` title="${title}"` : ""
98+
// return `<a class="md-link" href="${href}"${t} target="_blank" rel="noopener noreferrer">${text}</a>`
99+
// }
100+
101+
/* Lists */
102+
// renderer.list = ({ ordered, items }) => {
103+
// const tag = ordered ? "ol" : "ul"
104+
// const body = items.map(item => `<li class="md-list-item">${item}</li>`).join("")
105+
// return `<${tag} class="md-list">${body}</${tag}>`
106+
// }
107+
108+
// renderer.listitem = (text) => {
109+
// return `<li class="md-list-item">${text}</li>`
110+
// }
111+
112+
/* Blockquotes */
113+
// renderer.blockquote = (quote) => {
114+
// return `<blockquote class="md-blockquote">${quote}</blockquote>`
115+
// }
116+
117+
/* Inline code */
118+
// renderer.codespan = (code) => {
119+
// return `<code class="md-inline-code">${code}</code>`
120+
// }
121+
122+
/* Code blocks */
123+
// renderer.code = ({ text, lang }) => {
124+
// const langClass = lang ? ` lang-${lang}` : ""
125+
// return `
126+
// <pre class="md-code-block${langClass}">
127+
// <code class="md-code">${text}</code>
128+
// </pre>
129+
// `
130+
// }
131+
132+
/* Tables */
133+
// renderer.table = ({ header, rows }) => {
134+
// const body = marked.parseInline(rows)
135+
// return `
136+
// <table class="md-table">
137+
// <thead class="md-table-head">${header}</thead>
138+
// <tbody class="md-table-body">${body}</tbody>
139+
// </table>
140+
// `
141+
// }
142+
143+
// renderer.tablerow = (content) => {
144+
// return `<tr class="md-table-row">${content}</tr>`
145+
// }
146+
147+
// renderer.tablecell = (content, flags) => {
148+
// const tag = flags.header ? "th" : "td"
149+
// return `<${tag} class="md-table-cell">${content}</${tag}>`
150+
// }
151+
152+
/* Images */
153+
// renderer.image = ({ href, title, text }) => {
154+
// const t = title ? ` title="${title}"` : ""
155+
// return `<img class="md-image" src="${href}" alt="${text}"${t} />`
156+
// }
157+
158+
/* Horizontal rule */
159+
// renderer.hr = () => {
160+
// return `<hr class="md-hr" />`
161+
// }
162+
163+
/* Strong / emphasis */
164+
// renderer.strong = (text) => {
165+
// return `<strong class="md-strong">${text}</strong>`
166+
// }
167+
168+
// renderer.em = (text) => {
169+
// return `<em class="md-em">${text}</em>`
170+
// }
171+
172+
// function e(name: string, attrs: Record<string, string>) {
173+
// const content = attrs.content ?? ""
174+
// delete attrs.content
175+
// return `<${name} ${Object.entries(attrs).map(([key, value]) => `${key}="${value}"`).join(" ")}>${content}</${name}>`
176+
// }
177+
178+
// marked.use({
179+
// renderer: {
180+
// blockquote({ tokens }) {
181+
// const text = this.parser.parse(tokens)
182+
// return `
183+
// <blockquote
184+
// class="pa-4 border-s-lg border-primary bg-surface"
185+
// style="--v-border-opacity: 1"
186+
// >
187+
// ${text}
188+
// </blockquote>
189+
// `
190+
// },
191+
// code(code) {
192+
// console.log(code)
193+
194+
// if (!code.type) {
195+
// console.log({ code })
196+
// }
197+
// return `
198+
// <pre class="bg-red overflow-y-auto"><code class="language-${code.lang}">${code.text}</code></pre>
199+
// `
200+
// },
201+
// },
202+
// })
35203
return docs.map((doc, index) => {
36204
const content = contents[index] ?? ""
37205
return {
38206
...doc,
39207
content,
40208
md: {
41-
html: marked.parse(content),
209+
html: marked.parse(content, { renderer }),
42210
tableOfContent: [],
43211
},
44212
}

frontend/kubecloud-v2/global.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,8 @@ declare global {
1414
DOTS?: (options: Record<string, any>) => void
1515
GLOBE?: (options: Record<string, any>) => void
1616
}
17+
MD?: {
18+
routeLink?: (event: Event, href: string) => void
19+
}
1720
}
1821
}

frontend/kubecloud-v2/pages/docs/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{{ page }}
44
</div> -->
55

6-
<div v-html="page?.md?.html" />
6+
<div class="markdown" v-html="page?.md?.html" />
77
</template>
88

99
<script setup lang="ts">

frontend/kubecloud-v2/public/docs/tutorial.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Tutorials
22

3-
This tutorial covers advanced deployment scenarios for Mycelium Cloud. For basic setup, see the [Getting Started Guide](#getting-started).
3+
This tutorial covers advanced deployment scenarios for Mycelium Cloud. For basic setup, see the [Getting Started Guide](/docs).
44

55
## Prerequisites
66

7-
- Completed [Getting Started Guide](#getting-started)
7+
- Completed [Getting Started Guide](/docs)
88
- Deployed cluster with kubectl access
99
- Mycelium binary installed
1010

0 commit comments

Comments
 (0)