@@ -92,34 +92,18 @@ import Prism from 'prismjs';
9292import UAParser from ' ua-parser-js' ;
9393import { Props } from ' @/types' ;
9494
95+ import { version } from ' prismjs/package.json' ;
96+
9597import StatusIcons from ' @/plugin/StatusIcons.vue' ;
96- const neonBunnyCarrotTheme = import .meta .glob (' ./themes/neon-bunny-carrot.css' , { eager: true , as: ' raw' });
97- const neonBunnyTheme = import .meta .glob (' ./themes/neon-bunny.css' , { eager: true , as: ' raw' });
98- const prismTheme = import .meta .glob (' prismjs/themes/prism.css' , { eager: true , as: ' raw' });
99- const prismThemeCoy = import .meta .glob (' prismjs/themes/prism-coy.css' , { eager: true , as: ' raw' });
100- const prismThemeDark = import .meta .glob (' prismjs/themes/prism-dark.css' , { eager: true , as: ' raw' });
101- const prismThemeFunky = import .meta .glob (' prismjs/themes/prism-funky.css' , { eager: true , as: ' raw' });
102- const prismThemeOkaidia = import .meta .glob (' prismjs/themes/prism-okaidia.css' , { eager: true , as: ' raw' });
103- const prismThemeSolarizedlight = import .meta .glob (' prismjs/themes/prism-solarizedlight.css' , { eager: true , as: ' raw' });
104- const prismThemeTomorrow = import .meta .glob (' prismjs/themes/prism-tomorrow.css' , { eager: true , as: ' raw' });
105- const prismThemeTwilight = import .meta .glob (' prismjs/themes/prism-twilight.css' , { eager: true , as: ' raw' });
106-
107- // import neonBunnyCarrotTheme from '@/plugin/themes/neon-bunny-carrot.css?inline';
108- // import neonBunnyTheme from '@/plugin/themes/neon-bunny.css?inline';
109- // import prismTheme from 'prismjs/themes/prism.css?inline';
110- // import prismThemeCoy from 'prismjs/themes/prism-coy.css?inline';
111- // import prismThemeDark from 'prismjs/themes/prism-dark.css?inline';
112- // import prismThemeFunky from 'prismjs/themes/prism-funky.css?inline';
113- // import prismThemeOkaidia from 'prismjs/themes/prism-okaidia.css?inline';
114- // import prismThemeSolarizedlight from 'prismjs/themes/prism-solarizedlight.css?inline';
115- // import prismThemeTomorrow from 'prismjs/themes/prism-tomorrow.css?inline';
116- // import prismThemeTwilight from 'prismjs/themes/prism-twilight.css?inline';
98+ import { neonBunnyCarrotTheme , neonBunnyTheme } from ' @/plugin/themes' ;
99+
117100
118101// -------------------------------------------------- Emits & Slots & Injects //
119102const emit = defineEmits ([' run' , ' update:copy-status' ]);
120103const slots = useSlots ();
121104const codeBlockGlobalOptions = inject <Props >(' codeBlockGlobalOptions' );
122105
106+
123107// -------------------------------------------------- Props //
124108const props = defineProps ({
125109 browserWindow: {
@@ -228,23 +212,26 @@ const props = defineProps({
228212 },
229213});
230214
215+
231216// -------------------------------------------------- Data //
232- const copyTextValue = ref <string >(' ' );
233217const convertedCode = ref (null );
234- const copying = ref <boolean >(false );
235218const copyStatus = ref <string >(' copy' );
219+ const copyTextValue = ref <string >(' ' );
220+ const copying = ref <boolean >(false );
221+ const isLoading = ref <boolean >(false );
236222const isMobile = ref <boolean >(false );
223+ const prismCdn = ref (` https://cdn.jsdelivr.net/gh/PrismJS/prism@${version }/themes ` );
237224const runTextValue = ref <string >(' ' );
238- const stylesheetId = ' v-code-block--theme' ;
239225const useTheme = ref <boolean | string >(' ' );
240226
227+
241228// -------------------------------------------------- Computed //
242229const codeBlockClasses = computed <string >(() => {
243230 return isMobile .value ? ' v-code-block--mobile' : ' ' ;
244231});
245232
246233const codeTagStyles = computed <StyleValue >(() => {
247- const width = useTheme .value === ' coy' ? ' 100%' : ' ' ;
234+ const width = useTheme .value === ' coy' && isLoading . value === false ? ' 100%' : ' ' ;
248235 return { width };
249236});
250237
@@ -324,6 +311,7 @@ const tabGroupStyle = computed<StyleValue>(() => {
324311 };
325312});
326313
314+
327315// -------------------------------------------------- Watch //
328316watch (props , () => {
329317 if (props .theme ) {
@@ -340,6 +328,7 @@ watch(props, () => {
340328 }
341329});
342330
331+
343332// -------------------------------------------------- Mounts //
344333onBeforeMount (() => {
345334 copyTextValue .value = props .copyText ;
@@ -352,6 +341,7 @@ onMounted(() => {
352341 mobileCheck ();
353342});
354343
344+
355345// -------------------------------------------------- Methods //
356346function convertCode(): void {
357347 if (props .lang === ' json' ) {
@@ -404,56 +394,65 @@ function copyCode(): void {
404394
405395function loadTheme(): void {
406396 let selectedTheme = null ;
407- const loadedThemeStyles = document .getElementById (stylesheetId );
408397 const head = document .getElementsByTagName (' head' )[0 ];
409398 const themeStyles = document .createElement (' style' );
399+ const themeId = ` v-code-block--theme-${useTheme .value } ` ;
400+ const loadedTheme = document .body .getAttribute (' data-v-code-block-theme' );
410401
411- if (loadedThemeStyles ) {
412- loadedThemeStyles .remove ();
402+ let isPrismTheme = true ;
403+ let cssFilename = ' ' ;
404+
405+ // If theme is loaded, do not keep trying to add it again //
406+ if (loadedTheme === useTheme .value ) {
407+ return ;
413408 }
414409
410+ document .body .setAttribute (' data-v-code-block-theme' , useTheme .value );
411+
412+ themeStyles .setAttribute (' type' , ' text/css' );
413+ themeStyles .setAttribute (' data-theme-id' , themeId );
414+ themeStyles .setAttribute (' data-theme' , ' v-code-block--theme-sheet' );
415+
415416 switch (useTheme .value ) {
416417 case ' neon-bunny' :
417418 selectedTheme = neonBunnyTheme ;
419+ isPrismTheme = false ;
418420 break ;
419421 case ' neon-bunny-carrot' :
420422 selectedTheme = neonBunnyCarrotTheme ;
421- break ;
422- case ' coy' :
423- selectedTheme = prismThemeCoy ;
424- break ;
425- case ' dark' :
426- selectedTheme = prismThemeDark ;
427- break ;
428- case ' funky' :
429- selectedTheme = prismThemeFunky ;
430- break ;
431- case ' okaidia' :
432- selectedTheme = prismThemeOkaidia ;
433- break ;
434- case ' solarizedlight' :
435- selectedTheme = prismThemeSolarizedlight ;
436- break ;
437- case ' tomorrow' :
438- selectedTheme = prismThemeTomorrow ;
439- break ;
440- case ' twilight' :
441- selectedTheme = prismThemeTwilight ;
423+ isPrismTheme = false ;
442424 break ;
443425 case ' default' :
444426 case ' prism' :
445- selectedTheme = prismTheme ;
427+ isPrismTheme = true ;
428+ cssFilename = ' prism.css' ;
446429 break ;
447430 default :
448- selectedTheme = prismTheme ;
431+ isPrismTheme = true ;
432+ cssFilename = ` prism-${useTheme .value }.css ` ;
449433 break ;
450434 }
451435
452- themeStyles .setAttribute (' type' , ' text/css' );
453- themeStyles .id = stylesheetId ;
454- themeStyles .appendChild (document .createTextNode (selectedTheme ));
436+ if (! isPrismTheme ) {
437+ removeStylesheets ();
455438
456- head .appendChild (themeStyles );
439+ themeStyles .appendChild (document .createTextNode (selectedTheme ));
440+ head .appendChild (themeStyles );
441+
442+ return ;
443+ }
444+
445+ isLoading .value = true ;
446+
447+ fetch (` ${prismCdn .value }/${cssFilename } ` ).then ((response ) => {
448+ return response .text ();
449+ }).then ((data ) => {
450+ removeStylesheets ();
451+
452+ themeStyles .appendChild (document .createTextNode (data ));
453+ head .appendChild (themeStyles );
454+ isLoading .value = false ;
455+ });
457456}
458457
459458function mobileCheck(): void {
@@ -466,6 +465,16 @@ window.addEventListener('orientationchange', () => {
466465 mobileCheck ();
467466});
468467
468+ function removeStylesheets() {
469+ const themeSheets = document .querySelectorAll (' [data-theme="v-code-block--theme-sheet"]' );
470+
471+ if (themeSheets .length > 0 ) {
472+ themeSheets .forEach ((themeSheet ) => {
473+ themeSheet .remove ();
474+ });
475+ }
476+ }
477+
469478function runCode(): void {
470479 emit (' run' );
471480}
0 commit comments