feat: add license plugin

pull/48/MERGE
vben 2024-06-23 19:45:40 +08:00
parent 24aab5b4bb
commit 16ed5a05ba
16 changed files with 156 additions and 74 deletions

13
.github/semantic.yml vendored Normal file
View File

@ -0,0 +1,13 @@
titleAndCommits: true
types:
- feat
- fix
- docs
- chore
- style
- refactor
- perf
- test
- build
- ci
- revert

View File

@ -31,6 +31,7 @@
"@changesets/git": "^3.0.0",
"@manypkg/get-packages": "^2.2.1",
"consola": "^3.2.3",
"dayjs": "^1.11.11",
"find-up": "^7.0.0",
"nanoid": "^5.0.7",
"pkg-types": "^1.1.1",

View File

@ -0,0 +1,10 @@
import dayjs from 'dayjs';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
dayjs.extend(timezone);
const dateUtil = dayjs().tz('Asia/Shanghai');
export { dateUtil };

View File

@ -1,13 +1,9 @@
export { UNICODE } from './constants';
export * from './constants';
export * from './date';
export * from './git';
export { add as gitAdd, getStagedFiles } from './git';
export { generatorContentHash } from './hash';
export {
findMonorepoRoot,
getPackage,
getPackages,
getPackagesSync,
} from './monorepo';
export * from './monorepo';
export { toPosixPath } from './path';
export { prettierFormat } from './prettier';
export type { Package } from '@manypkg/get-packages';

View File

