sa2kit 1.6.57 → 1.6.59
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/dist/AliyunOSSProvider-KSYW2IOG.js +15 -0
- package/dist/{AliyunOSSProvider-2FARPAQD.js.map → AliyunOSSProvider-KSYW2IOG.js.map} +1 -1
- package/dist/AliyunOSSProvider-TBK3G7YK.mjs +6 -0
- package/dist/{AliyunOSSProvider-UMVGVBDJ.mjs.map → AliyunOSSProvider-TBK3G7YK.mjs.map} +1 -1
- package/dist/LocalStorageProvider-2DGYRQAB.mjs +6 -0
- package/dist/{LocalStorageProvider-PYOHETJV.mjs.map → LocalStorageProvider-2DGYRQAB.mjs.map} +1 -1
- package/dist/LocalStorageProvider-SSRW3ZJW.js +15 -0
- package/dist/{LocalStorageProvider-JQF5WK5H.js.map → LocalStorageProvider-SSRW3ZJW.js.map} +1 -1
- package/dist/UniversalFileService-336GFY6N.mjs +6 -0
- package/dist/{UniversalFileService-TNYKO6JN.mjs.map → UniversalFileService-336GFY6N.mjs.map} +1 -1
- package/dist/UniversalFileService-J6ET6KZK.js +15 -0
- package/dist/{UniversalFileService-RBV6EN5J.js.map → UniversalFileService-J6ET6KZK.js.map} +1 -1
- package/dist/calendar/index.js +11 -11
- package/dist/calendar/index.mjs +4 -4
- package/dist/chunk-25OFOKNF.js +171 -0
- package/dist/chunk-25OFOKNF.js.map +1 -0
- package/dist/chunk-3DXPQ4YV.mjs +165 -0
- package/dist/chunk-3DXPQ4YV.mjs.map +1 -0
- package/dist/{chunk-4VJQZSPU.mjs → chunk-3NHAT7D4.mjs} +3 -4
- package/dist/chunk-3NHAT7D4.mjs.map +1 -0
- package/dist/{chunk-3JW4X3AC.mjs → chunk-622Y6LTH.mjs} +3 -3
- package/dist/{chunk-3JW4X3AC.mjs.map → chunk-622Y6LTH.mjs.map} +1 -1
- package/dist/{chunk-HYZ5C6FY.mjs → chunk-7CMGQX3S.mjs} +1199 -1995
- package/dist/chunk-7CMGQX3S.mjs.map +1 -0
- package/dist/chunk-CIVO4R6N.mjs +37 -0
- package/dist/chunk-CIVO4R6N.mjs.map +1 -0
- package/dist/{chunk-6BJ76BYC.mjs → chunk-EGJPS7OL.mjs} +3 -3
- package/dist/{chunk-6BJ76BYC.mjs.map → chunk-EGJPS7OL.mjs.map} +1 -1
- package/dist/{chunk-UR5TU4MW.mjs → chunk-FVDPGX6A.mjs} +3 -3
- package/dist/{chunk-UR5TU4MW.mjs.map → chunk-FVDPGX6A.mjs.map} +1 -1
- package/dist/chunk-HDMIOOZY.mjs +546 -0
- package/dist/chunk-HDMIOOZY.mjs.map +1 -0
- package/dist/{chunk-MZKATHB7.js → chunk-HHVDOIPV.js} +4 -4
- package/dist/{chunk-MZKATHB7.js.map → chunk-HHVDOIPV.js.map} +1 -1
- package/dist/chunk-HJ6MH7J7.js +552 -0
- package/dist/chunk-HJ6MH7J7.js.map +1 -0
- package/dist/chunk-KH6RQ4J5.js +28 -0
- package/dist/chunk-KH6RQ4J5.js.map +1 -0
- package/dist/{chunk-53WLQ22S.js → chunk-LJGJPAQ4.js} +6 -6
- package/dist/{chunk-53WLQ22S.js.map → chunk-LJGJPAQ4.js.map} +1 -1
- package/dist/{chunk-35CXIK5Y.js → chunk-NCOXT7SK.js} +11 -11
- package/dist/{chunk-35CXIK5Y.js.map → chunk-NCOXT7SK.js.map} +1 -1
- package/dist/chunk-NZZZUMMX.mjs +784 -0
- package/dist/chunk-NZZZUMMX.mjs.map +1 -0
- package/dist/{chunk-OBIPI4GU.mjs → chunk-OFYBMMWT.mjs} +4 -4
- package/dist/{chunk-OBIPI4GU.mjs.map → chunk-OFYBMMWT.mjs.map} +1 -1
- package/dist/chunk-Q5EDCKQA.js +336 -0
- package/dist/chunk-Q5EDCKQA.js.map +1 -0
- package/dist/{chunk-U7AQC2Z7.js → chunk-SKCMZYSQ.js} +1203 -2001
- package/dist/chunk-SKCMZYSQ.js.map +1 -0
- package/dist/{chunk-6NMIKAE7.mjs → chunk-SNBILYSH.mjs} +5 -5
- package/dist/{chunk-6NMIKAE7.mjs.map → chunk-SNBILYSH.mjs.map} +1 -1
- package/dist/{chunk-IPY26RQH.js → chunk-UVHPCLP6.js} +5 -5
- package/dist/{chunk-IPY26RQH.js.map → chunk-UVHPCLP6.js.map} +1 -1
- package/dist/{chunk-V6BXO6ZS.mjs → chunk-UZB4IO3T.mjs} +835 -38
- package/dist/chunk-UZB4IO3T.mjs.map +1 -0
- package/dist/{chunk-W2NCOORK.js → chunk-WK3HTUID.js} +951 -145
- package/dist/chunk-WK3HTUID.js.map +1 -0
- package/dist/chunk-YMS6BPXS.js +807 -0
- package/dist/chunk-YMS6BPXS.js.map +1 -0
- package/dist/chunk-YOTQG4NP.mjs +314 -0
- package/dist/chunk-YOTQG4NP.mjs.map +1 -0
- package/dist/chunk-ZGVB35L2.mjs +25 -0
- package/dist/chunk-ZGVB35L2.mjs.map +1 -0
- package/dist/chunk-ZRAW3HXA.js +43 -0
- package/dist/chunk-ZRAW3HXA.js.map +1 -0
- package/dist/{chunk-4XXIBWCO.js → chunk-ZRWED7Q6.js} +66 -66
- package/dist/{chunk-4XXIBWCO.js.map → chunk-ZRWED7Q6.js.map} +1 -1
- package/dist/{chunk-DVENFCQY.js → chunk-ZWQJSZEY.js} +4 -5
- package/dist/chunk-ZWQJSZEY.js.map +1 -0
- package/dist/components/index.js +104 -104
- package/dist/components/index.mjs +4 -4
- package/dist/index.js +146 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -11
- package/dist/index.mjs.map +1 -1
- package/dist/logger/index.js +7 -7
- package/dist/logger/index.mjs +1 -4
- package/dist/mikuFusionGame/index.js +4 -4
- package/dist/mikuFusionGame/index.mjs +3 -3
- package/dist/portfolio/index.js +10 -10
- package/dist/portfolio/index.mjs +5 -5
- package/dist/showmasterpiece/db/index.js +42 -42
- package/dist/showmasterpiece/db/index.mjs +1 -1
- package/dist/showmasterpiece/index.js +143 -144
- package/dist/showmasterpiece/index.js.map +1 -1
- package/dist/showmasterpiece/index.mjs +7 -9
- package/dist/showmasterpiece/index.mjs.map +1 -1
- package/dist/showmasterpiece/logic/index.d.mts +10 -1
- package/dist/showmasterpiece/logic/index.d.ts +10 -1
- package/dist/showmasterpiece/logic/index.js +19 -19
- package/dist/showmasterpiece/logic/index.mjs +2 -2
- package/dist/showmasterpiece/server/index.js +42 -42
- package/dist/showmasterpiece/server/index.mjs +1 -1
- package/dist/showmasterpiece/ui/web/index.js +34 -34
- package/dist/showmasterpiece/ui/web/index.mjs +6 -6
- package/dist/universalExport/server/index.js +2 -4
- package/dist/universalExport/server/index.js.map +1 -1
- package/dist/universalExport/server/index.mjs +1 -3
- package/dist/universalExport/server/index.mjs.map +1 -1
- package/dist/universalFile/index.js +6 -9
- package/dist/universalFile/index.js.map +1 -1
- package/dist/universalFile/index.mjs +1 -5
- package/dist/universalFile/index.mjs.map +1 -1
- package/dist/universalFile/server/index.js +31 -64
- package/dist/universalFile/server/index.js.map +1 -1
- package/dist/universalFile/server/index.mjs +7 -42
- package/dist/universalFile/server/index.mjs.map +1 -1
- package/dist/utils/index.js +11 -11
- package/dist/utils/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/AliyunOSSProvider-2FARPAQD.js +0 -15
- package/dist/AliyunOSSProvider-UMVGVBDJ.mjs +0 -9
- package/dist/LocalStorageProvider-JQF5WK5H.js +0 -15
- package/dist/LocalStorageProvider-PYOHETJV.mjs +0 -9
- package/dist/UniversalFileService-RBV6EN5J.js +0 -15
- package/dist/UniversalFileService-TNYKO6JN.mjs +0 -9
- package/dist/chunk-4NFOSCM6.js +0 -34
- package/dist/chunk-4NFOSCM6.js.map +0 -1
- package/dist/chunk-4VJQZSPU.mjs.map +0 -1
- package/dist/chunk-6AHYPPUP.js +0 -344
- package/dist/chunk-6AHYPPUP.js.map +0 -1
- package/dist/chunk-76V7EKBX.mjs +0 -796
- package/dist/chunk-76V7EKBX.mjs.map +0 -1
- package/dist/chunk-ACLOJXXE.js +0 -195
- package/dist/chunk-ACLOJXXE.js.map +0 -1
- package/dist/chunk-AEXPAH7Z.mjs +0 -32
- package/dist/chunk-AEXPAH7Z.mjs.map +0 -1
- package/dist/chunk-CFGX3EKK.js +0 -560
- package/dist/chunk-CFGX3EKK.js.map +0 -1
- package/dist/chunk-D2HXMGXS.js +0 -46
- package/dist/chunk-D2HXMGXS.js.map +0 -1
- package/dist/chunk-DVENFCQY.js.map +0 -1
- package/dist/chunk-HYZ5C6FY.mjs.map +0 -1
- package/dist/chunk-K7WNCB4V.mjs +0 -554
- package/dist/chunk-K7WNCB4V.mjs.map +0 -1
- package/dist/chunk-L4ZYBFB2.mjs +0 -44
- package/dist/chunk-L4ZYBFB2.mjs.map +0 -1
- package/dist/chunk-M4HGHTIC.js +0 -820
- package/dist/chunk-M4HGHTIC.js.map +0 -1
- package/dist/chunk-PXWDQFWV.mjs +0 -192
- package/dist/chunk-PXWDQFWV.mjs.map +0 -1
- package/dist/chunk-U7AQC2Z7.js.map +0 -1
- package/dist/chunk-V6BXO6ZS.mjs.map +0 -1
- package/dist/chunk-VTGPHE4Z.mjs +0 -322
- package/dist/chunk-VTGPHE4Z.mjs.map +0 -1
- package/dist/chunk-W2NCOORK.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/universalFile/server/types.ts"],"names":[],"mappings":";;;AA8cO,IAAM,gBAAA,GAAN,cAA+B,KAAA,CAAM;AAAA,EAC1C,WAAA,CACE,OAAA,EACgB,IAAA,EACA,OAAA,EAChB;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAHG,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF,CAAA;AAmBO,IAAM,oBAAA,GAAN,cAAmC,gBAAA,CAAiB;AAAA,EACzD,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,OAAA,EAAS,0BAA0B,OAAO,CAAA;AAChD,IAAA,IAAA,CAAK,IAAA,GAAO,sBAAA;AAAA,EACd;AACF;AAGO,IAAM,gBAAA,GAAN,cAA+B,gBAAA,CAAiB;AAAA,EACrD,WAAA,CAAY,SAAiB,OAAA,EAA+B;AAC1D,IAAA,KAAA,CAAM,OAAA,EAAS,sBAAsB,OAAO,CAAA;AAC5C,IAAA,IAAA,CAAK,IAAA,GAAO,kBAAA;AAAA,EACd;AACF","file":"chunk-KH6RQ4J5.js","sourcesContent":["/**\n * UniversalFile Server 端类型定义\n */\n\nimport type {\n StorageType as _StorageType,\n CDNType as _CDNType,\n ProcessorType as _ProcessorType,\n FileMetadata,\n UploadStatus,\n AccessPermission,\n UploadFileInfo as _UploadFileInfo,\n ProcessingOptions as _ProcessingOptions,\n} from '../types';\n\n// Re-export client types for server use\nexport type StorageType = _StorageType;\nexport type CDNType = _CDNType;\nexport type ProcessorType = _ProcessorType;\nexport type UploadFileInfo = _UploadFileInfo;\nexport type ProcessingOptions = _ProcessingOptions;\n\n// ============= Provider 接口 =============\n\n/** 存储提供者接口 */\nexport interface IStorageProvider {\n /** 提供者类型 */\n readonly type: StorageType;\n\n /** 初始化 */\n initialize(config: StorageConfig): Promise<void>;\n\n /** 上传文件 */\n upload(fileInfo: UploadFileInfo, path: string): Promise<StorageResult>;\n\n /** 下载文件 */\n download(path: string): Promise<Buffer>;\n\n /** 删除文件 */\n delete(path: string): Promise<StorageResult>;\n\n /** 获取文件信息 */\n getFileInfo(path: string): Promise<StorageResult>;\n\n /** 生成访问URL */\n getAccessUrl(path: string, expiresIn?: number): Promise<string>;\n\n /** 生成预签名上传URL */\n getUploadUrl(path: string, expiresIn?: number): Promise<string>;\n\n /** 检查文件是否存在 */\n exists(path: string): Promise<boolean>;\n\n /** 列出文件 */\n list(prefix: string, maxKeys?: number): Promise<string[]>;\n}\n\n/** CDN 提供者接口 */\nexport interface ICDNProvider {\n /** 提供者类型 */\n readonly type: CDNType;\n\n /** 初始化 */\n initialize(config: CDNConfig): Promise<void>;\n\n /** 生成CDN URL */\n generateUrl(originalUrl: string): Promise<string>;\n\n /** 刷新缓存 */\n refreshCache(urls: string[]): Promise<CDNResult>;\n\n /** 预热缓存 */\n preheatCache(urls: string[]): Promise<CDNResult>;\n\n /** 获取访问统计 */\n getAccessStats(startTime: Date, endTime: Date): Promise<CDNResult>;\n}\n\n/** 文件处理器接口 */\nexport interface IFileProcessor {\n /** 处理器类型 */\n readonly type: ProcessorType;\n\n /** 初始化 */\n initialize(): Promise<void>;\n\n /** 处理文件 */\n process(\n inputPath: string,\n outputPath: string,\n options: ProcessingOptions\n ): Promise<ProcessingResult>;\n\n /** 检查文件是否支持处理 */\n supports(mimeType: string): boolean;\n\n /** 获取文件信息 */\n getFileInfo(filePath: string): Promise<Record<string, any>>;\n}\n\n// ============= 配置接口 =============\n\n/** 存储配置基础接口 */\nexport interface StorageConfig {\n /** 存储类型 */\n type: StorageType;\n /** 是否启用 */\n enabled: boolean;\n}\n\n/** 本地存储配置 */\nexport interface LocalStorageConfig extends StorageConfig {\n type: 'local';\n /** 存储根目录 */\n rootPath: string;\n /** 基础URL */\n baseUrl: string;\n}\n\n/** 阿里云 OSS 配置 */\nexport interface AliyunOSSConfig extends StorageConfig {\n type: 'aliyun-oss';\n /** 地域 */\n region: string;\n /** 存储桶名称 */\n bucket: string;\n /** 访问密钥ID */\n accessKeyId: string;\n /** 访问密钥密码 */\n accessKeySecret: string;\n /** 自定义域名 */\n customDomain?: string;\n /** 是否使用HTTPS */\n secure?: boolean;\n /** 是否使用内网访问 */\n internal?: boolean;\n}\n\n/** CDN配置基础接口 */\nexport interface CDNConfig {\n /** CDN类型 */\n type: CDNType;\n /** 是否启用 */\n enabled: boolean;\n}\n\n/** 阿里云 CDN 配置 */\nexport interface AliyunCDNConfig extends CDNConfig {\n type: 'aliyun-cdn';\n /** CDN域名 */\n domain: string;\n /** 访问密钥ID */\n accessKeyId: string;\n /** 访问密钥密码 */\n accessKeySecret: string;\n /** 地域 */\n region?: string;\n}\n\n/** 缓存配置 */\nexport interface CacheConfig {\n /** 是否启用缓存 */\n enabled: boolean;\n /** 最大缓存大小 */\n maxSize?: number;\n /** 缓存 TTL(秒) */\n ttl?: number;\n /** 是否使用 Redis */\n useRedis?: boolean;\n /** Redis 配置 */\n redisConfig?: {\n host: string;\n port: number;\n password?: string;\n db?: number;\n };\n}\n\n/** 文件服务配置 */\n/** 缓存配置扩展 */\nexport interface CacheConfig {\n /** 是否启用缓存 */\n enabled: boolean;\n /** 元数据缓存TTL(秒) */\n metadataTTL?: number;\n /** URL缓存TTL(秒) */\n urlTTL?: number;\n /** 最大缓存条目数 */\n maxSize?: number;\n}\n\nexport interface UniversalFileServiceConfig {\n /** 存储配置 */\n storage: StorageConfig;\n /** CDN 配置(可选) */\n cdn?: CDNConfig;\n /** 缓存配置(可选) */\n cache?: CacheConfig;\n /** 数据库持久化配置(可选) */\n persistence?: FileServicePersistenceConfig;\n /** 启用的处理器 */\n processors?: ProcessorType[];\n /** 数据库连接(可选) @deprecated 使用 persistence.repository 代替 */\n db?: any;\n /** 最大文件大小(字节) */\n maxFileSize?: number;\n /** 允许的文件类型 */\n allowedMimeTypes?: string[];\n /** 是否启用监控 */\n enableMonitoring?: boolean;\n\n // 运行时字段(由服务类内部管理)\n /** 存储提供者映射(内部使用) */\n storageProviders?: Map<StorageType, IStorageProvider>;\n /** 默认存储类型 */\n defaultStorage?: StorageType;\n /** 默认CDN类型 */\n defaultCDN?: CDNType;\n}\n\n// ============= 结果类型 =============\n\n/** 存储结果 */\n/** 存储操作结果 */\nexport interface StorageResult {\n /** 是否成功 */\n success: boolean;\n /** 存储路径 */\n path?: string;\n /** 访问URL */\n url?: string;\n /** 文件大小 */\n size?: number;\n /** 错误信息 */\n error?: string;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** 存储元数据 */\nexport interface StorageMetadata {\n /** 文件大小 */\n size: number;\n /** MIME 类型 */\n mimeType: string;\n /** 最后修改时间 */\n lastModified: Date;\n /** 自定义元数据 */\n metadata?: Record<string, any>;\n}\n\n/** CDN 结果 */\n/** CDN操作结果 */\nexport interface CDNResult {\n /** 是否成功 */\n success: boolean;\n /** CDN URL */\n url?: string;\n /** 错误信息 */\n error?: string;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** CDN 统计信息 */\nexport interface CDNStats {\n /** 带宽(字节/秒) */\n bandwidth: number;\n /** 请求数 */\n requests: number;\n /** 流量(字节) */\n traffic: number;\n /** 统计时间范围 */\n timeRange: {\n start: Date;\n end: Date;\n };\n}\n\n/** 处理结果 */\nexport interface ProcessingResult {\n /** 是否成功 */\n success: boolean;\n /** 处理后的文件路径 */\n processedPath?: string;\n /** 处理后的文件大小 */\n processedSize?: number;\n /** 缩略图路径 */\n thumbnailPath?: string;\n /** 错误信息 */\n error?: string;\n /** 处理耗时(毫秒) */\n processingTime?: number;\n /** 额外数据 */\n data?: Record<string, any>;\n}\n\n/** 处理器信息 */\nexport interface ProcessorInfo {\n /** 处理器名称 */\n name: string;\n /** 处理器版本 */\n version: string;\n /** 支持的格式 */\n supportedFormats: string[];\n /** 支持的操作 */\n supportedOperations: string[];\n}\n\n// ============= 数据库相关类型 =============\n\n/** 文件数据库记录 */\nexport interface FileRecord extends FileMetadata {\n /** 创建时间 */\n createdAt: Date | string;\n /** 更新时间 */\n updatedAt: Date | string;\n}\n\n/** 文件查询选项 */\nexport interface FileQueryOptions {\n /** 模块 ID */\n moduleId?: string;\n /** 业务 ID */\n businessId?: string;\n /** 上传者 ID */\n uploaderId?: string;\n /** 文件类型 */\n mimeType?: string;\n /** 访问权限 */\n permission?: AccessPermission;\n /** 状态 */\n status?: UploadStatus;\n /** 分页 */\n page?: number;\n pageSize?: number;\n /** 排序 */\n orderBy?: string;\n orderDirection?: 'asc' | 'desc';\n}\n\n/** 分页结果 */\nexport interface PaginatedResult<T> {\n /** 数据列表 */\n items: T[];\n /** 总数 */\n total: number;\n /** 当前页 */\n page: number;\n /** 每页大小 */\n pageSize: number;\n /** 总页数 */\n totalPages: number;\n}\n\n// ============= 事件类型 =============\n\n/** 文件事件类型 */\nexport type FileEventType =\n | 'upload:start'\n | 'upload:progress'\n | 'upload:complete'\n | 'upload:error'\n | 'download:start'\n | 'download:complete'\n | 'download:error'\n | 'delete:complete'\n | 'delete:error'\n | 'process:start'\n | 'process:complete'\n | 'process:error';\n\n/** 文件事件 */\nexport interface FileEvent {\n /** 事件类型 */\n type: FileEventType;\n /** 文件 ID */\n fileId: string;\n /** 事件数据 */\n data?: any;\n /** 时间戳 */\n timestamp: Date;\n}\n\n/** 事件监听器 */\nexport type FileEventListener = (event: FileEvent) => void | Promise<void>;\n\n// ============= 数据库持久化接口 =============\n\n/**\n * 文件元数据数据库持久化接口\n *\n * 实现此接口以提供自定义的数据库持久化支持\n *\n * @example\n * ```typescript\n * // Drizzle ORM 实现\n * class DrizzleFileRepository implements IFileMetadataRepository {\n * async save(metadata: FileMetadata): Promise<void> {\n * await db.insert(fileMetadata).values(metadata);\n * }\n * // ... 其他方法\n * }\n * ```\n */\nexport interface IFileMetadataRepository {\n /**\n * 保存文件元数据到数据库\n */\n save(metadata: FileMetadata): Promise<void>;\n\n /**\n * 从数据库获取文件元数据\n */\n get(fileId: string): Promise<FileMetadata | null>;\n\n /**\n * 查询文件列表\n */\n query(options: FileQueryOptions): Promise<PaginatedResult<FileMetadata>>;\n\n /**\n * 从数据库删除文件元数据\n */\n delete(fileId: string): Promise<void>;\n\n /**\n * 批量删除文件元数据\n */\n batchDelete(fileIds: string[]): Promise<void>;\n}\n\n/**\n * 数据库持久化配置\n */\nexport interface FileServicePersistenceConfig {\n /**\n * 是否启用持久化\n */\n enabled: boolean;\n\n /**\n * 持久化仓储实现\n */\n repository: IFileMetadataRepository;\n\n /**\n * 是否自动持久化(默认 true)\n * 如果为 true,文件上传完成后自动保存到数据库\n */\n autoPersist?: boolean;\n\n /**\n * 是否优先使用缓存(默认 false)\n * 如果为 true,查询时优先从缓存获取\n */\n cacheFirst?: boolean;\n}\n\n// ============= 异常类型定义 =============\n\n/** 文件服务异常基类 */\nexport class FileServiceError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly details?: Record<string, any>\n ) {\n super(message);\n this.name = 'FileServiceError';\n }\n}\n\n/** 文件上传异常 */\nexport class FileUploadError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'FILE_UPLOAD_ERROR', details);\n this.name = 'FileUploadError';\n }\n}\n\n/** 文件处理异常 */\nexport class FileProcessingError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'FILE_PROCESSING_ERROR', details);\n this.name = 'FileProcessingError';\n }\n}\n\n/** 存储提供者异常 */\nexport class StorageProviderError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'STORAGE_PROVIDER_ERROR', details);\n this.name = 'StorageProviderError';\n }\n}\n\n/** CDN提供者异常 */\nexport class CDNProviderError extends FileServiceError {\n constructor(message: string, details?: Record<string, any>) {\n super(message, 'CDN_PROVIDER_ERROR', details);\n this.name = 'CDNProviderError';\n }\n}\n"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSKCMZYSQ_js = require('./chunk-SKCMZYSQ.js');
|
|
4
4
|
|
|
5
5
|
// src/showmasterpiece/logic/index.ts
|
|
6
|
-
|
|
6
|
+
chunkSKCMZYSQ_js.init_hooks();
|
|
7
7
|
|
|
8
8
|
// src/showmasterpiece/logic/contexts/index.ts
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
chunkSKCMZYSQ_js.init_CartContext();
|
|
10
|
+
chunkSKCMZYSQ_js.init_hooks();
|
|
11
11
|
|
|
12
12
|
// src/showmasterpiece/logic/shared/storage.ts
|
|
13
13
|
var hasWxStorage = () => typeof wx !== "undefined" && typeof wx.getStorageSync === "function";
|
|
@@ -115,5 +115,5 @@ exports.clearCart = clearCart;
|
|
|
115
115
|
exports.getCart = getCart;
|
|
116
116
|
exports.removeCartItem = removeCartItem;
|
|
117
117
|
exports.updateCartItem = updateCartItem;
|
|
118
|
-
//# sourceMappingURL=chunk-
|
|
119
|
-
//# sourceMappingURL=chunk-
|
|
118
|
+
//# sourceMappingURL=chunk-LJGJPAQ4.js.map
|
|
119
|
+
//# sourceMappingURL=chunk-LJGJPAQ4.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/showmasterpiece/logic/index.ts","../src/showmasterpiece/logic/contexts/index.ts","../src/showmasterpiece/logic/shared/storage.ts","../src/showmasterpiece/logic/shared/cart.ts"],"names":["init_hooks","init_CartContext"],"mappings":"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","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/showmasterpiece/logic/index.ts","../src/showmasterpiece/logic/contexts/index.ts","../src/showmasterpiece/logic/shared/storage.ts","../src/showmasterpiece/logic/shared/cart.ts"],"names":["init_hooks","init_CartContext"],"mappings":"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","file":"chunk-LJGJPAQ4.js","sourcesContent":["export * from './hooks';\nexport * from './contexts';\nexport * from './shared';\n","export { CartProvider } from './CartContext';\nexport { useCartContext } from '../hooks';\n","declare const wx: any;\n\nconst hasWxStorage = (): boolean =>\n typeof wx !== 'undefined' && typeof (wx as any).getStorageSync === 'function';\n\nconst hasLocalStorage = (): boolean =>\n typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function';\n\nexport const getStorageSync = <T>(key: string): T | null => {\n try {\n if (hasWxStorage()) {\n return (wx as any).getStorageSync(key) as T;\n }\n if (hasLocalStorage()) {\n const value = localStorage.getItem(key);\n return value ? (JSON.parse(value) as T) : null;\n }\n } catch {\n return null;\n }\n return null;\n};\n\nexport const setStorageSync = (key: string, value: unknown): void => {\n try {\n if (hasWxStorage()) {\n (wx as any).setStorageSync(key, value);\n return;\n }\n if (hasLocalStorage()) {\n localStorage.setItem(key, JSON.stringify(value));\n }\n } catch {\n // ignore\n }\n};\n","import type { Cart } from '../../types/cart';\nimport type { ArtCollection } from '../../types';\nimport { getStorageSync, setStorageSync } from './storage';\n\nconst CART_STORAGE_KEY = 'showmasterpiece_cart';\n\nconst normalizeCart = (cart?: Cart): Cart => {\n const safeCart: Cart = cart ?? { items: [], totalPrice: 0, totalQuantity: 0 };\n const totals = safeCart.items.reduce(\n (acc, item) => {\n acc.totalQuantity += item.quantity;\n acc.totalPrice += (item.collection.price || 0) * item.quantity;\n return acc;\n },\n { totalQuantity: 0, totalPrice: 0 }\n );\n\n return {\n ...safeCart,\n totalQuantity: totals.totalQuantity,\n totalPrice: totals.totalPrice\n };\n};\n\nexport const getCart = (): Cart => {\n const stored = getStorageSync<Cart>(CART_STORAGE_KEY);\n if (stored && stored.items) {\n return normalizeCart(stored);\n }\n return normalizeCart();\n};\n\nconst saveCart = (cart: Cart) => {\n setStorageSync(CART_STORAGE_KEY, cart);\n};\n\nexport const addToCart = (collection: ArtCollection, quantity = 1): Cart => {\n const cart = getCart();\n const existing = cart.items.find(item => item.collectionId === collection.id);\n\n if (existing) {\n existing.quantity += quantity;\n } else {\n cart.items.push({\n collectionId: collection.id,\n collection,\n quantity,\n addedAt: new Date()\n });\n }\n\n const next = normalizeCart(cart);\n saveCart(next);\n return next;\n};\n\nexport const updateCartItem = (collectionId: number, quantity: number): Cart => {\n const cart = getCart();\n const target = cart.items.find(item => item.collectionId === collectionId);\n if (!target) return cart;\n\n if (quantity <= 0) {\n cart.items = cart.items.filter(item => item.collectionId !== collectionId);\n } else {\n target.quantity = quantity;\n }\n\n const next = normalizeCart(cart);\n saveCart(next);\n return next;\n};\n\nexport const removeCartItem = (collectionId: number): Cart => {\n const cart = getCart();\n cart.items = cart.items.filter(item => item.collectionId !== collectionId);\n const next = normalizeCart(cart);\n saveCart(next);\n return next;\n};\n\nexport const clearCart = (): Cart => {\n const empty = normalizeCart({ items: [], totalPrice: 0, totalQuantity: 0 });\n saveCart(empty);\n return empty;\n};\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkZRWED7Q6_js = require('./chunk-ZRWED7Q6.js');
|
|
4
|
+
var chunkZWQJSZEY_js = require('./chunk-ZWQJSZEY.js');
|
|
5
5
|
var React2 = require('react');
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var Link = require('next/link');
|
|
@@ -15,7 +15,7 @@ var About = ({
|
|
|
15
15
|
timelineConfig,
|
|
16
16
|
collisionBallsConfig
|
|
17
17
|
}) => {
|
|
18
|
-
return /* @__PURE__ */ React2__default.default.createElement("section", { id: "about", className: "py-16 bg-white" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "container mx-auto px-4" }, /* @__PURE__ */ React2__default.default.createElement("h2", { className: "text-3xl font-bold text-center mb-12" }, "\u5173\u4E8E\u6211"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-12" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "bg-white rounded-lg shadow-lg p-6" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-2xl font-semibold mb-6" }, "\u4E2A\u4EBA\u7ECF\u5386"), /* @__PURE__ */ React2__default.default.createElement(
|
|
18
|
+
return /* @__PURE__ */ React2__default.default.createElement("section", { id: "about", className: "py-16 bg-white" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "container mx-auto px-4" }, /* @__PURE__ */ React2__default.default.createElement("h2", { className: "text-3xl font-bold text-center mb-12" }, "\u5173\u4E8E\u6211"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-12" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "bg-white rounded-lg shadow-lg p-6" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-2xl font-semibold mb-6" }, "\u4E2A\u4EBA\u7ECF\u5386"), /* @__PURE__ */ React2__default.default.createElement(chunkZRWED7Q6_js.Timeline, { items: timelineConfig.items })), /* @__PURE__ */ React2__default.default.createElement("div", { className: "bg-white rounded-lg shadow-lg p-6" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-2xl font-semibold mb-6" }, "\u6280\u80FD\u5C55\u793A"), /* @__PURE__ */ React2__default.default.createElement("div", { style: { height: "400px", position: "relative" } }, /* @__PURE__ */ React2__default.default.createElement(chunkZRWED7Q6_js.CollisionBalls, { collisionBallsConfig }))))));
|
|
19
19
|
};
|
|
20
20
|
var About_default = About;
|
|
21
21
|
var Contact = () => {
|
|
@@ -115,7 +115,7 @@ var Home = ({ homeConfig, className }) => {
|
|
|
115
115
|
"section",
|
|
116
116
|
{
|
|
117
117
|
id: "home",
|
|
118
|
-
className:
|
|
118
|
+
className: chunkZWQJSZEY_js.cn("min-h-screen flex items-center justify-center py-16 bg-gradient-to-b from-white to-gray-50", className)
|
|
119
119
|
},
|
|
120
120
|
/* @__PURE__ */ React2__default.default.createElement("div", { className: "container mx-auto px-4" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col md:flex-row items-center gap-12" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex-1 text-center md:text-left" }, /* @__PURE__ */ React2__default.default.createElement("h1", { className: "text-4xl md:text-6xl font-bold mb-6 text-gray-900" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: "inline-block" }, displayText), /* @__PURE__ */ React2__default.default.createElement("span", { className: "animate-pulse ml-1 text-blue-500" }, "|")), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-xl md:text-2xl text-gray-600 mb-8" }, subtitle), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-wrap gap-4 justify-center md:justify-start" }, buttons.map((button) => /* @__PURE__ */ React2__default.default.createElement(
|
|
121
121
|
"a",
|
|
@@ -160,10 +160,10 @@ var ExperimentCard = ({
|
|
|
160
160
|
return dateString;
|
|
161
161
|
}
|
|
162
162
|
};
|
|
163
|
-
return /* @__PURE__ */ React2__default.default.createElement(Link__default.default, { href, className:
|
|
163
|
+
return /* @__PURE__ */ React2__default.default.createElement(Link__default.default, { href, className: chunkZWQJSZEY_js.cn("block group", className) }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "w-full h-full bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 transform group-hover:-translate-y-1 border border-gray-100 hover:border-gray-200" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "p-6" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-start justify-between mb-4" }, /* @__PURE__ */ React2__default.default.createElement("h3", { className: "text-xl font-semibold text-gray-900 flex-1 pr-4 leading-tight" }, title), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-col gap-2 flex-shrink-0" }, /* @__PURE__ */ React2__default.default.createElement("span", { className: chunkZWQJSZEY_js.cn(
|
|
164
164
|
"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm",
|
|
165
165
|
category === "utility" ? "bg-gradient-to-r from-green-50 to-green-100 text-green-700 border border-green-200" : "bg-gradient-to-r from-purple-50 to-purple-100 text-purple-700 border border-purple-200"
|
|
166
|
-
) }, category === "utility" ? "\u{1F527} \u5B9E\u7528\u5DE5\u5177" : "\u{1F3AE} \u4F11\u95F2\u5A31\u4E50"), /* @__PURE__ */ React2__default.default.createElement("span", { className:
|
|
166
|
+
) }, category === "utility" ? "\u{1F527} \u5B9E\u7528\u5DE5\u5177" : "\u{1F3AE} \u4F11\u95F2\u5A31\u4E50"), /* @__PURE__ */ React2__default.default.createElement("span", { className: chunkZWQJSZEY_js.cn(
|
|
167
167
|
"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm border",
|
|
168
168
|
isCompleted ? "bg-gradient-to-r from-emerald-50 to-emerald-100 text-emerald-700 border border-emerald-200" : "bg-gradient-to-r from-orange-50 to-orange-100 text-orange-700 border border-orange-200"
|
|
169
169
|
) }, isCompleted ? "\u2705 \u5DF2\u5B8C\u6210" : "\u{1F6A7} \u8FDB\u884C\u4E2D"))), /* @__PURE__ */ React2__default.default.createElement("p", { className: "text-gray-600 mb-4" }, description), updatedAt && /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex items-center gap-1 mb-3 text-xs text-gray-500" }, /* @__PURE__ */ React2__default.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", className: "h-4 w-4", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" }, /* @__PURE__ */ React2__default.default.createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" })), /* @__PURE__ */ React2__default.default.createElement("span", null, "\u66F4\u65B0\u4E8E: ", formatDate(updatedAt)), createdAt && createdAt !== updatedAt && /* @__PURE__ */ React2__default.default.createElement("span", { className: "ml-2 text-gray-400" }, "\u521B\u5EFA\u4E8E: ", formatDate(createdAt))), /* @__PURE__ */ React2__default.default.createElement("div", { className: "flex flex-wrap gap-2" }, tags.map((tag) => /* @__PURE__ */ React2__default.default.createElement(
|
|
@@ -188,11 +188,11 @@ var ProjectCarousel = ({ projects, className }) => {
|
|
|
188
188
|
(prevIndex) => prevIndex === 0 ? projects.length - 1 : prevIndex - 1
|
|
189
189
|
);
|
|
190
190
|
};
|
|
191
|
-
return /* @__PURE__ */ React2__default.default.createElement("section", { id: "projects", className:
|
|
191
|
+
return /* @__PURE__ */ React2__default.default.createElement("section", { id: "projects", className: chunkZWQJSZEY_js.cn("py-16 bg-gray-50", className) }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "container mx-auto px-4" }, /* @__PURE__ */ React2__default.default.createElement("h2", { className: "text-3xl font-bold text-center mb-12 text-gray-900" }, "\u9879\u76EE\u5C55\u793A"), /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative max-w-4xl mx-auto" }, /* @__PURE__ */ React2__default.default.createElement("div", { className: "relative h-[400px] overflow-hidden rounded-lg shadow-xl" }, projects.map((project, index) => /* @__PURE__ */ React2__default.default.createElement(
|
|
192
192
|
"div",
|
|
193
193
|
{
|
|
194
194
|
key: project.id,
|
|
195
|
-
className:
|
|
195
|
+
className: chunkZWQJSZEY_js.cn(
|
|
196
196
|
"absolute w-full h-full transition-all duration-500 transform",
|
|
197
197
|
index === currentIndex ? "translate-x-0 opacity-100" : index < currentIndex ? "-translate-x-full opacity-0" : "translate-x-full opacity-0"
|
|
198
198
|
)
|
|
@@ -260,7 +260,7 @@ var ProjectCarousel = ({ projects, className }) => {
|
|
|
260
260
|
{
|
|
261
261
|
key: index,
|
|
262
262
|
onClick: () => setCurrentIndex(index),
|
|
263
|
-
className:
|
|
263
|
+
className: chunkZWQJSZEY_js.cn(
|
|
264
264
|
"w-2 h-2 rounded-full transition-all duration-300",
|
|
265
265
|
index === currentIndex ? "bg-blue-500 w-4" : "bg-gray-300"
|
|
266
266
|
)
|
|
@@ -273,5 +273,5 @@ exports.Contact_default = Contact_default;
|
|
|
273
273
|
exports.ExperimentCard = ExperimentCard;
|
|
274
274
|
exports.Home_default = Home_default;
|
|
275
275
|
exports.ProjectCarousel = ProjectCarousel;
|
|
276
|
-
//# sourceMappingURL=chunk-
|
|
277
|
-
//# sourceMappingURL=chunk-
|
|
276
|
+
//# sourceMappingURL=chunk-NCOXT7SK.js.map
|
|
277
|
+
//# sourceMappingURL=chunk-NCOXT7SK.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/portfolio/About.tsx","../src/portfolio/Contact.tsx","../src/portfolio/Home.tsx","../src/portfolio/ExperimentCard.tsx","../src/portfolio/ProjectCarousel.tsx"],"names":["React","Timeline","CollisionBalls","useState","clsx","useEffect","cn","Link"],"mappings":"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","file":"chunk-35CXIK5Y.js","sourcesContent":["'use client';\n\nimport React from \"react\";\n\nimport { CollisionBalls, Timeline } from \"@/components\";\nimport type { TimelineConfig, CollisionBallsConfig } from \"@/components\";\n\ninterface AboutProps {\n timelineConfig: TimelineConfig;\n collisionBallsConfig: CollisionBallsConfig;\n}\n\nconst About: React.FC<AboutProps> = ({\n timelineConfig,\n collisionBallsConfig,\n}) => {\n return (\n <section id=\"about\" className=\"py-16 bg-white\">\n <div className=\"container mx-auto px-4\">\n <h2 className=\"text-3xl font-bold text-center mb-12\">关于我</h2>\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-12\">\n <div className=\"bg-white rounded-lg shadow-lg p-6\">\n <h3 className=\"text-2xl font-semibold mb-6\">个人经历</h3>\n <Timeline items={timelineConfig.items} />\n </div>\n <div className=\"bg-white rounded-lg shadow-lg p-6\">\n <h3 className=\"text-2xl font-semibold mb-6\">技能展示</h3>\n <div style={{ height: '400px', position: 'relative' }}>\n <CollisionBalls collisionBallsConfig={collisionBallsConfig} />\n </div>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default About;\n","'use client';\n\nimport React, { useState } from 'react';\nimport { clsx } from 'clsx';\n\ninterface FormData {\n name: string;\n email: string;\n message: string;\n}\n\nconst Contact: React.FC = () => {\n const [formData, setFormData] = useState<FormData>({\n name: '',\n email: '',\n message: ''\n });\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value } = e.target;\n setFormData(prev => ({\n ...prev,\n [name]: value\n }));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setSubmitStatus('idle');\n\n try {\n // 这里添加你的表单提交逻辑\n await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟API调用\n setSubmitStatus('success');\n setFormData({ name: '', email: '', message: '' });\n } catch (error) {\n setSubmitStatus('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <section id=\"contact\" className=\"py-16 bg-gray-50\">\n <div className=\"max-w-4xl mx-auto px-4 sm:px-6 lg:px-8\">\n <div className=\"text-center mb-12\">\n <h2 className=\"text-3xl font-bold text-gray-900 sm:text-4xl\">\n 联系我\n </h2>\n <p className=\"mt-4 text-lg text-gray-600\">\n 有任何问题或建议?请随时联系我\n </p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-xl p-6 sm:p-8\">\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <div>\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-gray-700\">\n 姓名\n </label>\n <input\n type=\"text\"\n name=\"name\"\n id=\"name\"\n value={formData.name}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的姓名\"\n />\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700\">\n 邮箱\n </label>\n <input\n type=\"email\"\n name=\"email\"\n id=\"email\"\n value={formData.email}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的邮箱\"\n />\n </div>\n\n <div>\n <label htmlFor=\"message\" className=\"block text-sm font-medium text-gray-700\">\n 消息\n </label>\n <textarea\n name=\"message\"\n id=\"message\"\n rows={4}\n value={formData.message}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的消息\"\n />\n </div>\n\n <div className=\"flex items-center justify-end\">\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className={clsx('inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white', isSubmitting \n ? 'bg-blue-400 cursor-not-allowed' \n : 'bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500')}\n >\n {isSubmitting ? '发送中...' : '发送消息'}\n </button>\n </div>\n\n {submitStatus === 'success' && (\n <div className=\"rounded-md bg-green-50 p-4\">\n <div className=\"flex\">\n <div className=\"flex-shrink-0\">\n <svg className=\"h-5 w-5 text-green-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n <div className=\"ml-3\">\n <p className=\"text-sm font-medium text-green-800\">\n 消息已成功发送!\n </p>\n </div>\n </div>\n </div>\n )}\n\n {submitStatus === 'error' && (\n <div className=\"rounded-md bg-red-50 p-4\">\n <div className=\"flex\">\n <div className=\"flex-shrink-0\">\n <svg className=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n <div className=\"ml-3\">\n <p className=\"text-sm font-medium text-red-800\">\n 发送失败,请稍后重试\n </p>\n </div>\n </div>\n </div>\n )}\n </form>\n </div>\n\n {/* 联系方式 */}\n <div className=\"mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">邮箱</h3>\n <p className=\"mt-2 text-gray-600\">your.email@example.com</p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">电话</h3>\n <p className=\"mt-2 text-gray-600\">+86 123 4567 8900</p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">地址</h3>\n <p className=\"mt-2 text-gray-600\">中国,北京</p>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default Contact; ","'use client';\n\nimport React, { useEffect, useState } from \"react\";\nimport { cn } from '@/utils';\n\nexport interface HomeConfig {\n title: string;\n subtitle: string;\n buttons: Array<{\n text: string;\n link: string;\n }>;\n imageSrc: string;\n}\n\ninterface HomeProps {\n homeConfig: HomeConfig;\n className?: string;\n}\n\nexport const Home: React.FC<HomeProps> = ({ homeConfig, className }) => {\n const { title, subtitle, buttons, imageSrc } = homeConfig;\n const [displayText, setDisplayText] = useState(\"\");\n const [currentIndex, setCurrentIndex] = useState(0);\n\n useEffect(() => {\n if (currentIndex < title.length) {\n const timer = setTimeout(() => {\n setDisplayText((prev) => prev + title[currentIndex]);\n setCurrentIndex((prev) => prev + 1);\n }, 150);\n\n return () => clearTimeout(timer);\n }\n return () => {\n setDisplayText(\"\");\n setCurrentIndex(0);\n };\n }, [currentIndex, title]);\n\n return (\n <section \n id=\"home\" \n className={cn(\"min-h-screen flex items-center justify-center py-16 bg-gradient-to-b from-white to-gray-50\", className)}\n >\n <div className=\"container mx-auto px-4\">\n <div className=\"flex flex-col md:flex-row items-center gap-12\">\n <div className=\"flex-1 text-center md:text-left\">\n <h1 className=\"text-4xl md:text-6xl font-bold mb-6 text-gray-900\">\n <span className=\"inline-block\">{displayText}</span>\n <span className=\"animate-pulse ml-1 text-blue-500\">|</span>\n </h1>\n <p className=\"text-xl md:text-2xl text-gray-600 mb-8\">{subtitle}</p>\n <div className=\"flex flex-wrap gap-4 justify-center md:justify-start\">\n {buttons.map((button) => (\n <a\n key={button.link}\n href={button.link}\n className=\"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-300 shadow-md hover:shadow-lg font-medium\"\n >\n {button.text}\n </a>\n ))}\n </div>\n </div>\n <div className=\"flex-1\">\n <div className=\"relative group\">\n <div className=\"absolute -inset-1 bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200\"></div>\n <img\n src={imageSrc}\n alt=\"Profile\"\n className=\"relative w-full max-w-md mx-auto rounded-lg shadow-xl transform hover:scale-[1.02] transition-transform duration-300 bg-white\"\n />\n </div>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default Home;\n\n","'use client';\n\nimport React from 'react';\nimport Link from 'next/link';\nimport { cn } from '@/utils';\n\nexport interface ExperimentCardProps {\n href: string;\n title: string;\n description: string;\n tags: string[];\n category: 'utility' | 'leisure';\n isCompleted?: boolean;\n updatedAt?: string;\n createdAt?: string;\n className?: string;\n}\n\nexport const ExperimentCard: React.FC<ExperimentCardProps> = ({ \n href, \n title, \n description, \n tags, \n category, \n isCompleted,\n updatedAt,\n createdAt,\n className\n}) => {\n // 格式化日期显示\n const formatDate = (dateString?: string) => {\n if (!dateString) return '';\n \n try {\n const date = new Date(dateString);\n return date.toLocaleDateString('zh-CN', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit'\n });\n } catch (e) {\n return dateString;\n }\n };\n \n return (\n <Link href={href} className={cn(\"block group\", className)}>\n <div className=\"w-full h-full bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 transform group-hover:-translate-y-1 border border-gray-100 hover:border-gray-200\">\n <div className=\"p-6\">\n <div className=\"flex items-start justify-between mb-4\">\n <h3 className=\"text-xl font-semibold text-gray-900 flex-1 pr-4 leading-tight\">\n {title}\n </h3>\n <div className=\"flex flex-col gap-2 flex-shrink-0\">\n <span className={cn(\n \"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm\",\n category === 'utility' \n ? 'bg-gradient-to-r from-green-50 to-green-100 text-green-700 border border-green-200' \n : 'bg-gradient-to-r from-purple-50 to-purple-100 text-purple-700 border border-purple-200'\n )}>\n {category === 'utility' ? '🔧 实用工具' : '🎮 休闲娱乐'}\n </span>\n <span className={cn(\n \"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm border\",\n isCompleted \n ? 'bg-gradient-to-r from-emerald-50 to-emerald-100 text-emerald-700 border border-emerald-200' \n : 'bg-gradient-to-r from-orange-50 to-orange-100 text-orange-700 border border-orange-200'\n )}>\n {isCompleted ? '✅ 已完成' : '🚧 进行中'}\n </span>\n </div>\n </div>\n <p className=\"text-gray-600 mb-4\">{description}</p>\n \n {/* 显示更新时间 */}\n {updatedAt && (\n <div className=\"flex items-center gap-1 mb-3 text-xs text-gray-500\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>更新于: {formatDate(updatedAt)}</span>\n {createdAt && createdAt !== updatedAt && (\n <span className=\"ml-2 text-gray-400\">创建于: {formatDate(createdAt)}</span>\n )}\n </div>\n )}\n \n <div className=\"flex flex-wrap gap-2\">\n {tags.map((tag) => (\n <span\n key={tag}\n className=\"px-3 py-1.5 text-xs font-medium bg-gradient-to-r from-gray-50 to-gray-100 text-gray-700 rounded-full border border-gray-200 shadow-sm hover:shadow-md transition-shadow duration-200\"\n >\n #{tag}\n </span>\n ))}\n </div>\n </div>\n </div>\n </Link>\n );\n};\n\nexport default ExperimentCard;\n\n","'use client';\n\nimport React, { useState } from 'react';\nimport { ExperimentCard } from './ExperimentCard';\nimport { cn } from '@/utils';\n\n// Project相关的类型定义\nexport interface Project {\n id: string;\n title: string;\n description: string;\n image: string;\n link?: string;\n tags: string[];\n}\n\nexport interface ProjectsConfig {\n projects: Project[];\n}\n\ninterface ProjectCarouselProps {\n projects: Project[];\n className?: string;\n}\n\nexport const ProjectCarousel: React.FC<ProjectCarouselProps> = ({ projects, className }) => {\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const nextSlide = () => {\n setCurrentIndex((prevIndex) =>\n prevIndex === projects.length - 1 ? 0 : prevIndex + 1\n );\n };\n\n const prevSlide = () => {\n setCurrentIndex((prevIndex) =>\n prevIndex === 0 ? projects.length - 1 : prevIndex - 1\n );\n };\n\n return (\n <section id=\"projects\" className={cn(\"py-16 bg-gray-50\", className)}>\n <div className=\"container mx-auto px-4\">\n <h2 className=\"text-3xl font-bold text-center mb-12 text-gray-900\">项目展示</h2>\n \n <div className=\"relative max-w-4xl mx-auto\">\n {/* 项目卡片 */}\n <div className=\"relative h-[400px] overflow-hidden rounded-lg shadow-xl\">\n {projects.map((project, index) => (\n <div\n key={project.id}\n className={cn(\n \"absolute w-full h-full transition-all duration-500 transform\",\n index === currentIndex\n ? \"translate-x-0 opacity-100\"\n : index < currentIndex\n ? \"-translate-x-full opacity-0\"\n : \"translate-x-full opacity-0\"\n )}\n >\n <ExperimentCard\n href={project.link || '#'}\n title={project.title}\n description={project.description}\n tags={project.tags}\n category=\"utility\"\n />\n </div>\n ))}\n </div>\n\n {/* 导航按钮 */}\n <button\n onClick={prevSlide}\n className=\"absolute left-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/80 hover:bg-white shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all z-[10]\"\n >\n <svg\n className=\"w-6 h-6 text-gray-600\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n\n <button\n onClick={nextSlide}\n className=\"absolute right-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/80 hover:bg-white shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all z-[10]\"\n >\n <svg\n className=\"w-6 h-6 text-gray-600\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </button>\n\n {/* 指示器 */}\n <div className=\"absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2 z-[10]\">\n {projects.map((_, index) => (\n <button\n key={index}\n onClick={() => setCurrentIndex(index)}\n className={cn(\n \"w-2 h-2 rounded-full transition-all duration-300\",\n index === currentIndex ? \"bg-blue-500 w-4\" : \"bg-gray-300\"\n )}\n />\n ))}\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default ProjectCarousel;\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/portfolio/About.tsx","../src/portfolio/Contact.tsx","../src/portfolio/Home.tsx","../src/portfolio/ExperimentCard.tsx","../src/portfolio/ProjectCarousel.tsx"],"names":["React","Timeline","CollisionBalls","useState","clsx","useEffect","cn","Link"],"mappings":"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","file":"chunk-NCOXT7SK.js","sourcesContent":["'use client';\n\nimport React from \"react\";\n\nimport { CollisionBalls, Timeline } from \"@/components\";\nimport type { TimelineConfig, CollisionBallsConfig } from \"@/components\";\n\ninterface AboutProps {\n timelineConfig: TimelineConfig;\n collisionBallsConfig: CollisionBallsConfig;\n}\n\nconst About: React.FC<AboutProps> = ({\n timelineConfig,\n collisionBallsConfig,\n}) => {\n return (\n <section id=\"about\" className=\"py-16 bg-white\">\n <div className=\"container mx-auto px-4\">\n <h2 className=\"text-3xl font-bold text-center mb-12\">关于我</h2>\n <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-12\">\n <div className=\"bg-white rounded-lg shadow-lg p-6\">\n <h3 className=\"text-2xl font-semibold mb-6\">个人经历</h3>\n <Timeline items={timelineConfig.items} />\n </div>\n <div className=\"bg-white rounded-lg shadow-lg p-6\">\n <h3 className=\"text-2xl font-semibold mb-6\">技能展示</h3>\n <div style={{ height: '400px', position: 'relative' }}>\n <CollisionBalls collisionBallsConfig={collisionBallsConfig} />\n </div>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default About;\n","'use client';\n\nimport React, { useState } from 'react';\nimport { clsx } from 'clsx';\n\ninterface FormData {\n name: string;\n email: string;\n message: string;\n}\n\nconst Contact: React.FC = () => {\n const [formData, setFormData] = useState<FormData>({\n name: '',\n email: '',\n message: ''\n });\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle');\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n const { name, value } = e.target;\n setFormData(prev => ({\n ...prev,\n [name]: value\n }));\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n setSubmitStatus('idle');\n\n try {\n // 这里添加你的表单提交逻辑\n await new Promise(resolve => setTimeout(resolve, 1000)); // 模拟API调用\n setSubmitStatus('success');\n setFormData({ name: '', email: '', message: '' });\n } catch (error) {\n setSubmitStatus('error');\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <section id=\"contact\" className=\"py-16 bg-gray-50\">\n <div className=\"max-w-4xl mx-auto px-4 sm:px-6 lg:px-8\">\n <div className=\"text-center mb-12\">\n <h2 className=\"text-3xl font-bold text-gray-900 sm:text-4xl\">\n 联系我\n </h2>\n <p className=\"mt-4 text-lg text-gray-600\">\n 有任何问题或建议?请随时联系我\n </p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-xl p-6 sm:p-8\">\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <div>\n <label htmlFor=\"name\" className=\"block text-sm font-medium text-gray-700\">\n 姓名\n </label>\n <input\n type=\"text\"\n name=\"name\"\n id=\"name\"\n value={formData.name}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的姓名\"\n />\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700\">\n 邮箱\n </label>\n <input\n type=\"email\"\n name=\"email\"\n id=\"email\"\n value={formData.email}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的邮箱\"\n />\n </div>\n\n <div>\n <label htmlFor=\"message\" className=\"block text-sm font-medium text-gray-700\">\n 消息\n </label>\n <textarea\n name=\"message\"\n id=\"message\"\n rows={4}\n value={formData.message}\n onChange={handleChange}\n required\n className=\"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 sm:text-sm\"\n placeholder=\"请输入您的消息\"\n />\n </div>\n\n <div className=\"flex items-center justify-end\">\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className={clsx('inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white', isSubmitting \n ? 'bg-blue-400 cursor-not-allowed' \n : 'bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500')}\n >\n {isSubmitting ? '发送中...' : '发送消息'}\n </button>\n </div>\n\n {submitStatus === 'success' && (\n <div className=\"rounded-md bg-green-50 p-4\">\n <div className=\"flex\">\n <div className=\"flex-shrink-0\">\n <svg className=\"h-5 w-5 text-green-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n <div className=\"ml-3\">\n <p className=\"text-sm font-medium text-green-800\">\n 消息已成功发送!\n </p>\n </div>\n </div>\n </div>\n )}\n\n {submitStatus === 'error' && (\n <div className=\"rounded-md bg-red-50 p-4\">\n <div className=\"flex\">\n <div className=\"flex-shrink-0\">\n <svg className=\"h-5 w-5 text-red-400\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clipRule=\"evenodd\" />\n </svg>\n </div>\n <div className=\"ml-3\">\n <p className=\"text-sm font-medium text-red-800\">\n 发送失败,请稍后重试\n </p>\n </div>\n </div>\n </div>\n )}\n </form>\n </div>\n\n {/* 联系方式 */}\n <div className=\"mt-12 grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">邮箱</h3>\n <p className=\"mt-2 text-gray-600\">your.email@example.com</p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">电话</h3>\n <p className=\"mt-2 text-gray-600\">+86 123 4567 8900</p>\n </div>\n\n <div className=\"bg-white rounded-lg shadow-lg p-6 text-center\">\n <div className=\"text-blue-600 mb-4\">\n <svg className=\"h-8 w-8 mx-auto\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\" />\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\" />\n </svg>\n </div>\n <h3 className=\"text-lg font-medium text-gray-900\">地址</h3>\n <p className=\"mt-2 text-gray-600\">中国,北京</p>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default Contact; ","'use client';\n\nimport React, { useEffect, useState } from \"react\";\nimport { cn } from '@/utils';\n\nexport interface HomeConfig {\n title: string;\n subtitle: string;\n buttons: Array<{\n text: string;\n link: string;\n }>;\n imageSrc: string;\n}\n\ninterface HomeProps {\n homeConfig: HomeConfig;\n className?: string;\n}\n\nexport const Home: React.FC<HomeProps> = ({ homeConfig, className }) => {\n const { title, subtitle, buttons, imageSrc } = homeConfig;\n const [displayText, setDisplayText] = useState(\"\");\n const [currentIndex, setCurrentIndex] = useState(0);\n\n useEffect(() => {\n if (currentIndex < title.length) {\n const timer = setTimeout(() => {\n setDisplayText((prev) => prev + title[currentIndex]);\n setCurrentIndex((prev) => prev + 1);\n }, 150);\n\n return () => clearTimeout(timer);\n }\n return () => {\n setDisplayText(\"\");\n setCurrentIndex(0);\n };\n }, [currentIndex, title]);\n\n return (\n <section \n id=\"home\" \n className={cn(\"min-h-screen flex items-center justify-center py-16 bg-gradient-to-b from-white to-gray-50\", className)}\n >\n <div className=\"container mx-auto px-4\">\n <div className=\"flex flex-col md:flex-row items-center gap-12\">\n <div className=\"flex-1 text-center md:text-left\">\n <h1 className=\"text-4xl md:text-6xl font-bold mb-6 text-gray-900\">\n <span className=\"inline-block\">{displayText}</span>\n <span className=\"animate-pulse ml-1 text-blue-500\">|</span>\n </h1>\n <p className=\"text-xl md:text-2xl text-gray-600 mb-8\">{subtitle}</p>\n <div className=\"flex flex-wrap gap-4 justify-center md:justify-start\">\n {buttons.map((button) => (\n <a\n key={button.link}\n href={button.link}\n className=\"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-300 shadow-md hover:shadow-lg font-medium\"\n >\n {button.text}\n </a>\n ))}\n </div>\n </div>\n <div className=\"flex-1\">\n <div className=\"relative group\">\n <div className=\"absolute -inset-1 bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200\"></div>\n <img\n src={imageSrc}\n alt=\"Profile\"\n className=\"relative w-full max-w-md mx-auto rounded-lg shadow-xl transform hover:scale-[1.02] transition-transform duration-300 bg-white\"\n />\n </div>\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default Home;\n\n","'use client';\n\nimport React from 'react';\nimport Link from 'next/link';\nimport { cn } from '@/utils';\n\nexport interface ExperimentCardProps {\n href: string;\n title: string;\n description: string;\n tags: string[];\n category: 'utility' | 'leisure';\n isCompleted?: boolean;\n updatedAt?: string;\n createdAt?: string;\n className?: string;\n}\n\nexport const ExperimentCard: React.FC<ExperimentCardProps> = ({ \n href, \n title, \n description, \n tags, \n category, \n isCompleted,\n updatedAt,\n createdAt,\n className\n}) => {\n // 格式化日期显示\n const formatDate = (dateString?: string) => {\n if (!dateString) return '';\n \n try {\n const date = new Date(dateString);\n return date.toLocaleDateString('zh-CN', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit'\n });\n } catch (e) {\n return dateString;\n }\n };\n \n return (\n <Link href={href} className={cn(\"block group\", className)}>\n <div className=\"w-full h-full bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 transform group-hover:-translate-y-1 border border-gray-100 hover:border-gray-200\">\n <div className=\"p-6\">\n <div className=\"flex items-start justify-between mb-4\">\n <h3 className=\"text-xl font-semibold text-gray-900 flex-1 pr-4 leading-tight\">\n {title}\n </h3>\n <div className=\"flex flex-col gap-2 flex-shrink-0\">\n <span className={cn(\n \"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm\",\n category === 'utility' \n ? 'bg-gradient-to-r from-green-50 to-green-100 text-green-700 border border-green-200' \n : 'bg-gradient-to-r from-purple-50 to-purple-100 text-purple-700 border border-purple-200'\n )}>\n {category === 'utility' ? '🔧 实用工具' : '🎮 休闲娱乐'}\n </span>\n <span className={cn(\n \"px-3 py-1.5 text-xs font-medium rounded-full shadow-sm border\",\n isCompleted \n ? 'bg-gradient-to-r from-emerald-50 to-emerald-100 text-emerald-700 border border-emerald-200' \n : 'bg-gradient-to-r from-orange-50 to-orange-100 text-orange-700 border border-orange-200'\n )}>\n {isCompleted ? '✅ 已完成' : '🚧 进行中'}\n </span>\n </div>\n </div>\n <p className=\"text-gray-600 mb-4\">{description}</p>\n \n {/* 显示更新时间 */}\n {updatedAt && (\n <div className=\"flex items-center gap-1 mb-3 text-xs text-gray-500\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <span>更新于: {formatDate(updatedAt)}</span>\n {createdAt && createdAt !== updatedAt && (\n <span className=\"ml-2 text-gray-400\">创建于: {formatDate(createdAt)}</span>\n )}\n </div>\n )}\n \n <div className=\"flex flex-wrap gap-2\">\n {tags.map((tag) => (\n <span\n key={tag}\n className=\"px-3 py-1.5 text-xs font-medium bg-gradient-to-r from-gray-50 to-gray-100 text-gray-700 rounded-full border border-gray-200 shadow-sm hover:shadow-md transition-shadow duration-200\"\n >\n #{tag}\n </span>\n ))}\n </div>\n </div>\n </div>\n </Link>\n );\n};\n\nexport default ExperimentCard;\n\n","'use client';\n\nimport React, { useState } from 'react';\nimport { ExperimentCard } from './ExperimentCard';\nimport { cn } from '@/utils';\n\n// Project相关的类型定义\nexport interface Project {\n id: string;\n title: string;\n description: string;\n image: string;\n link?: string;\n tags: string[];\n}\n\nexport interface ProjectsConfig {\n projects: Project[];\n}\n\ninterface ProjectCarouselProps {\n projects: Project[];\n className?: string;\n}\n\nexport const ProjectCarousel: React.FC<ProjectCarouselProps> = ({ projects, className }) => {\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const nextSlide = () => {\n setCurrentIndex((prevIndex) =>\n prevIndex === projects.length - 1 ? 0 : prevIndex + 1\n );\n };\n\n const prevSlide = () => {\n setCurrentIndex((prevIndex) =>\n prevIndex === 0 ? projects.length - 1 : prevIndex - 1\n );\n };\n\n return (\n <section id=\"projects\" className={cn(\"py-16 bg-gray-50\", className)}>\n <div className=\"container mx-auto px-4\">\n <h2 className=\"text-3xl font-bold text-center mb-12 text-gray-900\">项目展示</h2>\n \n <div className=\"relative max-w-4xl mx-auto\">\n {/* 项目卡片 */}\n <div className=\"relative h-[400px] overflow-hidden rounded-lg shadow-xl\">\n {projects.map((project, index) => (\n <div\n key={project.id}\n className={cn(\n \"absolute w-full h-full transition-all duration-500 transform\",\n index === currentIndex\n ? \"translate-x-0 opacity-100\"\n : index < currentIndex\n ? \"-translate-x-full opacity-0\"\n : \"translate-x-full opacity-0\"\n )}\n >\n <ExperimentCard\n href={project.link || '#'}\n title={project.title}\n description={project.description}\n tags={project.tags}\n category=\"utility\"\n />\n </div>\n ))}\n </div>\n\n {/* 导航按钮 */}\n <button\n onClick={prevSlide}\n className=\"absolute left-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/80 hover:bg-white shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all z-[10]\"\n >\n <svg\n className=\"w-6 h-6 text-gray-600\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n\n <button\n onClick={nextSlide}\n className=\"absolute right-4 top-1/2 -translate-y-1/2 p-2 rounded-full bg-white/80 hover:bg-white shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all z-[10]\"\n >\n <svg\n className=\"w-6 h-6 text-gray-600\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 5l7 7-7 7\"\n />\n </svg>\n </button>\n\n {/* 指示器 */}\n <div className=\"absolute bottom-4 left-1/2 transform -translate-x-1/2 flex space-x-2 z-[10]\">\n {projects.map((_, index) => (\n <button\n key={index}\n onClick={() => setCurrentIndex(index)}\n className={cn(\n \"w-2 h-2 rounded-full transition-all duration-300\",\n index === currentIndex ? \"bg-blue-500 w-4\" : \"bg-gray-300\"\n )}\n />\n ))}\n </div>\n </div>\n </div>\n </section>\n );\n};\n\nexport default ProjectCarousel;\n\n"]}
|