1010 <div class =" code-window-dot bg-warning" ></div >
1111 <div class =" code-window-dot bg-success" ></div >
1212 </div >
13- <div class =" language-label text-gray-500 text-xs" >{{ language }}</div >
13+ <div class =" language-label text-gray-500 text-xs" >
14+ {{ language.toUpperCase() }}
15+ </div >
1416 <button
1517 v-if =" code"
1618 @click =" copyCode"
1921 {{ copied ? "Copied!" : "Copy" }}
2022 </button >
2123 </div >
22- <div
23- class =" code-window-content relative p-6 bg-[#272822] text-white overflow-auto"
24- >
25- <!-- Code content with Monokai-like background -->
26- <div class =" relative z-10" >
27- <slot ></slot >
28- </div >
24+ <div class =" code-window-content relative p-6 bg-[#272822] text-white" >
25+ <ClientOnly >
26+ <!-- Prism-highlighted code (client-side only) -->
27+ <div class =" flex" >
28+ <!-- Line numbers -->
29+ <div
30+ v-if =" showLineNumbers"
31+ class =" line-numbers select-none pr-4 opacity-50 text-right"
32+ >
33+ <div
34+ v-for =" n in lineCount"
35+ :key =" n"
36+ class =" text-gray-500 leading-relaxed"
37+ >
38+ {{ n }}
39+ </div >
40+ </div >
2941
30- <!-- Line numbers -->
31- <div
32- v-if =" showLineNumbers"
33- class =" absolute top-6 left-4 text-opacity-50 select-none"
34- >
35- <div
36- v-for =" n in lineCount"
37- :key =" n"
38- class =" text-gray-500 text-right pr-4"
39- >
40- {{ n }}
42+ <!-- Code content -->
43+ <pre
44+ class =" flex-1 relative z-10 m-0 p-0 bg-transparent overflow-x-auto whitespace-pre"
45+ ><code :class =" `language-${prismLanguage}`" v-html =" highlightedCode" ></code ></pre >
4146 </div >
42- </div >
47+ <template #fallback >
48+ <!-- Non-highlighted fallback for SSR -->
49+ <div class =" flex" >
50+ <!-- Line numbers -->
51+ <div
52+ v-if =" showLineNumbers"
53+ class =" line-numbers select-none pr-4 opacity-50 text-right"
54+ >
55+ <div
56+ v-for =" n in lineCount"
57+ :key =" n"
58+ class =" text-gray-500 leading-relaxed"
59+ >
60+ {{ n }}
61+ </div >
62+ </div >
63+
64+ <!-- Code content -->
65+ <pre
66+ class =" flex-1 relative z-10 m-0 p-0 bg-transparent overflow-x-auto whitespace-pre"
67+ ><code >{{ code }}</code ></pre >
68+ </div >
69+ </template >
70+ </ClientOnly >
4371 </div >
4472 </div >
4573</template >
4674
4775<script setup>
48- import { ref , computed , onMounted } from " vue"
76+ import { ref , computed , onMounted , watch } from " vue"
4977
5078const props = defineProps ({
5179 language: {
@@ -62,12 +90,77 @@ const props = defineProps({
6290 },
6391})
6492
93+ // Map language aliases to Prism language names
94+ const languageMap = {
95+ js: " javascript" ,
96+ ts: " typescript" ,
97+ bash: " bash" ,
98+ shell: " bash" ,
99+ sh: " bash" ,
100+ html: " markup" ,
101+ xml: " markup" ,
102+ yml: " yaml" ,
103+ py: " python" ,
104+ }
105+
106+ const prismLanguage = computed (() => {
107+ return (
108+ languageMap[props .language .toLowerCase ()] || props .language .toLowerCase ()
109+ )
110+ })
111+
112+ const nuxtApp = useNuxtApp ()
65113const copied = ref (false )
114+ const highlightedCode = ref (" " )
115+
66116const lineCount = computed (() => {
67117 if (! props .code ) return 0
68118 return props .code .split (" \n " ).length
69119})
70120
121+ const highlightCode = () => {
122+ if (! process .client || ! props .code ) {
123+ highlightedCode .value = props .code
124+ return
125+ }
126+
127+ try {
128+ const Prism = nuxtApp .$prism
129+ if (! Prism) {
130+ console .warn (" Prism.js not available" )
131+ highlightedCode .value = props .code
132+ return
133+ }
134+
135+ // Use the mapped language
136+ const lang = prismLanguage .value
137+
138+ // Check if language is loaded
139+ if (Prism .languages [lang]) {
140+ highlightedCode .value = Prism .highlight (
141+ props .code ,
142+ Prism .languages [lang],
143+ lang
144+ )
145+ } else {
146+ console .warn (` Language '${ lang} ' not loaded in Prism` )
147+ highlightedCode .value = props .code
148+ }
149+ } catch (error) {
150+ console .error (" Error highlighting code:" , error)
151+ highlightedCode .value = props .code
152+ }
153+ }
154+
155+ onMounted (() => {
156+ if (process .client ) {
157+ highlightCode ()
158+ }
159+ })
160+
161+ watch (() => props .code , highlightCode)
162+ watch (() => props .language , highlightCode)
163+
71164const copyCode = () => {
72165 navigator .clipboard .writeText (props .code )
73166 copied .value = true
@@ -87,6 +180,88 @@ const copyCode = () => {
87180
88181.code-window-dot {
89182 @apply w- 2.5 h- 2.5 rounded-full mr- 1;
90- /* No box-shadow */
183+ }
184+
185+ :deep(pre ) {
186+ margin : 0 ;
187+ padding : 0 ;
188+ background : transparent !important ;
189+ text-shadow : none !important ;
190+ tab-size : 2 ;
191+ }
192+
193+ :deep(code ) {
194+ font-family : " JetBrains Mono" , monospace !important ;
195+ font-size : 0.9rem !important ;
196+ line-height : 1.5 !important ;
197+ background : transparent !important ;
198+ text-shadow : none !important ;
199+ color : #f8f8f2 !important ;
200+ white-space : pre !important ;
201+ }
202+
203+ .line-numbers {
204+ min-width : 2rem ;
205+ font-size : 0.9rem ;
206+ line-height : 1.5 ;
207+ font-family : " JetBrains Mono" , monospace ;
208+ }
209+
210+ /* Override Prism.js token colors to match Monokai theme */
211+ :deep(.token.comment ),
212+ :deep(.token.prolog ),
213+ :deep(.token.doctype ),
214+ :deep(.token.cdata ) {
215+ color : #8292a2 !important ;
216+ }
217+
218+ :deep(.token.punctuation ) {
219+ color : #f8f8f2 !important ;
220+ }
221+
222+ :deep(.token.property ),
223+ :deep(.token.tag ),
224+ :deep(.token.constant ),
225+ :deep(.token.symbol ),
226+ :deep(.token.deleted ) {
227+ color : #f92672 !important ;
228+ }
229+
230+ :deep(.token.boolean ),
231+ :deep(.token.number ) {
232+ color : #ae81ff !important ;
233+ }
234+
235+ :deep(.token.selector ),
236+ :deep(.token.attr-name ),
237+ :deep(.token.string ),
238+ :deep(.token.char ),
239+ :deep(.token.builtin ),
240+ :deep(.token.inserted ) {
241+ color : #a6e22e !important ;
242+ }
243+
244+ :deep(.token.operator ),
245+ :deep(.token.entity ),
246+ :deep(.token.url ),
247+ :deep(.language-css .token.string ),
248+ :deep(.style .token.string ),
249+ :deep(.token.variable ) {
250+ color : #f8f8f2 !important ;
251+ }
252+
253+ :deep(.token.atrule ),
254+ :deep(.token.attr-value ),
255+ :deep(.token.function ) {
256+ color : #e6db74 !important ;
257+ }
258+
259+ :deep(.token.keyword ) {
260+ color : #66d9ef !important ;
261+ }
262+
263+ :deep(.token.regex ),
264+ :deep(.token.important ) {
265+ color : #fd971f !important ;
91266}
92267 </style >
0 commit comments