@ -25,6 +25,7 @@ function defineApplicationConfig(options: DefineApplicationOptions = {}) {
i18n: true,
injectAppLoading: true,
isBuild,
license: true,
mock: true,
mode,
pwa: true,

View File

@ -1,11 +1,11 @@
import type { PluginOption } from 'vite';
import {
colors,
generatorContentHash,
readPackageJSON,
} from '@vben/node-utils';
import { type PluginOption } from 'vite';
import { getEnvConfig } from '../utils/env';
interface PluginOptions {

View File

@ -27,6 +27,7 @@ import viteVueDevTools from 'vite-plugin-vue-devtools';
import { viteExtraAppConfigPlugin } from './extra-app-config';
import { viteImportMapPlugin } from './importmap';
import { viteInjectAppLoadingPlugin } from './inject-app-loading';
import { viteLicensePlugin } from './license';
/**
* vite
@ -94,12 +95,12 @@ async function getApplicationConditionPlugins(
compress,
compressTypes,
extraAppConfig,
html,
i18n,
importmap,
importmapOptions,
injectAppLoading,
license,
mock,
pwa,
pwaOptions,
@ -130,6 +131,10 @@ async function getApplicationConditionPlugins(
condition: injectAppLoading,
plugins: async () => [await viteInjectAppLoadingPlugin(!!isBuild, env)],
},
{
condition: license,
plugins: async () => [await viteLicensePlugin()],
},
{
condition: pwa,
plugins: () =>

View File

@ -0,0 +1,76 @@
import type {
NormalizedOutputOptions,
OutputAsset,
OutputBundle,
OutputChunk,
} from 'rollup';
import type { PluginOption } from 'vite';
import { EOL } from 'node:os';
import { dateUtil, readPackageJSON } from '@vben/node-utils';
/**
*
* @returns
*/
async function viteLicensePlugin(
root = process.cwd(),
): Promise<PluginOption | undefined> {
const {
description = '',
homepage = '',
version = '',
} = await readPackageJSON(root);
return {
apply: 'build',
enforce: 'post',
generateBundle: {
handler: (_options: NormalizedOutputOptions, bundle: OutputBundle) => {
const date = dateUtil.format('YYYY-MM-DD ');
const copyrightText = `/*!
* Vben Admin Pro
* Version: ${version}
* Author: vben
* Copyright (C) 2024 Vben
* License: MIT License
* Description: ${description}
* Date Created: ${date}
* Homepage: ${homepage}
* Contact: ann.vben@gmail.com
*/
`.trim();
for (const [, fileContent] of Object.entries(bundle)) {
if (
fileContent.type === 'asset' ||
(fileContent.type === 'chunk' && fileContent.isEntry)
) {
const chunkContent = fileContent as OutputChunk;
const assetContent = fileContent as OutputAsset;
// 插入版权信息
const content =
typeof assetContent.source === 'string'
? assetContent.source
: chunkContent.code;
const updatedContent = `${copyrightText}${EOL}${content}`;
// 更新bundle
if (assetContent.source === undefined) {
(fileContent as OutputChunk).code = updatedContent;
} else {
(fileContent as OutputAsset).source = updatedContent;
}
}
}
},
order: 'post',
},
name: 'vite:license',
};
}
export { viteLicensePlugin };

View File

@ -67,6 +67,8 @@ interface ApplicationPluginOptions extends CommonPluginOptions {
importmapOptions?: ImportmapPluginOptions;
/** 是否注入app loading */
injectAppLoading?: boolean;
/** 是否注入版权信息 */
license?: boolean;
/** mock 插件配置 */
mock?: boolean;
/** 是否开启pwa */

View File

@ -83,8 +83,9 @@
"packageManager": "pnpm@9.4.0",
"pnpm": {
"overrides": {
"@ctrl/tinycolor": "4.1.0",
"clsx": "2.1.1",
"@ant-design/colors": "^7.0.2",
"@ctrl/tinycolor": "^4.1.0",
"clsx": "^2.1.1",
"vue": "^3.4.30"
},
"neverBuiltDependencies": [

View File

@ -43,6 +43,7 @@ function handleMouseenter(menu: MenuRecordRaw) {
is(theme, true),
is('rounded', rounded),
]"
class="relative"
>
<template v-for="menu in menus" :key="menu.path">
<li
@ -66,9 +67,7 @@ function handleMouseenter(menu: MenuRecordRaw) {
--menu-item-padding-x: 0px;
--menu-item-radius: 0px;
--menu-dark-background: 0deg 0% 100% / 10%;
// --menu-light-background: 240deg 5% 96%;
position: relative;
height: calc(100% - 4px);
@include is('rounded') {

View File

@ -8,27 +8,11 @@
--tabs-active-background: hsl(var(--primary) / 100%);
--tabs-active: hsl(var(--primary-foreground));
position: relative;
width: 100%;
height: 100%;
padding-top: 4px;
background-color: var(--tabs-background);
@include e('content') {
position: relative;
height: 32px;
overflow: hidden;
}
}
@include b('chrome-tab') {
position: absolute;
display: flex;
align-items: center;
height: 100%;
color: hsl(var(--muted-foreground));
cursor: pointer;
user-select: none;
@include is('active') {
z-index: 2;
@ -57,7 +41,6 @@
position: absolute;
right: 0;
left: 0;
// z-index: 1;
display: flex;
align-items: center;
height: 100%;
@ -174,59 +157,37 @@
}
@include b('chrome-tab-background') {
position: absolute;
width: 100%;
height: 100%;
padding: 0 calc(var(--tabs-gap) + 0px);
@include e('divider') {
position: absolute;
left: 0;
width: calc(100% - 14px);
height: 100%;
margin: 0 7px;
&::before {
position: absolute;
top: 20%;
right: 100%;
width: 1px;
height: 60%;
content: '';
background-color: var(--tabs-divider);
}
&::after {
position: absolute;
top: 20%;
left: calc(100% - 1px);
width: 1px;
height: 60%;
content: '';
background-color: var(--tabs-divider);
}
}
@include e('content') {
height: 100%;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
transition: background 0.15s ease;
}
@include e('before') {
position: absolute;
bottom: -1px;
left: -3px;
fill: transparent;
transition: 0.15s;
}
@include e('after') {
position: absolute;
right: -3px;
bottom: -1px;
fill: transparent;
transition: 0.15s;
}
}

View File

@ -9,13 +9,26 @@ const { b, e } = useNamespace('chrome-tab-background');
</script>
<template>
<div :class="b()">
<div :class="e('divider')"></div>
<div :class="e('content')"></div>
<svg :class="e('before')" height="10" width="10">
<div :class="b()" class="absolute size-full">
<div
:class="e('divider')"
class="absolute left-0 h-full before:absolute before:right-[100%] before:top-[15%] before:h-[60%] before:w-[1px] before:content-[''] after:absolute after:top-[15%] after:h-[60%] after:w-[1px] after:content-['']"
></div>
<div :class="e('content')" class="h-full"></div>
<svg
:class="e('before')"
class="absolute fill-transparent"
height="10"
width="10"
>
<path d="M 0 10 A 10 10 0 0 0 10 0 L 10 10 Z" />
</svg>
<svg :class="e('after')" height="10" width="10">
<svg
:class="e('after')"
class="absolute fill-transparent"
height="10"
width="10"
>
<path d="M 0 0 A 10 10 0 0 0 10 10 L 0 10 Z" />
</svg>
</div>

View File

@ -38,7 +38,10 @@ function handleUnPushPin() {
</script>
<template>
<div :class="[b()]">
<div
:class="[b()]"
class="absolute flex h-full cursor-pointer select-none items-center"
>
<VbenContextMenu :handler-data="tab" :menus="menus" item-class="pr-4">
<div class="h-full">
<TabBackground />

View File

@ -83,8 +83,12 @@ function handleUnPushPin(tab: TabItem) {
</script>
<template>
<div :class="b()">
<div ref="contentRef" :class="e('content')">
<div :class="b()" class="relative size-full pt-1">
<div
ref="contentRef"
:class="e('content')"
class="relative h-8 overflow-hidden"
>
<TransitionGroup name="slide-down">
<Tab
v-for="(tab, i) in tabsView"

View File

@ -5,8 +5,9 @@ settings:
excludeLinksFromLockfile: false
overrides:
'@ctrl/tinycolor': 4.1.0
clsx: 2.1.1
'@ant-design/colors': ^7.0.2
'@ctrl/tinycolor': ^4.1.0
clsx: ^2.1.1
vue: ^3.4.30
importers:
@ -328,6 +329,9 @@ importers:
consola:
specifier: ^3.2.3
version: 3.2.3
dayjs:
specifier: ^1.11.11
version: 1.11.11
find-up:
specifier: ^7.0.0
version: 7.0.0
@ -556,7 +560,7 @@ importers:
specifier: ^7.0.2
version: 7.0.2
'@ctrl/tinycolor':
specifier: 4.1.0
specifier: ^4.1.0
version: 4.1.0
packages/@core/shared/design:
@ -582,7 +586,7 @@ importers:
specifier: ^3.4.30
version: 3.4.30
clsx:
specifier: 2.1.1
specifier: ^2.1.1
version: 2.1.1
dayjs:
specifier: ^1.11.11
@ -978,9 +982,6 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@ant-design/colors@6.0.0':
resolution: {integrity: sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==}
'@ant-design/colors@7.0.2':
resolution: {integrity: sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==}
@ -8928,10 +8929,6 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
'@ant-design/colors@6.0.0':
dependencies:
'@ctrl/tinycolor': 4.1.0
'@ant-design/colors@7.0.2':
dependencies:
'@ctrl/tinycolor': 4.1.0
@ -8940,7 +8937,7 @@ snapshots:
'@ant-design/icons-vue@7.0.1(vue@3.4.30(typescript@5.5.2))':
dependencies:
'@ant-design/colors': 6.0.0
'@ant-design/colors': 7.0.2
'@ant-design/icons-svg': 4.4.2
vue: 3.4.30(typescript@5.5.2)
@ -12141,7 +12138,7 @@ snapshots:
ant-design-vue@4.2.3(vue@3.4.30(typescript@5.5.2)):
dependencies:
'@ant-design/colors': 6.0.0
'@ant-design/colors': 7.0.2
'@ant-design/icons-vue': 7.0.1(vue@3.4.30(typescript@5.5.2))
'@babel/runtime': 7.24.7
'@ctrl/tinycolor': 4.1.0