Skip to content

Commit

Permalink
feat: complete
Browse files Browse the repository at this point in the history
  • Loading branch information
KazariEX committed Oct 10, 2024
1 parent 6c0da49 commit a577e80
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 50 deletions.
48 changes: 37 additions & 11 deletions playground/app/app.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,63 @@
<script lang="ts" setup>
import { repository, version } from "../../package.json";
import { type BundledLanguage, bundledLanguages, type BundledTheme, bundledThemes } from "shiki";
import pkg from "../../package.json";
const repoUrl = "https://github.com/" + repository;
const repository = new URL(pkg.repository, "https://github.com").href;
const version = "v" + pkg.version;
const langNames = Object.keys(bundledLanguages).sort((a, b) => a.localeCompare(b));
const themeNames = Object.keys(bundledThemes).sort((a, b) => a.localeCompare(b));
const lang = ref<BundledLanguage>("typescript");
const lightTheme = ref<BundledTheme>("catppuccin-latte");
const darkTheme = ref<BundledTheme>("one-dark-pro");
const themes = computed(() => ({
light: lightTheme.value,
dark: darkTheme.value
}));
</script>

<template>
<header flex="~ items-center justify-between" m="x-auto y-3" p="x-3" max-w="screen-lg">
<header
flex="~ items-center justify-between"
m="x-auto y-4"
p="x-4"
max-w="screen-lg"
>
<hgroup flex="~ gap-2 items-center">
<h1>Plain Shiki Playground</h1>
<h1 font="bold" text="5">Plain Shiki Playground</h1>
<span
p="x-1 y-.5"
b="rounded-1"
bg="primary op-20"
font="mono"
text="3 primary"
>v{{ version }}</span>
>{{ version }}</span>
</hgroup>
<nav flex="~ gap-2">
<nav-button icon="ph:github-logo" as="a" :href="repoUrl"/>
<plain-button as="a" icon="ph:github-logo" title="GitHub" :href="repository"/>
<theme-button mode="light" icon="solar:sun-2-outline"/>
<theme-button mode="system" icon="solar:monitor-outline"/>
<theme-button mode="dark" icon="solar:moon-outline"/>
</nav>
</header>
<main m="x-auto" max-w="screen-lg">
<div m="3" b="1 solid gray op-40 rounded-md">
<main
m="x-auto"
p="x-4"
max-w="screen-lg"
>
<div b="1 solid gray op-40 rounded-md">
<div
flex="~ gap-2 items-center"
p="x-3 y-2"
p="x-4 y-1"
b-b="~ solid gray op-40"
>
<plain-select :items="['javascript', 'typescript', 'html', 'css', 'json']"/>
<plain-select :items="langNames" v-model="lang"/>
<plain-select :items="themeNames" v-model="lightTheme"/>
<plain-select :items="themeNames" v-model="darkTheme"/>
</div>
<plain-shiki />
<plain-shiki :lang :themes/>
</div>
</main>
</template>
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script lang="ts" setup>
const {
as = "a"
} = defineProps<{
const { as = "a" } = defineProps<{
as?: string;
icon: string;
}>();
Expand All @@ -20,8 +18,8 @@
size="9"
b="1 solid gray op-40 rounded-md"
bg="transparent"
un-text="5"
transition="250"
hover:bg="gray op-20"
un-text="4.5"
cursor="pointer"
>
<iconify :name="icon"/>
Expand Down
54 changes: 44 additions & 10 deletions playground/app/components/plain-select.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
const props = defineProps<{
defineProps<{
items: string[];
}>();
const modelValue = defineModel<string>();
Expand All @@ -8,26 +8,60 @@
<template>
<select-root v-model="modelValue">
<select-trigger
flex="inline justify-between items-center gap-1"
flex="inline items-center gap-1.5"
h="8"
min-w="40"
w="45"
outline="none"
bg="inherit"
font="mono"
text="sm"
text="sm nowrap truncate"
cursor="pointer"
>
<select-icon flex="~" text="3 gray">
<iconify name="fa6-solid:chevron-down"/>
</select-icon>
<select-value />
<select-icon />
</select-trigger>
<select-portal>
<select-content font="mono" bg="inherit">
<select-scroll-up-button />
<select-content
class="select-content"
p="y-2"
b="~ solid gray op-40 rounded-md"
backdrop="blur-6"
font="mono"
position="popper"
>
<select-scroll-up-button flex="~ justify-center" text="3 gray">
<iconify name="fa6-solid:chevron-up"/>
</select-scroll-up-button>
<select-viewport>
<select-item v-for="item, i in items" :key="i" :value="item">
<select-item
v-for="item, i in items"
:key="i"
class="select-item"
p="x-3.5"
leading="6"
text="sm"
:value="item"
>
<select-item-text>{{ item }}</select-item-text>
</select-item>
</select-viewport>
<select-scroll-down-button />
<select-scroll-down-button flex="~ justify-center" text="3 gray">
<iconify name="fa6-solid:chevron-down"/>
</select-scroll-down-button>
</select-content>
</select-portal>
</select-root>
</template>
</template>

<style>
.select-content {
min-width: var(--radix-select-trigger-width);
max-height: var(--radix-select-content-available-height);
}
.select-item[data-highlighted] {
--uno: outline-none text-primary bg-gray bg-op-30;
}
</style>
28 changes: 14 additions & 14 deletions playground/app/components/plain-shiki.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
<script lang="ts" setup>
import type { BundledLanguage, BundledTheme } from "shiki";
import example from "~/assets/example.ts?raw";
const { lang, themes } = defineProps<{
lang: BundledLanguage;
themes: Record<string, BundledTheme>;
}>();
const editorEl = useTemplateRef("editor");
usePlainShiki(editorEl, {
lang: "ts",
themes: {
light: "catppuccin-latte",
dark: "one-dark-pro"
}
lang: () => lang,
themes: () => themes
});
</script>

<template>
<div
ref="editor"
class="plain-shiki"
p="x-3 y-2"
overflow="x-auto"
p="x-4 y-3"
outline="none"
font="mono"
whitespace="break-spaces"
lh="6"
leading="6"
text="nowrap"
contenteditable
v-html="example"
></div>
</template>

<style>
.plain-shiki {
font-family: consolas, var(--font);
}
</style>
</template>
6 changes: 3 additions & 3 deletions playground/app/components/theme-button.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
const props = defineProps<{
const { mode } = defineProps<{
mode: string;
icon: string;
}>();
Expand All @@ -8,13 +8,13 @@
function setColorMode() {
tryStartViewTransition(() => {
colorMode.preference = props.mode;
colorMode.preference = mode;
});
}
</script>

<template>
<nav-button
<plain-button
:icon
:class="{
[`is-checked`]: colorMode.preference === mode
Expand Down
31 changes: 24 additions & 7 deletions playground/app/composables/usePlainShiki.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
import { createPlainShiki, type CreatePlainShikiReturns, type MountPlainShikiOptions } from "plain-shiki";
import { type BundledLanguage, createHighlighter, createJavaScriptRegexEngine } from "shiki";
import {
type BundledLanguage,
bundledLanguages,
type BundledTheme,
bundledThemes,
createHighlighterCore,
createJavaScriptRegexEngine,
type HighlighterCore
} from "shiki";

export type UsePlainShikiOptions = Omit<MountPlainShikiOptions, "lang"> & {
export type UsePlainShikiOptions = Omit<MountPlainShikiOptions, "lang" | "themes"> & {
lang: MaybeRefOrGetter<BundledLanguage>;
themes: MaybeRefOrGetter<Record<string, BundledTheme>>;
};

let shiki: HighlighterCore;

export default function(el: MaybeRefOrGetter<HTMLElement | null>, options: UsePlainShikiOptions) {
const target = toRef(el);
const lang = toRef(options.lang);
const themes = toRef(options.themes);

let plain: CreatePlainShikiReturns;
let ctx: ReturnType<(typeof plain)["mount"]>;

const { trigger } = watchTriggerable([target, lang], () => {
const { trigger } = watchTriggerable([target, lang, themes], async () => {
ctx?.dispose();

if (target.value) {
await shiki?.loadLanguage(bundledLanguages[lang.value]);
for (const theme of Object.values(themes.value)) {
await shiki?.loadTheme(bundledThemes[theme]);
}

ctx = plain?.mount(target.value, {
...options,
lang: lang.value
lang: lang.value,
themes: themes.value
});
}
});

tryOnMounted(async () => {
const shiki = await createHighlighter({
langs: ["html", "css", "js", "ts"],
themes: Object.values(options.themes ?? {}).filter((theme) => theme !== void 0),
shiki ??= await createHighlighterCore({
engine: createJavaScriptRegexEngine()
});

Expand Down

0 comments on commit a577e80

Please sign in to comment.