mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-14 13:58:21 +00:00
Add code groups with syntax highlighting
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, defineProps, onMounted } from 'vue'
|
||||
const props = defineProps<{
|
||||
groups: string[] | undefined,
|
||||
groupName: string,
|
||||
}>()
|
||||
|
||||
console.log(props.groups);
|
||||
|
||||
|
||||
const getSaveIdname = (name: string) => {
|
||||
return name.toLowerCase().replace(/\s/g, '-')
|
||||
}
|
||||
|
||||
const tabs = computed(() => props.groups?.map((group) => {
|
||||
return {
|
||||
id: getSaveIdname(group),
|
||||
name: group,
|
||||
}
|
||||
}))
|
||||
|
||||
const saveTabId = (id: string) => {
|
||||
console.log(id);
|
||||
|
||||
localStorage.setItem(props.groupName, id)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const id = localStorage.getItem(props.groupName)
|
||||
if (id) {
|
||||
const tab = document.getElementById(`label-tab-${id}`)
|
||||
|
||||
if (tab) {
|
||||
tab.click()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="vp-code-group">
|
||||
<div class="tabs">
|
||||
<template v-for="(tab, index) in tabs">
|
||||
<input
|
||||
type="radio"
|
||||
:id="`tab-${tab.id}`"
|
||||
:name="`group-${groupName}`"
|
||||
:checked="index === 0"
|
||||
@change="saveTabId(tab.id)"
|
||||
>
|
||||
<label :for="`tab-${tab.id}`" :id="`label-tab-${tab.id}`">{{ tab.name }}</label>
|
||||
</template>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
@@ -8,7 +8,6 @@ type CodeExampleType = Record<string, {
|
||||
code: string,
|
||||
metastring?: string,
|
||||
}[],
|
||||
breakpoint: 'base'|'sm'|'md',
|
||||
}>
|
||||
|
||||
const getIconCodes = (name: string): CodeExampleType => {
|
||||
@@ -24,7 +23,6 @@ const getIconCodes = (name: string): CodeExampleType => {
|
||||
`,
|
||||
},
|
||||
],
|
||||
breakpoint: 'base',
|
||||
},
|
||||
react: {
|
||||
title: 'React',
|
||||
@@ -48,7 +46,6 @@ export default App;
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'base',
|
||||
},
|
||||
vue: {
|
||||
title: 'Vue 3',
|
||||
@@ -66,7 +63,6 @@ import { ${pascalCase} } from 'lucide-vue-next';
|
||||
metastring: '{2,6}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'base',
|
||||
},
|
||||
svelte: {
|
||||
title: 'Svelte',
|
||||
@@ -86,7 +82,6 @@ import { ${pascalCase} } from 'lucide-svelte';
|
||||
metastring: '{2,5}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'sm',
|
||||
},
|
||||
preact:{
|
||||
title: 'Preact',
|
||||
@@ -110,7 +105,6 @@ export default App;
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'md',
|
||||
},
|
||||
solid:{
|
||||
title: 'Solid',
|
||||
@@ -134,7 +128,6 @@ export default App;
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'md',
|
||||
},
|
||||
angular: {
|
||||
title: 'Angular',
|
||||
@@ -152,10 +145,8 @@ import { LucideAngularModule, ${pascalCase} } from 'lucide-angular';\r
|
||||
// app.component.html
|
||||
<lucide-icon name="${name}"></lucide-icon>
|
||||
`,
|
||||
metastring: '{2,6}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'base',
|
||||
},
|
||||
font: {
|
||||
title: 'Icon Font',
|
||||
@@ -170,7 +161,6 @@ import { LucideAngularModule, ${pascalCase} } from 'lucide-angular';\r
|
||||
`,
|
||||
},
|
||||
],
|
||||
breakpoint: 'md',
|
||||
},
|
||||
flutter: {
|
||||
title: 'Flutter',
|
||||
@@ -179,10 +169,8 @@ import { LucideAngularModule, ${pascalCase} } from 'lucide-angular';\r
|
||||
language: 'javascript',
|
||||
code: `Icon(LucideIcons.${name});
|
||||
`,
|
||||
metastring: '{1}',
|
||||
},
|
||||
],
|
||||
breakpoint: 'sm',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
import { startCase, camelCase } from "lodash";
|
||||
import {
|
||||
BUNDLED_LANGUAGES,
|
||||
type IThemeRegistration
|
||||
} from 'shiki'
|
||||
import {
|
||||
getHighlighter,
|
||||
} from 'shiki-processor'
|
||||
|
||||
type CodeExampleType = {
|
||||
title: string,
|
||||
lang: string,
|
||||
codes: {
|
||||
language?: string,
|
||||
code: string,
|
||||
metastring?: string,
|
||||
}[],
|
||||
}[]
|
||||
|
||||
const getIconCodes = (name: string): CodeExampleType => {
|
||||
const pascalCase = startCase(camelCase(name)).replace(/\s/g, '')
|
||||
|
||||
return [
|
||||
{
|
||||
lang: 'html',
|
||||
title: 'HTML',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<i icon-name="${name}"></i>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'tsx',
|
||||
title: 'React',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { ${pascalCase} } from 'lucide-react';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<${pascalCase}
|
||||
color="red"
|
||||
size={48}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'vue',
|
||||
title: 'Vue 3',
|
||||
codes: [
|
||||
{
|
||||
language: 'vue',
|
||||
code: `<template>
|
||||
<${pascalCase} color="red" :size="32" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ${pascalCase} } from 'lucide-vue-next';
|
||||
</script>
|
||||
`,
|
||||
metastring: '{2,6}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'svelte',
|
||||
title: 'Svelte',
|
||||
codes: [
|
||||
{
|
||||
language: 'vue',
|
||||
code: `<script>
|
||||
import { ${pascalCase} } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<${pascalCase}
|
||||
color={red}
|
||||
size={48}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
`,
|
||||
metastring: '{2,5}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'preact',
|
||||
title: 'Preact',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { ${pascalCase} } from 'lucide-preact';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<${pascalCase}
|
||||
color="red"
|
||||
size={48}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'solid',
|
||||
title: 'Solid',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `import { ${pascalCase} } from 'lucide-solid';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<${pascalCase}
|
||||
color="red"
|
||||
size={48}
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
`,
|
||||
metastring: '{1,4}',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'angular',
|
||||
title: 'Angular',
|
||||
codes: [
|
||||
{
|
||||
language: 'tsx',
|
||||
code: `// app.module.ts
|
||||
import { LucideAngularModule, ${pascalCase} } from 'lucide-angular';\r
|
||||
@NgModule({
|
||||
imports: [
|
||||
LucideAngularModule.pick({ ${pascalCase} })
|
||||
],
|
||||
})
|
||||
|
||||
// app.component.html
|
||||
<lucide-icon name="${name}"></lucide-icon>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'html',
|
||||
title: 'Icon Font',
|
||||
codes: [
|
||||
{
|
||||
language: 'html',
|
||||
code: `<style>
|
||||
@import ('~lucide-static/font/Lucide.css')
|
||||
</style>
|
||||
|
||||
<div class="icon-${name}"></div>
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
lang: 'dart',
|
||||
title: 'Flutter',
|
||||
codes: [
|
||||
{
|
||||
language: 'dart',
|
||||
code: `Icon(LucideIcons.${name});
|
||||
`,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
export type ThemeOptions =
|
||||
| IThemeRegistration
|
||||
| { light: IThemeRegistration; dark: IThemeRegistration }
|
||||
|
||||
const highLightCode = async (code: string, lang: string, active?: boolean) => {
|
||||
const highlighter = await getHighlighter({
|
||||
themes: ['material-theme-palenight'],
|
||||
langs: [...BUNDLED_LANGUAGES],
|
||||
processors: []
|
||||
})
|
||||
|
||||
const highlightedCode = highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
// lineOptions,
|
||||
theme: 'material-theme-palenight'
|
||||
}).replace('background-color: #292D3E', '')
|
||||
|
||||
return `<div class="language-${lang} ${active ? 'active' : ''}">
|
||||
<button title="Copy Code" class="copy"></button>
|
||||
<span class="lang">${lang}</span>
|
||||
${highlightedCode}
|
||||
</div>`
|
||||
}
|
||||
|
||||
|
||||
export default async function createCodeExamples(name: string) {
|
||||
const codes = getIconCodes(name);
|
||||
|
||||
const codeExamplePromises = codes.map(async (codeTemplate, index) => {
|
||||
const { title, lang, codes } = codeTemplate;
|
||||
const isFirst = index === 0;
|
||||
|
||||
const code = await highLightCode(codes[0].code, codes[0].language || lang, isFirst);
|
||||
|
||||
return {
|
||||
title,
|
||||
language: codes[0].language || lang,
|
||||
code,
|
||||
};
|
||||
})
|
||||
|
||||
return Promise.all(codeExamplePromises);
|
||||
}
|
||||
+18
-41
@@ -8,13 +8,22 @@ prev: false
|
||||
sidebar: true
|
||||
---
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import IconPreview from '../.vitepress/components/IconPreview.vue'
|
||||
import IconDetailName from '../.vitepress/components/IconDetailName.vue'
|
||||
import useIconCodeExamples from '../.vitepress/composables/useIconCodeExample.ts'
|
||||
import { useData } from 'vitepress'
|
||||
import CodeGroup from '../.vitepress/components/CodeGroup.vue'
|
||||
|
||||
const { params } = useData()
|
||||
const codeExample = useIconCodeExamples(params.value.name)
|
||||
const { params } = useData()
|
||||
|
||||
const tabs = computed(() => params.value.codeExamples?.map(
|
||||
(codeExample) => codeExample.title) ?? []
|
||||
)
|
||||
|
||||
const codeExample = computed(() => params.value.codeExamples?.map(
|
||||
(codeExample) => codeExample.code
|
||||
).join('') ?? []
|
||||
)
|
||||
</script>
|
||||
|
||||
<IconPreview
|
||||
@@ -27,44 +36,12 @@ import { useData } from 'vitepress'
|
||||
{{$params.name}}
|
||||
</IconDetailName>
|
||||
|
||||
::: code-group
|
||||
|
||||
```html-vue [HTML]
|
||||
{{codeExample.html.codes[0].code}}
|
||||
```
|
||||
|
||||
```jsx-vue [React]
|
||||
{{codeExample.react.codes[0].code}}
|
||||
```
|
||||
|
||||
```vue-vue [Vue]
|
||||
{{codeExample.vue.codes[0].code}}
|
||||
```
|
||||
|
||||
```svelte-vue [Svelte]
|
||||
{{codeExample.svelte.codes[0].code}}
|
||||
```
|
||||
|
||||
```jsx-vue [Preact]
|
||||
{{codeExample.preact.codes[0].code}}
|
||||
```
|
||||
|
||||
```jsx-vue [Solid]
|
||||
{{codeExample.solid.codes[0].code}}
|
||||
```
|
||||
|
||||
```tsx-vue [Angular]
|
||||
{{codeExample.angular.codes[0].code}}
|
||||
```
|
||||
|
||||
```html-vue [Font]
|
||||
{{codeExample.font.codes[0].code}}
|
||||
```
|
||||
|
||||
```html-vue [Flutter]
|
||||
{{codeExample.flutter.codes[0].code}}
|
||||
```
|
||||
:::
|
||||
<CodeGroup :groups="tabs" groupName="icon-code-example">
|
||||
<div
|
||||
class="blocks"
|
||||
v-html="codeExample"
|
||||
/>
|
||||
</CodeGroup>
|
||||
|
||||
<style module>
|
||||
.preview {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { getAllData } from "../.vitepress/lib/icons";
|
||||
import createCodeExamples from "../.vitepress/lib/createCodeExamples";
|
||||
|
||||
|
||||
|
||||
const directory = path.join(process.cwd(), 'icons');
|
||||
|
||||
@@ -15,10 +18,23 @@ export function getAllNames() {
|
||||
export default {
|
||||
paths: async () => {
|
||||
const icons = await getAllData()
|
||||
return icons.map((iconData) => {
|
||||
|
||||
const result = await createCodeExamples('activity')
|
||||
// const codeExamplesPromises = icons.map(async (icon) => {
|
||||
// return createCodeExamples(icon.name);
|
||||
// })
|
||||
|
||||
// const codeExamples = await Promise.all(codeExamplesPromises);
|
||||
|
||||
|
||||
return icons.map((iconData, index) => {
|
||||
const params = {
|
||||
...iconData,
|
||||
codeExamples: result
|
||||
};
|
||||
|
||||
return {
|
||||
params: iconData,
|
||||
params,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { getAllData } from '../.vitepress/lib/icons'
|
||||
|
||||
import createCodeExamples from "../.vitepress/lib/createCodeExamples";
|
||||
|
||||
export default {
|
||||
async load() {
|
||||
const result = await createCodeExamples('activity')
|
||||
|
||||
console.log(result);
|
||||
|
||||
return {
|
||||
test: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,14 @@
|
||||
"fuse.js": "^6.5.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jszip": "^3.7.0",
|
||||
"lodash": "^4.17.20",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucide-react": "workspace:*",
|
||||
"lucide-vue-next": "workspace:*",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"shiki": "^0.14.2",
|
||||
"shiki-processor": "^0.1.3",
|
||||
"svg-pathdata": "^6.0.3",
|
||||
"vue": "^3.2.47"
|
||||
}
|
||||
|
||||
Generated
+20
-7
@@ -64,6 +64,9 @@ importers:
|
||||
jszip:
|
||||
specifier: ^3.7.0
|
||||
version: 3.10.1
|
||||
lodash:
|
||||
specifier: ^4.17.20
|
||||
version: 4.17.21
|
||||
lodash-es:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@@ -79,6 +82,12 @@ importers:
|
||||
react-dom:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
shiki:
|
||||
specifier: ^0.14.2
|
||||
version: 0.14.2
|
||||
shiki-processor:
|
||||
specifier: ^0.1.3
|
||||
version: 0.1.3(shiki@0.14.2)
|
||||
svg-pathdata:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3
|
||||
@@ -10681,7 +10690,6 @@ packages:
|
||||
|
||||
/ansi-sequence-parser@1.1.0:
|
||||
resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==}
|
||||
dev: true
|
||||
|
||||
/ansi-styles@2.2.1:
|
||||
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
|
||||
@@ -22249,14 +22257,21 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/shiki@0.14.1:
|
||||
resolution: {integrity: sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==}
|
||||
/shiki-processor@0.1.3(shiki@0.14.2):
|
||||
resolution: {integrity: sha512-oZqVFKweklwt+fj6yUPb+ffrCpYYoJ4RYxNt7w1+aoHetHq5ZaN6oX6+4HrypOi0s/O6A2neBpn+Xf6bM4KfsQ==}
|
||||
peerDependencies:
|
||||
shiki: 0.x
|
||||
dependencies:
|
||||
shiki: 0.14.2
|
||||
dev: false
|
||||
|
||||
/shiki@0.14.2:
|
||||
resolution: {integrity: sha512-ltSZlSLOuSY0M0Y75KA+ieRaZ0Trf5Wl3gutE7jzLuIcWxLp5i/uEnLoQWNvgKXQ5OMpGkJnVMRLAuzjc0LJ2A==}
|
||||
dependencies:
|
||||
ansi-sequence-parser: 1.1.0
|
||||
jsonc-parser: 3.2.0
|
||||
vscode-oniguruma: 1.7.0
|
||||
vscode-textmate: 8.0.0
|
||||
dev: true
|
||||
|
||||
/side-channel@1.0.4:
|
||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||
@@ -24400,7 +24415,7 @@ packages:
|
||||
body-scroll-lock: 4.0.0-beta.0
|
||||
mark.js: 8.11.1
|
||||
minisearch: 6.0.1
|
||||
shiki: 0.14.1
|
||||
shiki: 0.14.2
|
||||
vite: 4.3.1
|
||||
vue: 3.2.47
|
||||
transitivePeerDependencies:
|
||||
@@ -24556,11 +24571,9 @@ packages:
|
||||
|
||||
/vscode-oniguruma@1.7.0:
|
||||
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
|
||||
dev: true
|
||||
|
||||
/vscode-textmate@8.0.0:
|
||||
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
|
||||
dev: true
|
||||
|
||||
/vue-demi@0.14.0(vue@3.2.47):
|
||||
resolution: {integrity: sha512-gt58r2ogsNQeVoQ3EhoUAvUsH9xviydl0dWJj7dabBC/2L4uBId7ujtCwDRD0JhkGsV1i0CtfLAeyYKBht9oWg==}
|
||||
|
||||
Reference in New Issue
Block a user