@coffic/cosy-ui 0.1.25 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,64 +1,26 @@
1
- # Coffic Shared UI
1
+ # Cosy UI
2
2
 
3
3
  这是一个 Astro 组件库,为同一个组织下的多个项目提供统一的 UI 风格。
4
4
 
5
5
  ## 安装
6
6
 
7
7
  ```bash
8
- npm install @coffic/shared-ui
8
+ npm install @coffic/cosy-ui
9
9
  ```
10
10
 
11
- ## 必要依赖
12
-
13
- 本组件库依赖以下包,请确保您的项目中已正确安装和配置:
14
-
15
- ### 1. Astro
16
-
17
- 确保您的项目是一个 Astro 项目。如果不是,可以按照以下步骤创建:
18
-
19
- ```bash
20
- npm create astro@latest
21
- ```
22
-
23
- ### 2. TailwindCSS
24
-
25
- 如果您的项目还没有配置 TailwindCSS,请按照以下步骤安装:
26
-
27
- ```bash
28
- npm install -D tailwindcss @astrojs/tailwind
29
- ```
30
-
31
- 然后在您的 `astro.config.mjs` 中添加:
32
-
33
- ```javascript
34
- import tailwind from '@astrojs/tailwind';
11
+ Tailwind 的 CSS 文件中增加:
35
12
 
36
- export default defineConfig({
37
- integrations: [tailwind()],
38
- });
39
- ```
40
-
41
- ### 3. DaisyUI
42
-
43
- 安装 DaisyUI:
44
-
45
- ```bash
46
- npm install -D daisyui
13
+ ```css
14
+ @source '../node_modules/@coffic/shared-ui';
47
15
  ```
48
16
 
49
- 在您的 `tailwind.config.js` 中添加 DaisyUI:
50
-
51
- ```javascript
52
- export default {
53
- plugins: [require('daisyui')],
54
- };
55
- ```
17
+ ## 必要依赖
56
18
 
57
- ### 4. CSS
19
+ 本组件库依赖以下包,请确保您的项目中已正确安装和配置:
58
20
 
59
- ```css
60
- @source '../node_modules/@coffic/shared-ui';
61
- ```
21
+ - Astro
22
+ - TailwindCSS
23
+ - DaisyUI
62
24
 
63
25
  ## 内置组件
64
26
 
@@ -72,8 +34,6 @@ export default {
72
34
  - 组件的样式会受到您项目中 Tailwind 配置的影响
73
35
  - 如果您修改了 Tailwind 的默认主题或 DaisyUI 的主题,可能会影响组件的外观
74
36
 
75
- 2. 建议在您的项目中保持默认的 Tailwind 和 DaisyUI 配置,以确保组件显示正常
76
-
77
37
  ## 贡献
78
38
 
79
39
  欢迎提交 Issue 和 Pull Request!
package/index.ts CHANGED
@@ -1,7 +1,18 @@
1
- export { default as Header } from './src/components/Header.astro';
2
- export { default as Footer } from './src/components/Footer.astro';
1
+ // 这里用于导出所有组件,注意按照字母排序
2
+ export { default as Alert } from './src/components/Alert.astro';
3
+ export { default as Article } from './src/components/Article.astro';
4
+ export { default as Blog } from './src/components/Blog.astro';
3
5
  export { default as Banner } from './src/components/Banner.astro';
6
+ export { default as Button } from './src/components/Button.astro';
7
+ export { default as Card } from './src/components/Card.astro';
8
+ export { default as CodeBlock } from './src/components/CodeBlock.astro';
9
+ export { default as Footer } from './src/components/Footer.astro';
10
+ export { default as Header } from './src/components/Header.astro';
11
+ export { default as Hero } from './src/components/Hero.astro';
12
+ export { default as Image } from './src/components/Image.astro';
4
13
  export { default as Link } from './src/components/Link.astro';
14
+ export { default as Modal } from './src/components/Modal.astro';
5
15
  export { default as SocialIcon } from './src/components/SocialIcon.astro';
6
- export { default as Component } from './src/components/Component.astro';
7
- export { default as ThemeItem } from './src/components/ThemeItem.astro';
16
+ export { default as ThemeItem } from './src/components/ThemeItem.astro';
17
+ export { default as TeamMember } from './src/components/TeamMember.astro';
18
+ export { default as TeamMembers } from './src/components/TeamMembers.astro';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffic/cosy-ui",
3
- "version": "0.1.25",
3
+ "version": "0.1.28",
4
4
  "description": "A astro component library",
5
5
  "repository": {
6
6
  "url": "https://github.com/CofficLab/cosy-ui"
@@ -23,16 +23,19 @@
23
23
  "scripts": {
24
24
  "format": "prettier -w .",
25
25
  "lint": "eslint . --ext .ts,.js,.astro src",
26
- "dev": "cd example && astro dev --host 0.0.0.0"
26
+ "dev": "astro dev --host 0.0.0.0 --root example",
27
+ "build": "astro build --root example",
28
+ "preview": "astro preview --root example"
27
29
  },
28
30
  "devDependencies": {
31
+ "@tailwindcss/typography": "^0.5.16",
29
32
  "@tailwindcss/vite": "^4.0.14",
30
33
  "@types/chai": "^5.2.0",
31
34
  "@types/eslint": "^9.6.1",
32
35
  "@types/mocha": "^10.0.10",
33
36
  "@types/node": "^22.13.10",
34
37
  "@typescript-eslint/parser": "^8.26.1",
35
- "astro": "^5.5.1",
38
+ "astro": "^5.5.2",
36
39
  "chai": "^4.5.0",
37
40
  "daisyui": "^5.0.3",
38
41
  "eslint": "^8.57.1",
@@ -40,18 +43,18 @@
40
43
  "mocha": "^10.8.2",
41
44
  "prettier": "^3.5.3",
42
45
  "prettier-plugin-astro": "^0.14.1",
46
+ "sharp": "^0.33.2",
43
47
  "tailwindcss": "^4.0.14",
44
48
  "typescript": "^5.8.2"
45
49
  },
46
50
  "peerDependencies": {
47
- "@remixicon/vue": "^4.6.0",
48
- "@astrojs/vue": "^5.0.7",
49
51
  "astro": "^5.0.0",
50
- "daisyui": "^5.0.3",
51
- "tailwindcss": "^4.0.13"
52
+ "daisyui": "^5.0.3"
52
53
  },
53
54
  "dependencies": {
54
55
  "@astrojs/vue": "^5.0.7",
56
+ "@remixicon/vue": "^4.6.0",
57
+ "prismjs": "^1.29.0",
55
58
  "vue": "^3.5.13"
56
59
  }
57
60
  }
@@ -0,0 +1,78 @@
1
+ ---
2
+ interface Props {
3
+ type?: 'info' | 'success' | 'warning' | 'error';
4
+ title?: string;
5
+ closeable?: boolean;
6
+ class?: string;
7
+ }
8
+
9
+ const {
10
+ type = 'info',
11
+ title,
12
+ closeable = false,
13
+ class: className = '',
14
+ } = Astro.props;
15
+
16
+ // 根据类型设置样式
17
+ const alertClass = {
18
+ info: 'alert-info',
19
+ success: 'alert-success',
20
+ warning: 'alert-warning',
21
+ error: 'alert-error',
22
+ }[type];
23
+
24
+ // 根据类型设置图标
25
+ const icons = {
26
+ info: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="h-6 w-6 stroke-current">
27
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
28
+ </svg>`,
29
+ success: `<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 stroke-current" fill="none" viewBox="0 0 24 24">
30
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
31
+ </svg>`,
32
+ warning: `<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 stroke-current" fill="none" viewBox="0 0 24 24">
33
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
34
+ </svg>`,
35
+ error: `<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 stroke-current" fill="none" viewBox="0 0 24 24">
36
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
37
+ </svg>`,
38
+ };
39
+ ---
40
+
41
+ <div class={`alert ${alertClass} ${className}`} role="alert">
42
+ <div class="flex items-center gap-2">
43
+ <div set:html={icons[type]} />
44
+ <div class="flex-1">
45
+ {title && <h3 class="font-bold">{title}</h3>}
46
+ <div><slot /></div>
47
+ </div>
48
+ {closeable && (
49
+ <button class="btn btn-ghost btn-sm btn-circle close-alert">
50
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
51
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
52
+ </svg>
53
+ </button>
54
+ )}
55
+ </div>
56
+ </div>
57
+
58
+ {closeable && (
59
+ <script>
60
+ function initializeCloseButtons() {
61
+ const closeButtons = document.querySelectorAll('.close-alert');
62
+ closeButtons.forEach(button => {
63
+ button.addEventListener('click', () => {
64
+ const alert = button.closest('.alert');
65
+ if (alert) {
66
+ alert.remove();
67
+ }
68
+ });
69
+ });
70
+ }
71
+
72
+ // 初始化关闭按钮
73
+ initializeCloseButtons();
74
+
75
+ // Astro 页面切换时重新初始化
76
+ document.addEventListener('astro:page-load', initializeCloseButtons);
77
+ </script>
78
+ )}
@@ -0,0 +1,11 @@
1
+ ---
2
+ interface Props {
3
+ class?: string;
4
+ }
5
+
6
+ const { class: className = '' } = Astro.props;
7
+ ---
8
+
9
+ <article class:list={['prose prose-slate dark:prose-invert max-w-none', className]}>
10
+ <slot />
11
+ </article>
@@ -1,12 +1,49 @@
1
- <div class="w-full px-8 z-50 mx-auto">
1
+ <div class="w-full max-w-7xl px-4 sm:px-8 z-50 mx-auto">
2
2
  <div
