@flecblog/core-nuxt 0.1.0

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.
Files changed (70) hide show
  1. package/app.vue +172 -0
  2. package/assets/css/base.scss +96 -0
  3. package/composables/api/article.ts +25 -0
  4. package/composables/api/category.ts +19 -0
  5. package/composables/api/comment.ts +25 -0
  6. package/composables/api/createApi.ts +242 -0
  7. package/composables/api/feedback.ts +14 -0
  8. package/composables/api/friend.ts +14 -0
  9. package/composables/api/moment.ts +10 -0
  10. package/composables/api/music.ts +39 -0
  11. package/composables/api/notification.ts +19 -0
  12. package/composables/api/stats.ts +14 -0
  13. package/composables/api/subscribe.ts +13 -0
  14. package/composables/api/sysconfig.ts +9 -0
  15. package/composables/api/tag.ts +19 -0
  16. package/composables/api/theme.ts +9 -0
  17. package/composables/api/upload.ts +13 -0
  18. package/composables/api/user.ts +77 -0
  19. package/composables/useArticle.ts +227 -0
  20. package/composables/useAuth.ts +180 -0
  21. package/composables/useComment.ts +143 -0
  22. package/composables/useDarkMode.ts +29 -0
  23. package/composables/useEmoji.ts +39 -0
  24. package/composables/useFeedback.ts +38 -0
  25. package/composables/useFriendList.ts +100 -0
  26. package/composables/useMermaid.ts +30 -0
  27. package/composables/useMoment.ts +86 -0
  28. package/composables/useMusic.ts +37 -0
  29. package/composables/useSearchState.ts +90 -0
  30. package/composables/useStores.ts +557 -0
  31. package/composables/useSubscribe.ts +13 -0
  32. package/composables/useTheme.ts +61 -0
  33. package/composables/useUser.ts +202 -0
  34. package/layouts/default.vue +1 -0
  35. package/nuxt.config.ts +170 -0
  36. package/package.json +58 -0
  37. package/pages/index.vue +1 -0
  38. package/plugins/console-banner.client.ts +11 -0
  39. package/plugins/custom-code.ts +121 -0
  40. package/plugins/syncThemeMeta.ts +28 -0
  41. package/plugins/tracker.client.ts +107 -0
  42. package/server/plugins/sitemap.ts +170 -0
  43. package/server/routes/atom.xml.ts +21 -0
  44. package/server/routes/manifest.json.ts +45 -0
  45. package/server/routes/rss.xml.ts +21 -0
  46. package/types/article.ts +48 -0
  47. package/types/auth.ts +8 -0
  48. package/types/category.ts +12 -0
  49. package/types/comment.ts +72 -0
  50. package/types/emoji.ts +10 -0
  51. package/types/feedback.ts +31 -0
  52. package/types/friend.ts +63 -0
  53. package/types/markdown.ts +7 -0
  54. package/types/moment.ts +85 -0
  55. package/types/notification.ts +56 -0
  56. package/types/request.ts +30 -0
  57. package/types/stats.ts +38 -0
  58. package/types/sysconfig.ts +2 -0
  59. package/types/tag.ts +11 -0
  60. package/types/theme.ts +26 -0
  61. package/types/upload.ts +5 -0
  62. package/types/user.ts +106 -0
  63. package/utils/avatar.ts +21 -0
  64. package/utils/date.ts +136 -0
  65. package/utils/download.ts +11 -0
  66. package/utils/emoji.ts +90 -0
  67. package/utils/format.ts +42 -0
  68. package/utils/markdown.ts +1458 -0
  69. package/utils/scroll.ts +31 -0
  70. package/utils/upload.ts +57 -0
@@ -0,0 +1,31 @@
1
+ interface ScrollOptions {
2
+ behavior?: ScrollBehavior;
3
+ block?: ScrollLogicalPosition;
4
+ }
5
+
6
+ /**
7
+ * 平滑滚动到顶部
8
+ */
9
+ export function scrollToTop(): void {
10
+ if (!import.meta.client) return;
11
+ window.scrollTo({ top: 0, behavior: 'smooth' });
12
+ }
13
+
14
+ /**
15
+ * 平滑滚动到指定元素
16
+ * @param selector CSS 选择器
17
+ * @param options 滚动选项
18
+ */
19
+ export function scrollToElement(selector: string, options?: ScrollOptions): void {
20
+ if (!import.meta.client) return;
21
+
22
+ const { behavior = 'smooth', block = 'center' } = options || {};
23
+ // # 开头用 getElementById 支持特殊字符,否则用 querySelector
24
+ const element = selector.startsWith('#')
25
+ ? document.getElementById(selector.slice(1))
26
+ : document.querySelector(selector);
27
+
28
+ if (element) {
29
+ element.scrollIntoView({ behavior, block });
30
+ }
31
+ }
@@ -0,0 +1,57 @@
1
+ import { uploadFileApi } from '@/composables/api/upload';
2
+ import type { UploadResponse } from '@@/types/upload';
3
+
4
+ export function getMaxFileSizeMB(): number {
5
+ try {
6
+ const { uploadConfig } = useSysConfig();
7
+ const configValue = uploadConfig.value['max_file_size'] || '5';
8
+ const parsed = parseInt(configValue, 10);
9
+ return isNaN(parsed) || parsed <= 0 ? 5 : parsed;
10
+ } catch {
11
+ return 5;
12
+ }
13
+ }
14
+
15
+ export function validateFile(file: File, allowedTypes?: string[]): string | null {
16
+ if (allowedTypes && !allowedTypes.includes(file.type)) {
17
+ return `不支持的文件类型`;
18
+ }
19
+
20
+ const maxSizeMB = getMaxFileSizeMB();
21
+ const maxSize = maxSizeMB * 1024 * 1024;
22
+ if (file.size > maxSize) {
23
+ return `文件大小不能超过 ${maxSizeMB}MB`;
24
+ }
25
+
26
+ return null;
27
+ }
28
+
29
+ export async function uploadFiles(
30
+ files: File[],
31
+ type: string,
32
+ allowedTypes?: string[]
33
+ ): Promise<string[]> {
34
+ if (files.length === 0) return [];
35
+ const results = await Promise.all(files.map(file => uploadFile(file, type, allowedTypes)));
36
+ return results.map(r => r.file_url);
37
+ }
38
+
39
+ export async function uploadFile(
40
+ file: File,
41
+ type: string,
42
+ allowedTypes?: string[]
43
+ ): Promise<UploadResponse> {
44
+ const validationError = validateFile(file, allowedTypes);
45
+ if (validationError) {
46
+ throw new Error(validationError);
47
+ }
48
+
49
+ const formData = new FormData();
50
+ formData.append('file', file);
51
+ formData.append('type', type);
52
+
53
+ return uploadFileApi(formData).catch((error: unknown) => {
54
+ const err = error as { data?: { message?: string }; message?: string };
55
+ throw new Error(err?.data?.message || err?.message || '文件上传失败');
56
+ });
57
+ }