feat: first commit

This commit is contained in:
Yuwnei Xiao 2023-08-23 12:10:29 +08:00
parent 4ae85fdb0f
commit cb2cead693
23 changed files with 2523 additions and 2 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [xiaoluoboding]

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
lib
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

8
.prettierrc Normal file
View File

@ -0,0 +1,8 @@
{
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,
"semi": false,
"trailingComma": "none",
"printWidth": 80
}

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

View File

@ -1,2 +1,83 @@
# vue-library-starter
A minimal Vue library starter, built on top of Vite & Vue 3
# Vue Library Starter
[![NPM][npmBadge]][npmUrl]
[![Minzip Package][bundlePhobiaBadge]][bundlePhobiaUrl]
[![NPM Download][npmDtBadge]][npmDtUrl]
[npmBadge]: https://img.shields.io/npm/v/vue-library-starter.svg?maxAge=2592000
[npmUrl]: https://www.npmjs.com/package/vue-library-starter
[npmDtBadge]: https://img.shields.io/npm/dt/vue-library-starter.svg
[npmDtUrl]: https://www.npmjs.com/package/vue-library-starter
[bundlePhobiaBadge]: https://img.shields.io/bundlephobia/minzip/vue-library-starter
[bundlePhobiaUrl]: https://bundlephobia.com/package/vue-library-starter@latest
> A minimal Vue library starter, built on top of Vite & Vue 3
## Table of Contents
<details>
<summary>TOC</summary>
- [Vue Library Starter](#vue-library-starter)
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Use the Template](#use-the-template)
- [GitHub Template](#github-template)
- [Clone to local](#clone-to-local)
- [Usage](#usage)
- [1、Install dependencies](#1install-dependencies)
- [2、Build a library](#2build-a-library)
- [3、Publish to npm](#3publish-to-npm)
- [License](#license)
</details>
## Features
- Package manager [pnpm](https://pnpm.js.org/), safe and fast
- Bundle with the [library mode](https://vitejs.dev/guide/build.html#library-mode)
- Release with [semantic-release](https://www.npmjs.com/package/semantic-release)
- Publish to [npm](https://docs.npmjs.com/cli/v8/commands/npm-publish)
## Use the Template
### GitHub Template
[create a repo from this template on GitHub](https://github.com/new?template_name=vue-library-starter&template_owner=xiaoluoboding)
### Clone to local
```bash
git clone https://github.com/xiaoluoboding/vue-library-starter
cd vue-library-starter
```
## Usage
Building it is as easy as 1, 2, 3.
### 1、Install dependencies
```bash
pnpm install
```
### 2、Build a library
Rename all the `vue-library-starter` to your component name in the file `package.json、vite.config.ts`, eg: `my-component`
```bash
pnpm run build:lib
```
### 3、Publish to npm
```
npm publish
```
## License
MIT [@xiaoluoboding](https://github.com/xiaoluoboding)

18
components.d.ts vendored Normal file
View File

@ -0,0 +1,18 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
declare module 'vue' {
export interface GlobalComponents {
'Carbon:cafe': typeof import('~icons/carbon/cafe')['default']
'Carbon:logoGithub': typeof import('~icons/carbon/logo-github')['default']
'Carbon:logoTwitter': typeof import('~icons/carbon/logo-twitter')['default']
'Carbon:moon': typeof import('~icons/carbon/moon')['default']
'Carbon:sun': typeof import('~icons/carbon/sun')['default']
Logo: typeof import('./src/components/Logo.vue')['default']
'Mdi:heart': typeof import('~icons/mdi/heart')['default']
}
}

16
index.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Library Starter</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

49
package.json Normal file
View File

@ -0,0 +1,49 @@
{
"name": "vue-library-starter",
"description": "A minimal Vue library starter, built on top of Vite & Vue 3",
"version": "0.0.1",
"type": "module",
"author": "xiaoluoboding <xiaoluoboding@gmail.com>",
"scripts": {
"dev": "vite",
"build:docs": "vite build --mode docs",
"build:lib": "vue-tsc --noEmit && vite build --mode lib",
"preview": "vite preview",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/xiaoluoboding/vue-library-starter.git"
},
"homepage": "https://github.com/xiaoluoboding/vue-library-starter",
"files": [
"lib"
],
"main": "./lib/vue-library-starter.umd.cjs",
"module": "./lib/vue-library-starter.js",
"exports": {
".": {
"import": "./lib/vue-library-starter.js",
"require": "./lib/vue-library-starter.umd.cjs",
"types": "./lib/index.d.ts"
}
},
"types": "./lib/index.d.ts",
"devDependencies": {
"@iconify/json": "^2.2.104",
"@types/node": "^18.7.14",
"@unocss/reset": "^0.55.2",
"@vitejs/plugin-vue": "^4.3.2",
"@vueuse/core": "^10.3.0",
"highlight.js": "^11.6.0",
"sass": "^1.66.1",
"typescript": "^4.6.4",
"unocss": "^0.55.2",
"unplugin-icons": "^0.16.5",
"unplugin-vue-components": "^0.25.1",
"vite": "^4.4.9",
"vite-plugin-dts": "^3.5.2",
"vue": "^3.3.4",
"vue-tsc": "^1.8.8"
}
}

9
packages/MyComponent.vue Normal file
View File

@ -0,0 +1,9 @@
<template>
<div>Hello {{ msg }} !</div>
</template>
<script lang="ts" setup>
defineProps({
msg: String
})
</script>

1
packages/index.ts Normal file
View File

@ -0,0 +1 @@
export { default as MyComponent } from './MyComponent.vue'

1873
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

137
src/App.vue Normal file
View File

@ -0,0 +1,137 @@
<template>
<div class="w-full h-full min-h-screen bg-neutral-50 dark:bg-neutral-900">
<div class="container mx-auto max-w-5xl relative">
<nav class="h-20 py-4 flex-between text-primary">
<div class="font-semibold text-xl flex-center gap-2">
<Logo class="h-6 w-6" />
Vue Library Starter
</div>
<div class="flex-center gap-4">
<button
class="!bg-transparent opacity-50 hover:opacity-100 transition"
@click="(e) => toggleDarkmode()"
>
<carbon:moon class="w-6 h-6" v-if="isDark" />
<carbon:sun class="w-6 h-6" v-else />
</button>
<a
class="opacity-50 hover:opacity-100 transition"
href="https://github.com/xiaoluoboding/vue-library-starter"
>
<carbon:logo-github class="h-6 w-6" />
</a>
</div>
</nav>
<header class="py-20">
<div class="font-extrabold">
<span class="text-6xl text-neon">Build your own</span>
<div class="text-6xl text-primary">Vue Component Library</div>
</div>
<div
class="text-2xl font-semibold text-slate-700 py-4 dark:text-slate-200"
>
A minimal Vue library starter, built on top of Vite & Vue 3
</div>
<div class="flex gap-4 mt-8">
<a
class="bg-gray-200 hover:bg-gray-300 transition rounded-full text-lg font-semibold py-3 px-6 w-full sm:w-auto text-center"
href="https://github.com/xiaoluoboding/vue-library-starter"
target="_blank"
>
<span>Documentation</span>
</a>
<a
class="bg-emerald-400 hover:bg-emerald-500 flex items-center justify-center space-x-3 transition rounded-full text-white text-lg font-semibold py-3 px-6 w-full sm:w-auto cursor-pointer"
href="https://github.com/new?template_name=vue-library-starter&template_owner=xiaoluoboding"
target="_blank"
>
<span>Use the template</span>
</a>
</div>
</header>
<main class="grid grid-cols-1 gap-8 text-xs 2xl:text-sm">
<Highlight
:autodetect="false"
language="javascript"
:code="demoCode0"
/>
</main>
<footer
class="mt-16 w-full flex-center text-primary"
text="slate-900 dark:slate-300 opacity-60 sm"
>
<div class="copyright flex flex-col justify-center items-center">
<p>
Code with & by
<a class="text-neon" href="https://github.com/xiaoluoboding">
@xiaoluoboding
</a>
<span> © {{ new Date().getFullYear() }}</span>
</p>
<p class="flex items-center space-x-1">
<carbon:logo-twitter class="text-emerald-500" />
<span>
<a
href="https://twitter.com/xiaoluoboding"
class="text-neon"
target="_blank"
>
Follow me on Twitter
</a>
</span>
<span class="px-2 text-emerald-300">|</span>
<carbon:cafe class="text-emerald-500" />
<span>
<a
href="https://www.buymeacoffee.com/xlbd"
target="_blank"
class="text-neon"
>
Buy me a coffee
</a>
</span>
<span class="px-2 text-emerald-300">|</span>
<mdi:heart class="text-emerald-500" />
<span>
<a
href="https://github.com/sponsors/xiaoluoboding"
target="_blank"
class="text-neon"
>
Sponsor me on GitHub
</a>
</span>
</p>
</div>
</footer>
<div class="w-full mx-auto"></div>
</div>
</div>
</template>
<script lang="ts" setup>
import { isDark, toggleDarkmode } from '~/composables/useDarkmode'
const demoCode0 = `# install dependencies
> pnpm install
# start the doc app with HMR
> pnpm run dev
# build the doc app, available under /dist
> pnpm run build:docs
# build the library, available under /lib
> pnpm run build:lib
# create the changelog
> pnpm run changelog
`
</script>
<style lang="scss">
@import '~/assets/highlight.scss';
</style>

12
src/assets/highlight.scss Normal file
View File

@ -0,0 +1,12 @@
@use 'sass:meta';
html {
@include meta.load-css('highlight.js/styles/github');
}
html.dark {
@include meta.load-css('highlight.js/styles/github-dark');
}
code.hljs {
border-radius: 16px;
}

45
src/components/Logo.vue Normal file
View File

@ -0,0 +1,45 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--logos"
width="31.88"
height="32"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 256 257"
>
<defs>
<linearGradient
id="IconifyId1813088fe1fbc01fb466"
x1="-.828%"
x2="57.636%"
y1="7.652%"
y2="78.411%"
>
<stop offset="0%" stop-color="#41D1FF"></stop>
<stop offset="100%" stop-color="#BD34FE"></stop>
</linearGradient>
<linearGradient
id="IconifyId1813088fe1fbc01fb467"
x1="43.376%"
x2="50.316%"
y1="2.242%"
y2="89.03%"
>
<stop offset="0%" stop-color="#FFEA83"></stop>
<stop offset="8.333%" stop-color="#FFDD35"></stop>
<stop offset="100%" stop-color="#FFA800"></stop>
</linearGradient>
</defs>
<path
fill="url(#IconifyId1813088fe1fbc01fb466)"
d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"
></path>
<path
fill="url(#IconifyId1813088fe1fbc01fb467)"
d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"
></path>
</svg>
</template>

View File

@ -0,0 +1,4 @@
import { useDark, useToggle } from '@vueuse/core'
export const isDark = useDark()
export const toggleDarkmode = useToggle(isDark)

11
src/main.ts Normal file
View File

@ -0,0 +1,11 @@
import { createApp } from 'vue'
import App from './App.vue'
import 'uno.css'
import '@unocss/reset/tailwind-compat.css'
import highlight from '~/plugins/highlight'
const app = createApp(App)
app.use(highlight)
app.mount('#app')

104
src/plugins/highlight.ts Normal file
View File

@ -0,0 +1,104 @@
import { ref, h, computed, defineComponent, Plugin, watch } from 'vue'
import hljs from 'highlight.js/lib/core'
import javascript from 'highlight.js/lib/languages/javascript'
import xml from 'highlight.js/lib/languages/xml'
hljs.registerLanguage('javascript', javascript)
hljs.registerLanguage('xml', xml)
function escapeHtml(value: string): string {
return value
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;')
}
const component = defineComponent({
props: {
code: {
type: String,
required: true
},
language: {
type: String,
default: ''
},
autodetect: {
type: Boolean,
default: true
},
ignoreIllegals: {
type: Boolean,
default: true
}
},
setup(props) {
const language = ref(props.language)
watch(
() => props.language,
(newLanguage) => {
language.value = newLanguage
}
)
const autodetect = computed(() => props.autodetect || !language.value)
const cannotDetectLanguage = computed(
() => !autodetect.value && !hljs.getLanguage(language.value)
)
const className = computed((): string => {
if (cannotDetectLanguage.value) {
return ''
} else {
return `hljs ${language.value}`
}
})
const highlightedCode = computed((): string => {
// No idea what language to use, return raw code
if (cannotDetectLanguage.value) {
console.warn(
`The language "${language.value}" you specified could not be found.`
)
return escapeHtml(props.code)
}
if (autodetect.value) {
const result = hljs.highlightAuto(props.code)
language.value = result.language ?? ''
return result.value
} else {
const result = hljs.highlight(props.code, {
language: language.value,
ignoreIllegals: props.ignoreIllegals
})
return result.value
}
})
return {
className,
highlightedCode
}
},
render() {
return h('pre', {}, [
h('code', {
class: this.className,
innerHTML: this.highlightedCode,
tabindex: '0'
})
])
}
})
const plugin: Plugin & { component: typeof component } = {
install(app) {
app.component('Highlight', component)
},
component
}
export default plugin

7
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

32
tsconfig.json Normal file
View File

@ -0,0 +1,32 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"@/*": ["packages/*"],
"~/*": ["./src/*"]
}
},
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
"src/**/*.tsx",
"src/**/*.vue",
"packages/**/*.ts",
"packages/**/*.d.ts",
"packages/**/*.tsx",
"packages/**/*.vue"
],
"references": [{ "path": "./tsconfig.node.json" }]
}

9
tsconfig.node.json Normal file
View File

@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

14
unocss.config.ts Normal file
View File

@ -0,0 +1,14 @@
import { defineConfig, presetUno, presetAttributify } from 'unocss'
export default defineConfig({
presets: [presetUno(), presetAttributify()],
shortcuts: [
{
'flex-center': 'flex justify-center items-center',
'flex-between': 'flex justify-between items-center',
'text-primary': 'text-neutral-900 dark:text-neutral-50',
'text-neon':
'text-transparent bg-clip-text bg-gradient-to-r from-emerald-500 to-emerald-700 dark:to-emerald-300 '
}
]
})

59
vite.config.ts Normal file
View File

@ -0,0 +1,59 @@
import { defineConfig, UserConfig } from 'vite'
import { resolve } from 'path'
import vue from '@vitejs/plugin-vue'
import dts from 'vite-plugin-dts'
import UnoCSS from 'unocss/vite'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
import Components from 'unplugin-vue-components/vite'
// https://vitejs.dev/config/
export default defineConfig(({ command, mode }) => {
let userConfig: UserConfig = {}
if (mode === 'lib') {
userConfig.build = {
lib: {
entry: resolve(__dirname, 'packages/index.ts'),
name: 'VueLibraryStarter',
fileName: 'vue-library-starter'
},
outDir: 'lib',
emptyOutDir: true,
sourcemap: false,
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue'
}
}
}
}
}
return {
resolve: {
alias: {
'@': resolve(__dirname, '/packages'),
'~': resolve(__dirname, '/src')
}
},
plugins: [
vue(),
dts({
include: './packages'
}),
UnoCSS(),
Components({
resolvers: [
IconsResolver({
prefix: ''
})
]
}),
Icons()
],
...userConfig
}
})