3
- class="mt-0 hero p-4 rounded-2xl bg-base-300/50 dark:bg-base-200/50 backdrop-blur-xl hover:shadow-2xl transform duration-100">
3
+ class="mt-0 hero p-4 rounded-2xl bg-base-300/50 dark:bg-base-200/50 backdrop-blur-xl
4
+ hover:shadow-2xl transform duration-300 ease-in-out
5
+ hover:scale-[1.02] hover:bg-base-300/70 dark:hover:bg-base-200/70
6
+ motion-safe:animate-fadeIn"
7
+ >
4
8
  <div class="text-center hero-content">
5
- <div class="max-w-md flex flex-row justify-center items-center mx-auto">
6
- <p class="text-2xl md:text-3xl font-bold text-base-content">
9
+ <div class="w-full max-w-prose flex flex-row justify-center items-center mx-auto">
10
+ <p
11
+ class="text-xl sm:text-2xl md:text-3xl font-bold text-base-content
12
+ motion-safe:animate-slideUp"
13
+ >
7
14
  <slot />
8
15
  </p>
9
16
  </div>
10
17
  </div>
11
18
  </div>
12
19
  </div>
20
+
21
+ <style>
22
+ @keyframes fadeIn {
23
+ from {
24
+ opacity: 0;
25
+ }
26
+ to {
27
+ opacity: 1;
28
+ }
29
+ }
30
+
31
+ @keyframes slideUp {
32
+ from {
33
+ opacity: 0;
34
+ transform: translateY(1rem);
35
+ }
36
+ to {
37
+ opacity: 1;
38
+ transform: translateY(0);
39
+ }
40
+ }
41
+
42
+ .animate-fadeIn {
43
+ animation: fadeIn 0.5s ease-out;
44
+ }
45
+
46
+ .animate-slideUp {
47
+ animation: slideUp 0.5s ease-out;
48
+ }
49
+ </style>
@@ -0,0 +1,115 @@
1
+ ---
2
+ interface Props {
3
+ title: string;
4
+ subtitle?: string;
5
+ author?: string;
6
+ date?: Date;
7
+ cover?: {
8
+ src: string;
9
+ alt?: string;
10
+ };
11
+ tags?: string[];
12
+ }
13
+
14
+ const {
15
+ title,
16
+ subtitle,
17
+ author,
18
+ date,
19
+ cover,
20
+ tags = [],
21
+ } = Astro.props;
22
+
23
+ // 格式化日期
24
+ const formatDate = (date?: Date) => {
25
+ if (!date) return '';
26
+ return new Intl.DateTimeFormat('zh-CN', {
27
+ year: 'numeric',
28
+ month: 'long',
29
+ day: 'numeric'
30
+ }).format(date);
31
+ };
32
+ ---
33
+
34
+ <article class="article">
35
+ {/* 文章头部 */}
36
+ <header class="mb-8">
37
+ {cover && (
38
+ <div class="relative w-full h-[300px] md:h-[400px] mb-6 rounded-lg overflow-hidden">
39
+ <img
40
+ src={cover.src}
41
+ alt={cover.alt || title}
42
+ class="w-full h-full object-cover"
43
+ />
44
+ </div>
45
+ )}
46
+
47
+ <div class="space-y-4">
48
+ <h1 class="text-4xl md:text-5xl font-bold tracking-tight">{title}</h1>
49
+ {subtitle && (
50
+ <p class="text-xl text-base-content/70">{subtitle}</p>
51
+ )}
52
+
53
+ <div class="flex flex-wrap items-center gap-4 text-sm text-base-content/60">
54
+ {author && (
55
+ <div class="flex items-center gap-2">
56
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
57
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
58
+ </svg>
59
+ <span>{author}</span>
60
+ </div>
61
+ )}
62
+
63
+ {date && (
64
+ <div class="flex items-center gap-2">
65
+ <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor">
66
+ <rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
67
+ <line x1="16" y1="2" x2="16" y2="6"></line>
68
+ <line x1="8" y1="2" x2="8" y2="6"></line>
69
+ <line x1="3" y1="10" x2="21" y2="10"></line>
70
+ </svg>
71
+ <time datetime={date.toISOString()}>{formatDate(date)}</time>
72
+ </div>
73
+ )}
74
+ </div>
75
+
76
+ {tags.length > 0 && (
77
+ <div class="flex flex-wrap gap-2">
78
+ {tags.map(tag => (
79
+ <span class="badge badge-outline">{tag}</span>
80
+ ))}
81
+ </div>
82
+ )}
83
+ </div>
84
+ </header>
85
+
86
+ {/* 文章内容 */}
87
+ <div class="prose prose-lg max-w-none">
88
+ <slot />
89
+ </div>
90
+ </article>
91
+
92
+ <style>
93
+ /* 自定义文章样式 */
94
+ .article {
95
+ container-type: inline-size;
96
+ }
97
+
98
+ /* 优化大屏幕阅读体验 */
99
+ @container (min-width: 768px) {
100
+ .article {
101
+ font-size: 1.125rem;
102
+ line-height: 1.75;
103
+ }
104
+ }
105
+
106
+ /* 暗色主题适配 */
107
+ :global([data-theme="dark"]) .article {
108
+ --tw-prose-body: hsl(var(--bc));
109
+ --tw-prose-headings: hsl(var(--bc));
110
+ --tw-prose-links: hsl(var(--p));
111
+ --tw-prose-bold: hsl(var(--bc));
112
+ --tw-prose-quotes: hsl(var(--bc));
113
+ --tw-prose-code: hsl(var(--bc));
114
+ }
115
+ </style>
@@ -0,0 +1,49 @@
1
+ ---
2
+ interface Props {
3
+ variant?: 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost' | 'link' | 'outline' | 'neutral';
4
+ size?: 'lg' | 'md' | 'sm' | 'xs';
5
+ shape?: 'circle' | 'square';
6
+ wide?: boolean;
7
+ block?: boolean;
8
+ loading?: boolean;
9
+ disabled?: boolean;
10
+ type?: 'button' | 'submit' | 'reset';
11
+ class?: string;
12
+ onClick?: string;
13
+ }
14
+
15
+ const {
16
+ variant,
17
+ size,
18
+ shape,
19
+ wide = false,
20
+ block = false,
21
+ loading = false,
22
+ disabled = false,
23
+ type = 'button',
24
+ class: className,
25
+ onClick,
26
+ } = Astro.props;
27
+
28
+ const classes = [
29
+ 'btn',
30
+ variant && `btn-${variant}`,
31
+ size && `btn-${size}`,
32
+ shape && `btn-${shape}`,
33
+ wide && 'btn-wide',
34
+ block && 'btn-block',
35
+ loading && 'loading',
36
+ className,
37
+ ].filter(Boolean).join(' ');
38
+ ---
39
+
40
+ <button
41
+ type={type}
42
+ class={classes}
43
+ disabled={disabled}
44
+ onclick={onClick}
45
+ >
46
+ <slot name="icon-left" />
47
+ <slot />
48
+ <slot name="icon-right" />
49
+ </button>
@@ -0,0 +1,113 @@
1
+ ---
2
+ interface Props {
3
+ title?: string;
4
+ subtitle?: string;
5
+ imageUrl?: string;
6
+ href?: string;
7
+ }
8
+
9
+ const { title, subtitle, imageUrl, href } = Astro.props;
10
+ ---
11
+
12
+ <div class="group perspective-1000">
13
+ <div class:list={[
14
+ "card w-full bg-base-100/60 dark:bg-base-300/60 backdrop-blur-lg",
15
+ "transform transition-all duration-300 ease-out",
16
+ "hover:shadow-2xl hover:scale-[1.02]",
17
+ "active:scale-[0.98]",
18
+ "motion-safe:animate-fadeIn",
19
+ href && "cursor-pointer"
20
+ ]}>
21
+ {href ? (
22
+ <a href={href} class="card-body group-hover:translate-y-[-2px] transition-transform duration-300">
23
+ {imageUrl && (
24
+ <figure class="relative overflow-hidden rounded-t-2xl">
25
+ <img
26
+ src={imageUrl}
27
+ alt={title}
28
+ class="w-full h-48 object-cover transform transition-transform duration-300 group-hover:scale-105"
29
+ />
30
+ </figure>
31
+ )}
32
+ {title && (
33
+ <h2 class="card-title text-xl font-bold tracking-tight text-base-content">
34
+ {title}
35
+ </h2>
36
+ )}
37
+ {subtitle && (
38
+ <p class="text-base-content/80">
39
+ {subtitle}
40
+ </p>
41
+ )}
42
+ <slot />
43
+ </a>
44
+ ) : (
45
+ <div class="card-body">
46
+ {imageUrl && (
47
+ <figure class="relative overflow-hidden rounded-t-2xl">
48
+ <img
49
+ src={imageUrl}
50
+ alt={title}
51
+ class="w-full h-48 object-cover transform transition-transform duration-300 group-hover:scale-105"
52
+ />
53
+ </figure>
54
+ )}
55
+ {title && (
56
+ <h2 class="card-title text-xl font-bold tracking-tight text-base-content">
57
+ {title}
58
+ </h2>
59
+ )}
60
+ {subtitle && (
61
+ <p class="text-base-content/80">
62
+ {subtitle}
63
+ </p>
64
+ )}
65
+ <slot />
66
+ </div>
67
+ )}
68
+ </div>
69
+ </div>
70
+
71
+ <style>
72
+ @keyframes fadeIn {
73
+ from {
74
+ opacity: 0;
75
+ transform: translateY(10px);
76
+ }
77
+ to {
78
+ opacity: 1;
79
+ transform: translateY(0);
80
+ }
81
+ }
82
+
83
+ .animate-fadeIn {
84
+ animation: fadeIn 0.5s cubic-bezier(0.4, 0, 0.2, 1);
85
+ }
86
+
87
+ .perspective-1000 {
88
+ perspective: 1000px;
89
+ }
90
+
91
+ .card {
92
+ position: relative;
93
+ border: 1px solid rgba(255, 255, 255, 0.1);
94
+ }
95
+
96
+ .card::before {
97
+ content: '';
98
+ position: absolute;
99
+ inset: 0;
100
+ z-index: -1;
101
+ background: radial-gradient(
102
+ circle at 50% 0%,
103
+ rgba(255, 255, 255, 0.1),
104
+ transparent 70%
105
+ );
106
+ opacity: 0;
107
+ transition: opacity 0.3s ease;
108
+ }
109
+
110
+ .card:hover::before {
111
+ opacity: 1;
112
+ }
113
+ </style>