diff --git a/web/package.json b/web/package.json index f15484b9e..6157c2cb3 100644 --- a/web/package.json +++ b/web/package.json @@ -29,6 +29,7 @@ "lodash": "^4.17.21", "node-emoji": "^1.11.0", "pinia": "^2.0.17", + "prismjs": "^1.28.0", "vue": "^3.2.37", "vue-i18n": "^9.2.2", "vue-router": "^4.1.3" @@ -40,6 +41,7 @@ "@types/lodash": "^4.14.182", "@types/node": "^16.11.6", "@types/node-emoji": "^1.8.1", + "@types/prismjs": "^1.26.0", "@typescript-eslint/eslint-plugin": "^5.33.0", "@typescript-eslint/parser": "^5.33.0", "@vitejs/plugin-vue": "^3.0.1", @@ -59,6 +61,7 @@ "unplugin-icons": "^0.14.8", "unplugin-vue-components": "^0.22.3", "vite": "^3.0.4", + "vite-plugin-prismjs": "^0.0.8", "vite-plugin-windicss": "^1.8.7", "vite-svg-loader": "^3.4.0", "vue-tsc": "^0.39.5", diff --git a/web/src/components/atomic/SyntaxHighlight.ts b/web/src/components/atomic/SyntaxHighlight.ts new file mode 100644 index 000000000..79f56f026 --- /dev/null +++ b/web/src/components/atomic/SyntaxHighlight.ts @@ -0,0 +1,37 @@ +import '~/style/prism.css'; + +import Prism from 'prismjs'; +import { computed, defineComponent, h, toRef, VNode } from 'vue'; + +declare type Data = Record; + +export default defineComponent({ + name: 'SyntaxHighlight', + + props: { + code: { + type: String, + default: '', + }, + + language: { + type: String, + default: 'yaml', + }, + }, + + setup(props, { attrs }: { attrs: Data }) { + const code = toRef(props, 'code'); + const language = toRef(props, 'language'); + const prismLanguage = computed(() => Prism.languages[language.value]); + const className = computed(() => `language-${language.value}`); + + return (): VNode => + h('pre', { ...attrs, class: [attrs.class, className] }, [ + h('code', { + class: className, + innerHTML: Prism.highlight(code.value, prismLanguage.value, language.value), + }), + ]); + }, +}); diff --git a/web/src/style/prism.css b/web/src/style/prism.css new file mode 100644 index 000000000..86525d271 --- /dev/null +++ b/web/src/style/prism.css @@ -0,0 +1,291 @@ +.token.atrule { + color: #7c4dff; +} + +.token.attr-name { + color: #39adb5; +} + +.token.attr-value { + color: #f6a434; +} + +.token.attribute { + color: #f6a434; +} + +.token.boolean { + color: #7c4dff; +} + +.token.builtin { + color: #39adb5; +} + +.token.cdata { + color: #39adb5; +} + +.token.char { + color: #39adb5; +} + +.token.class { + color: #39adb5; +} + +.token.class-name { + color: #6182b8; +} + +.token.comment { + color: #aabfc9; +} + +.token.constant { + color: #7c4dff; +} + +.token.deleted { + color: #e53935; +} + +.token.doctype { + color: #aabfc9; +} + +.token.entity { + color: #e53935; +} + +.token.function { + color: #7c4dff; +} + +.token.hexcode { + color: #f76d47; +} + +.token.id { + color: #7c4dff; + font-weight: bold; +} + +.token.important { + color: #7c4dff; + font-weight: bold; +} + +.token.inserted { + color: #39adb5; +} + +.token.keyword { + color: #7c4dff; +} + +.token.number { + color: #f76d47; +} + +.token.operator { + color: #39adb5; +} + +.token.prolog { + color: #aabfc9; +} + +.token.property { + color: #39adb5; +} + +.token.pseudo-class { + color: #f6a434; +} + +.token.pseudo-element { + color: #f6a434; +} + +.token.punctuation { + color: #39adb5; +} + +.token.regex { + color: #6182b8; +} + +.token.selector { + color: #e53935; +} + +.token.string { + color: #f6a434; +} + +.token.symbol { + color: #7c4dff; +} + +.token.tag { + color: #e53935; +} + +.token.unit { + color: #f76d47; +} + +.token.url { + color: #e53935; +} + +.token.variable { + color: #e53935; +} + +.dark .token.atrule { + color: #c792ea; +} + +.dark .token.attr-name { + color: #ffcb6b; +} + +.dark .token.attr-value { + color: #a5e844; +} + +.dark .token.attribute { + color: #a5e844; +} + +.dark .token.boolean { + color: #c792ea; +} + +.dark .token.builtin { + color: #ffcb6b; +} + +.dark .token.cdata { + color: #80cbc4; +} + +.dark .token.char { + color: #80cbc4; +} + +.dark .token.class { + color: #ffcb6b; +} + +.dark .token.class-name { + color: #f2ff00; +} + +.dark .token.comment { + color: #616161; +} + +.dark .token.constant { + color: #c792ea; +} + +.dark .token.deleted { + color: #ff6666; +} + +.dark .token.doctype { + color: #616161; +} + +.dark .token.entity { + color: #ff6666; +} + +.dark .token.function { + color: #c792ea; +} + +.dark .token.hexcode { + color: #f2ff00; +} + +.dark .token.id { + color: #c792ea; + font-weight: bold; +} + +.dark .token.important { + color: #c792ea; + font-weight: bold; +} + +.dark .token.inserted { + color: #80cbc4; +} + +.dark .token.keyword { + color: #c792ea; +} + +.dark .token.number { + color: #fd9170; +} + +.dark .token.operator { + color: #89ddff; +} + +.dark .token.prolog { + color: #616161; +} + +.dark .token.property { + color: #80cbc4; +} + +.dark .token.pseudo-class { + color: #a5e844; +} + +.dark .token.pseudo-element { + color: #a5e844; +} + +.dark .token.punctuation { + color: #89ddff; +} + +.dark .token.regex { + color: #f2ff00; +} + +.dark .token.selector { + color: #ff6666; +} + +.dark .token.string { + color: #a5e844; +} + +.dark .token.symbol { + color: #c792ea; +} + +.dark .token.tag { + color: #ff6666; +} + +.dark .token.unit { + color: #fd9170; +} + +.dark .token.url { + color: #ff6666; +} + +.dark .token.variable { + color: #ff6666; +} diff --git a/web/src/views/repo/build/BuildConfig.vue b/web/src/views/repo/build/BuildConfig.vue index 6dd83b8b7..7a1fc1207 100644 --- a/web/src/views/repo/build/BuildConfig.vue +++ b/web/src/views/repo/build/BuildConfig.vue @@ -1,7 +1,7 @@ @@ -9,6 +9,7 @@