@bytechain.cn/colamd 1.5.0 → 1.5.1-beta.2

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 (193) hide show
  1. package/.trae/specs/optimize-theme-loading/checklist.md +20 -0
  2. package/.trae/specs/optimize-theme-loading/spec.md +103 -0
  3. package/.trae/specs/optimize-theme-loading/tasks.md +40 -0
  4. package/CHANGELOG.md +323 -0
  5. package/CLAUDE.md +56 -0
  6. package/README.md +422 -26
  7. package/README_CN.md +480 -28
  8. package/android/app/build/.npmkeep +0 -0
  9. package/android/app/build.gradle +76 -0
  10. package/android/app/capacitor.build.gradle +24 -0
  11. package/android/app/proguard-rules.pro +21 -0
  12. package/android/app/release.keystore +0 -0
  13. package/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +26 -0
  14. package/android/app/src/main/AndroidManifest.xml +64 -0
  15. package/android/app/src/main/java/cn/bytechain/colamd/MainActivity.java +180 -0
  16. package/android/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  17. package/android/app/src/main/res/drawable/splash.png +0 -0
  18. package/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
  19. package/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
  20. package/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
  21. package/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
  22. package/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
  23. package/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
  24. package/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
  25. package/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
  26. package/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
  27. package/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
  28. package/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +34 -0
  29. package/android/app/src/main/res/layout/activity_main.xml +12 -0
  30. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  31. package/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  32. package/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  33. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  34. package/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  35. package/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  36. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  37. package/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  38. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  39. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  40. package/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  41. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  42. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  43. package/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  44. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  45. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  46. package/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  47. package/android/app/src/main/res/values/ic_launcher_background.xml +4 -0
  48. package/android/app/src/main/res/values/strings.xml +7 -0
  49. package/android/app/src/main/res/values/styles.xml +22 -0
  50. package/android/app/src/main/res/xml/file_paths.xml +5 -0
  51. package/android/app/src/main/res/xml/network_security_config.xml +8 -0
  52. package/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +18 -0
  53. package/android/build.gradle +29 -0
  54. package/android/capacitor.settings.gradle +21 -0
  55. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  56. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  57. package/android/gradle.properties +22 -0
  58. package/android/gradlew +248 -0
  59. package/android/gradlew.bat +92 -0
  60. package/android/settings.gradle +5 -0
  61. package/android/variables.gradle +16 -0
  62. package/bytechain.cn-colamd-1.5.1-beta.2.tgz +0 -0
  63. package/capacitor.config.js +29 -0
  64. package/capacitor.config.ts +30 -0
  65. package/demo.md +191 -484
  66. package/dist/main/index.js +77 -46
  67. package/dist/renderer/assets/{arc-tTbbM8LO.js → arc-CPdeInCG.js} +1 -1
  68. package/dist/renderer/assets/{architectureDiagram-3BPJPVTR-CEgYow6c.js → architectureDiagram-3BPJPVTR-BAbnaR9G.js} +4 -3
  69. package/dist/renderer/assets/{blockDiagram-GPEHLZMM-LHyVtPwW.js → blockDiagram-GPEHLZMM-CYSWjnJg.js} +5 -4
  70. package/dist/renderer/assets/{c4Diagram-AAUBKEIU-C1P1eJrf.js → c4Diagram-AAUBKEIU-Rb1tstnr.js} +3 -2
  71. package/dist/renderer/assets/{channel-upve91Tq.js → channel-DpG2A6fE.js} +1 -1
  72. package/dist/renderer/assets/{chunk-2J33WTMH-lag2vhq9.js → chunk-2J33WTMH-DFc0Jxy_.js} +1 -1
  73. package/dist/renderer/assets/{chunk-4BX2VUAB-BXJ8Ggh-.js → chunk-4BX2VUAB-BhRxDTNn.js} +1 -1
  74. package/dist/renderer/assets/{chunk-55IACEB6-CiBpxRa1.js → chunk-55IACEB6-DEgMVBk8.js} +1 -1
  75. package/dist/renderer/assets/{chunk-727SXJPM-ODeKQFXC.js → chunk-727SXJPM-bjBIfiz8.js} +5 -5
  76. package/dist/renderer/assets/{chunk-AQP2D5EJ-BK7xJolB.js → chunk-AQP2D5EJ-DwQMzTzD.js} +3 -3
  77. package/dist/renderer/assets/{chunk-FMBD7UC4-BxpCZPtz.js → chunk-FMBD7UC4-CkphwJzs.js} +1 -1
  78. package/dist/renderer/assets/{chunk-ND2GUHAM-CqqaU9Ue.js → chunk-ND2GUHAM-oU09z4y4.js} +1 -1
  79. package/dist/renderer/assets/{chunk-QZHKN3VN-Biq_K124.js → chunk-QZHKN3VN-rCbVuPBn.js} +1 -1
  80. package/dist/renderer/assets/{classDiagram-v2-Q7XG4LA2-Cq95X99o.js → classDiagram-4FO5ZUOK-DGS2faoM.js} +7 -6
  81. package/dist/renderer/assets/{classDiagram-4FO5ZUOK-Cq95X99o.js → classDiagram-v2-Q7XG4LA2-DGS2faoM.js} +7 -6
  82. package/dist/renderer/assets/{cose-bilkent-S5V4N54A-XasiD0bu.js → cose-bilkent-S5V4N54A-iqY6-EwA.js} +2 -1
  83. package/dist/renderer/assets/{dagre-BM42HDAG-Nq84Gfx4.js → dagre-BM42HDAG-5t3X5sDa.js} +4 -3
  84. package/dist/renderer/assets/{diagram-2AECGRRQ-DwuB1GWt.js → diagram-2AECGRRQ-DzHiYDPh.js} +4 -3
  85. package/dist/renderer/assets/{diagram-5GNKFQAL-C2tgeI1h.js → diagram-5GNKFQAL-BiNv6Keq.js} +5 -4
  86. package/dist/renderer/assets/{diagram-KO2AKTUF-D5KzjNBc.js → diagram-KO2AKTUF-ClzeDG6f.js} +4 -3
  87. package/dist/renderer/assets/{diagram-LMA3HP47-C12xHS1c.js → diagram-LMA3HP47-CGkw7wII.js} +4 -3
  88. package/dist/renderer/assets/{diagram-OG6HWLK6-CnxI9oEa.js → diagram-OG6HWLK6-Dl-Hyk1_.js} +5 -4
  89. package/dist/renderer/assets/{erDiagram-TEJ5UH35-D_uPaKwn.js → erDiagram-TEJ5UH35-BxUN79Qb.js} +5 -4
  90. package/dist/renderer/assets/{flowDiagram-I6XJVG4X-B6q_1-tE.js → flowDiagram-I6XJVG4X-CzFk-KNI.js} +7 -6
  91. package/dist/renderer/assets/{ganttDiagram-6RSMTGT7-CFo7ifF9.js → ganttDiagram-6RSMTGT7-C2xl6Igx.js} +3 -2
  92. package/dist/renderer/assets/{gitGraphDiagram-PVQCEYII-WSexHTnq.js → gitGraphDiagram-PVQCEYII-_fn7XCa7.js} +5 -4
  93. package/dist/renderer/assets/{graph-DyX_9f6d.js → graph-CDoHYrHm.js} +1 -1
  94. package/dist/renderer/assets/index-B4uDgADr.js +530 -0
  95. package/dist/renderer/assets/index-CBcVpA3d.js +30 -0
  96. package/dist/renderer/assets/index-CGj1spkU.js +27 -0
  97. package/dist/renderer/assets/{index-dyHEFYvY.css → index-CeFpoCKV.css} +443 -400
  98. package/dist/renderer/assets/index-D4CPFkph.js +9 -0
  99. package/dist/renderer/assets/{index-DW7LS8C1.js → index-DAlXyxzt.js} +1183 -346
  100. package/dist/renderer/assets/index-DxOzbfR-.js +110 -0
  101. package/dist/renderer/assets/index-Y89U1ptl.js +9 -0
  102. package/dist/renderer/assets/{infoDiagram-5YYISTIA-DaeJdLRq.js → infoDiagram-5YYISTIA-DL6XIxLz.js} +3 -2
  103. package/dist/renderer/assets/{ishikawaDiagram-YF4QCWOH-DDCZc35f.js → ishikawaDiagram-YF4QCWOH-BUZLjRo-.js} +2 -1
  104. package/dist/renderer/assets/{journeyDiagram-JHISSGLW-BEdmpAgl.js → journeyDiagram-JHISSGLW-C4rH_mQM.js} +5 -4
  105. package/dist/renderer/assets/{kanban-definition-UN3LZRKU-BEFtQcFb.js → kanban-definition-UN3LZRKU-DRbrBcWV.js} +3 -2
  106. package/dist/renderer/assets/{layout-CAJgQHdw.js → layout-DZl4n4qu.js} +2 -2
  107. package/dist/renderer/assets/{linear-B2ggJ8Am.js → linear-B0Krxg21.js} +1 -1
  108. package/dist/renderer/assets/{mindmap-definition-RKZ34NQL-DSxVgHB5.js → mindmap-definition-RKZ34NQL-DdmPsWrn.js} +4 -3
  109. package/dist/renderer/assets/{pieDiagram-4H26LBE5-CwYoJBuL.js → pieDiagram-4H26LBE5-BPZLqwG0.js} +5 -4
  110. package/dist/renderer/assets/preload-helper-tXtZnHb0.js +88 -0
  111. package/dist/renderer/assets/{quadrantDiagram-W4KKPZXB-CST9Fvg9.js → quadrantDiagram-W4KKPZXB-Dr-oWRk9.js} +3 -2
  112. package/dist/renderer/assets/{requirementDiagram-4Y6WPE33-DtrH52jS.js → requirementDiagram-4Y6WPE33-B6QZd0lo.js} +4 -3
  113. package/dist/renderer/assets/{sankeyDiagram-5OEKKPKP-ca1tPzJ_.js → sankeyDiagram-5OEKKPKP-Cyl9ojEt.js} +2 -1
  114. package/dist/renderer/assets/{sequenceDiagram-3UESZ5HK-Dfp1EJZ7.js → sequenceDiagram-3UESZ5HK-D48Yr9T6.js} +4 -3
  115. package/dist/renderer/assets/{stateDiagram-AJRCARHV-Bha2QoNB.js → stateDiagram-AJRCARHV-qyb8ETsa.js} +7 -6
  116. package/dist/renderer/assets/{stateDiagram-v2-BHNVJYJU-DWgFUYu1.js → stateDiagram-v2-BHNVJYJU-DmDOyyrJ.js} +5 -4
  117. package/dist/renderer/assets/{timeline-definition-PNZ67QCA-C3h_-OTj.js → timeline-definition-PNZ67QCA-C-KQxTi1.js} +3 -2
  118. package/dist/renderer/assets/{vennDiagram-CIIHVFJN-DFzjSrZi.js → vennDiagram-CIIHVFJN-BdaZlnH-.js} +2 -1
  119. package/dist/renderer/assets/{wardley-L42UT6IY-Cx-VbqoS.js → wardley-L42UT6IY-b-_GPpqL.js} +1 -1
  120. package/dist/renderer/assets/{wardleyDiagram-YWT4CUSO-S2D9XqX6.js → wardleyDiagram-YWT4CUSO-B2hBE-EE.js} +4 -3
  121. package/dist/renderer/assets/web-BKE0SH0E.js +36 -0
  122. package/dist/renderer/assets/web-CBsFp24u.js +564 -0
  123. package/dist/renderer/assets/web-Dc8YgoHP.js +24 -0
  124. package/dist/renderer/assets/web-TfDzToU7.js +58 -0
  125. package/dist/renderer/assets/{xychartDiagram-2RQKCTM6-Cfxigbts.js → xychartDiagram-2RQKCTM6-CSvswDTY.js} +3 -2
  126. package/dist/renderer/index.html +62 -3
  127. package/docs/academic-demo.md +566 -0
  128. package/docs/demo.html +748 -0
  129. package/docs/demo.md +546 -0
  130. package/docs/demo.pdf +0 -0
  131. package/docs/theme-paradigm.md +658 -0
  132. package/electron-builder.yml +7 -0
  133. package/electron.vite.config.js +31 -0
  134. package/electron.vite.config.ts +1 -1
  135. package/ios/App/App/AppDelegate.swift +49 -0
  136. package/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png +0 -0
  137. package/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
  138. package/ios/App/App/Assets.xcassets/Contents.json +6 -0
  139. package/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +23 -0
  140. package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
  141. package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
  142. package/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
  143. package/ios/App/App/Base.lproj/LaunchScreen.storyboard +32 -0
  144. package/ios/App/App/Base.lproj/Main.storyboard +19 -0
  145. package/ios/App/App/Info.plist +49 -0
  146. package/ios/App/App.xcodeproj/project.pbxproj +408 -0
  147. package/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  148. package/ios/App/Podfile +28 -0
  149. package/package.json +23 -3
  150. package/resources/templates/slides/template-forest-ink.html +540 -0
  151. package/scripts/generate-icons.js +102 -0
  152. package/src/main/index.ts +87 -63
  153. package/src/preload/index.d.ts +51 -0
  154. package/src/preload/index.js +70 -0
  155. package/src/renderer/capacitor-api.ts +713 -0
  156. package/src/renderer/editor/editor.ts +87 -4
  157. package/src/renderer/editor/plugins/index.ts +24 -32
  158. package/src/renderer/editor/plugins/math-plugin.ts +1 -1
  159. package/src/renderer/editor/plugins/mermaid-plugin-custom.css +13 -398
  160. package/src/renderer/editor/plugins/mermaid-plugin.ts +62 -71
  161. package/src/renderer/editor/plugins/themes/base/dark.css +23 -0
  162. package/src/renderer/editor/plugins/themes/base/elegant.css +32 -0
  163. package/src/renderer/editor/plugins/themes/base/light.css +20 -0
  164. package/src/renderer/editor/plugins/themes/base/newsprint.css +27 -0
  165. package/src/renderer/editor/plugins/themes/components/mermaid/academic.css +43 -0
  166. package/src/renderer/editor/plugins/themes/components/mermaid/dark.css +20 -0
  167. package/src/renderer/editor/plugins/themes/components/mermaid/elegant.css +24 -0
  168. package/src/renderer/editor/plugins/themes/components/mermaid/light.css +21 -0
  169. package/src/renderer/editor/plugins/themes/components/mermaid/newsprint.css +26 -0
  170. package/src/renderer/editor/plugins/themes/components/mermaid/variables.css +592 -0
  171. package/src/renderer/editor/plugins/themes/foundation.css +143 -0
  172. package/src/renderer/editor/plugins/themes/theme-manager.ts +92 -0
  173. package/src/renderer/env.d.ts +4 -1
  174. package/src/renderer/index.html +59 -1
  175. package/src/renderer/main.ts +432 -57
  176. package/src/renderer/mobile.css +429 -0
  177. package/themes/README.md +3 -0
  178. package/themes/academic-paper.css +1321 -0
  179. package/themes/elegant.css +14 -7
  180. package/themes/forest-ink.css +664 -0
  181. package/themes/pixso-design.css +1261 -0
  182. package/themes/swiss-design.css +596 -0
  183. package/themes/template.css +498 -0
  184. package/tsconfig.main.json +1 -0
  185. package/tsconfig.main.tsbuildinfo +1 -0
  186. package/tsconfig.preload.json +1 -0
  187. package/tsconfig.preload.tsbuildinfo +1 -0
  188. package/tsconfig.renderer.json +1 -0
  189. package/tsconfig.renderer.tsbuildinfo +1 -0
  190. package/tsconfig.tsbuildinfo +1 -0
  191. package/.trae/documents/fix-mermaid-colors-and-sankey.md +0 -50
  192. package/src/renderer/themes/theme-manager.ts +0 -40
  193. /package/src/renderer/{themes → editor/plugins/themes}/base.css +0 -0
@@ -0,0 +1,28 @@
1
+ require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'
2
+
3
+ platform :ios, '13.0'
4
+ use_frameworks!
5
+
6
+ # workaround to avoid Xcode caching of Pods that requires
7
+ # Product -> Clean Build Folder after new Cordova plugins installed
8
+ # Requires CocoaPods 1.6 or newer
9
+ install! 'cocoapods', :disable_input_output_paths => true
10
+
11
+ def capacitor_pods
12
+ pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
13
+ pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
14
+ pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
15
+ pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
16
+ pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
17
+ pod 'CapacitorShare', :path => '../../node_modules/@capacitor/share'
18
+ pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
19
+ end
20
+
21
+ target 'App' do
22
+ capacitor_pods
23
+ # Add your Pods here
24
+ end
25
+
26
+ post_install do |installer|
27
+ assertDeploymentTarget(installer)
28
+ end
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@bytechain.cn/colamd",
3
- "version": "1.5.0",
3
+ "version": "1.5.1-beta.2",
4
4
  "description": "The Agent Native Markdown Editor — Extended with Math & Mermaid Plugin System",
5
5
  "main": "dist/main/index.js",
6
6
  "author": {
7
7
  "name": "byteuser1977",
8
- "email": ""
8
+ "email": "byteuser@qq.com"
9
9
  },
10
10
  "license": "MIT",
11
11
  "homepage": "https://github.com/byteuser1977/ColaMD-extend",
@@ -20,7 +20,16 @@
20
20
  "dist": "electron-vite build && electron-builder",
21
21
  "dist:mac": "electron-vite build && electron-builder --mac",
22
22
  "dist:win": "electron-vite build && electron-builder --win",
23
- "dist:linux": "electron-vite build && electron-builder --linux"
23
+ "dist:linux": "electron-vite build && electron-builder --linux",
24
+ "cap:sync": "npx cap sync",
25
+ "cap:open:android": "npx cap open android",
26
+ "cap:open:ios": "npx cap open ios",
27
+ "cap:run:android": "npm run build && npx cap sync android && JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home npx cap run android",
28
+ "cap:run:ios": "npm run build && npx cap sync ios && npx cap run ios",
29
+ "dist:android": "npm run build && npx cap sync android && cd android && JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew assembleRelease && cd .. && mkdir -p release && cp android/app/build/outputs/apk/release/app-release.apk release/colamd-$(node -p \"require('./package.json').version\")-android.apk",
30
+ "cap:build:android": "npm run build && npx cap sync android && cd android && JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew assembleDebug",
31
+ "cap:build:android:release": "npm run build && npx cap sync android && cd android && JAVA_HOME=/opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home ./gradlew assembleRelease",
32
+ "cap:build:ios": "npm run build && npx cap sync ios"
24
33
  },
25
34
  "dependencies": {
26
35
  "@milkdown/kit": "^7.19.2",
@@ -30,10 +39,21 @@
30
39
  "remark-math": "^6.0.0"
31
40
  },
32
41
  "devDependencies": {
42
+ "@capacitor/android": "^6.2.1",
43
+ "@capacitor/app": "^6.0.3",
44
+ "@capacitor/cli": "^6.2.1",
45
+ "@capacitor/core": "^6.2.1",
46
+ "@capacitor/filesystem": "^6.0.4",
47
+ "@capacitor/haptics": "^6.0.3",
48
+ "@capacitor/ios": "^6.2.1",
49
+ "@capacitor/share": "^6.0.4",
50
+ "@capacitor/status-bar": "^6.0.3",
51
+ "@capawesome/capacitor-file-picker": "^6.2.0",
33
52
  "@types/katex": "^0.16.8",
34
53
  "electron": "^34.0.0",
35
54
  "electron-builder": "^26.0.0",
36
55
  "electron-vite": "^3.0.0",
56
+ "sharp": "^0.34.5",
37
57
  "typescript": "^5.7.0",
38
58
  "vite": "^6.0.0"
39
59
  }
@@ -0,0 +1,540 @@
1
+ <!--
2
+ Forest Ink Theme - 森林墨配色方案
3
+ 基于 template.html 修改,保持完整结构和 JavaScript 不变
4
+ -->
5
+ <!doctype html>
6
+ <html lang="zh-CN">
7
+ <head>
8
+ <meta charset="UTF-8">
9
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
10
+ <title>Slide Deck</title>
11
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
12
+ <style>
13
+ :root {
14
+ --paper: #f5f1e8;
15
+ --ink: #1a2e1f;
16
+ --accent: #3d6b4a;
17
+ --accent-soft: rgba(61,107,74,0.1);
18
+ --gray-200: #d4cfc4;
19
+ --gray-500: #6b7a6e;
20
+ --gray-600: #4a5a4c;
21
+ --gray-900: #1a2e1f;
22
+ }
23
+
24
+ * { box-sizing: border-box; margin: 0; padding: 0; }
25
+
26
+ html, body {
27
+ width: 100%; height: 100%; overflow: hidden;
28
+ background:
29
+ radial-gradient(circle at 10% 12%, rgba(61,107,74,0.05) 0, rgba(61,107,74,0) 42%),
30
+ radial-gradient(circle at 88% 84%, rgba(77,123,90,0.05) 0, rgba(77,123,90,0) 40%),
31
+ var(--paper);
32
+ color: var(--ink);
33
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
34
+ -webkit-font-smoothing: antialiased;
35
+ touch-action: pan-y;
36
+ }
37
+
38
+ body::before {
39
+ content: ""; position: fixed; inset: 0;
40
+ background-image:
41
+ repeating-linear-gradient(0deg, rgba(26,46,31,0.012) 0, rgba(26,46,31,0.012) 1px, transparent 1px, transparent 4px),
42
+ repeating-linear-gradient(90deg, rgba(26,46,31,0.008) 0, rgba(26,46,31,0.008) 1px, transparent 1px, transparent 6px);
43
+ pointer-events: none; z-index: 1;
44
+ }
45
+
46
+ .viewport { position: relative; width: 100%; height: 100%; display: grid; place-items: center; padding: 18px; z-index: 2; }
47
+
48
+ .deck {
49
+ position: relative;
50
+ width: min(100vw - 36px, calc((100vh - 36px) * (16 / 9)));
51
+ aspect-ratio: 16 / 9;
52
+ border: 1px solid var(--gray-200); border-radius: 16px; overflow: hidden;
53
+ box-shadow: 0 24px 64px rgba(26,46,31,0.22), 0 8px 24px rgba(26,46,31,0.12), 0 2px 6px rgba(26,46,31,0.08);
54
+ background: linear-gradient(180deg, rgba(255,255,255,0.56), rgba(245,241,232,0.18));
55
+ isolation: isolate;
56
+ }
57
+
58
+ .slides { position: relative; width: 100%; height: 100%; }
59
+
60
+ .slide {
61
+ position: absolute; inset: 0;
62
+ display: grid; grid-template-columns: clamp(16px,1.5vw,26px) 1fr;
63
+ opacity: 0; transform: translateX(32px); pointer-events: none;
64
+ transition: opacity 340ms ease, transform 380ms ease;
65
+ }
66
+ .slide.active { opacity: 1; transform: translateX(0); pointer-events: auto; }
67
+
68
+ .axis-bar {
69
+ background: linear-gradient(180deg, var(--accent) 0 34%, rgba(61,107,74,0.12) 34% 100%);
70
+ box-shadow: inset -1px 0 rgba(26,46,31,0.1);
71
+ }
72
+
73
+ .slide-main {
74
+ position: relative;
75
+ padding: clamp(30px,4.2vw,82px);
76
+ display: grid; grid-template-rows: auto 1fr auto;
77
+ min-height: 0; gap: clamp(10px,1.3vw,20px);
78
+ }
79
+
80
+ .slide header {
81
+ display: flex; align-items: center; justify-content: space-between;
82
+ gap: 18px; min-height: 44px; padding-right: clamp(44px,4.2vw,76px);
83
+ }
84
+
85
+ .kicker {
86
+ font-weight: 600; letter-spacing: 0.06em;
87
+ font-size: clamp(13px,1.15vw,22px); text-transform: uppercase;
88
+ color: var(--accent); white-space: nowrap;
89
+ }
90
+ .top-line { flex: 1; height: 2px; background: linear-gradient(90deg, rgba(61,107,74,0.5), rgba(61,107,74,0)); }
91
+ .marker { color: rgba(61,107,74,0.6); font-size: clamp(12px,1vw,18px); }
92
+
93
+ .content {
94
+ min-height: 0; max-width: 94%;
95
+ display: grid; align-content: center;
96
+ gap: clamp(14px,1.7vw,28px); overflow: hidden;
97
+ padding-right: clamp(6px,0.8vw,12px);
98
+ }
99
+
100
+ h1, h2 {
101
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; line-height: 1.14;
102
+ letter-spacing: 0.01em; text-wrap: balance; max-width: 96%; color: var(--ink);
103
+ }
104
+ h1 { font-weight: 900; font-size: clamp(48px,5.6vw,108px); }
105
+ h2 { font-weight: 800; font-size: clamp(40px,4.4vw,82px); }
106
+
107
+ .md-block {
108
+ white-space: pre-wrap; word-break: break-word; text-wrap: pretty;
109
+ font-size: clamp(23px,2.1vw,44px); line-height: 1.45;
110
+ font-weight: 500; color: var(--gray-900);
111
+ }
112
+
113
+ .statement-only h2 { font-size: clamp(46px,5.2vw,96px); max-width: 98%; }
114
+
115
+ .cover-slide {
116
+ grid-template-columns: 1fr !important;
117
+ display: block !important;
118
+ }
119
+ .cover-slide .axis-bar { display: none; }
120
+ .cover-slide .slide-main {
121
+ width: 100%; height: 100%;
122
+ background: var(--paper);
123
+ background-size: cover; background-position: center; background-repeat: no-repeat;
124
+ padding: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
125
+ }
126
+ .cover-slide .slide-main header { display: none; }
127
+ .cover-slide .slide-main .content {
128
+ display: grid; place-items: center; gap: clamp(8px,1.2vw,18px);
129
+ text-align: center; max-width: 100%; padding: 0 20px;
130
+ flex: 1; align-self: stretch; display: flex; flex-direction: column; align-items: center; justify-content: center;
131
+ }
132
+ .cover-slide .slide-main .content h1 {
133
+ font-family: "Noto Serif SC", "Source Han Serif SC", -apple-system, BlinkMacSystemFont, sans-serif;
134
+ font-size: clamp(64px,7vw,130px); color: var(--accent); font-weight: 900;
135
+ text-shadow: 0 4px 24px rgba(61,107,74,0.25); letter-spacing: 0.01em;
136
+ }
137
+ .cover-slide .slide-main .content .md-block {
138
+ font-size: clamp(22px,2.4vw,44px); color: var(--gray-600);
139
+ font-weight: 500; text-shadow: none;
140
+ }
141
+ .cover-slide .slide-main footer {
142
+ border-top: 1px solid var(--gray-200); justify-content: center; padding-bottom: clamp(20px,2.5vw,40px);
143
+ }
144
+ .cover-slide .slide-main footer .chip { display: none; }
145
+ .cover-slide .slide-main footer .page {
146
+ color: var(--gray-500); font-size: clamp(12px,1vw,18px);
147
+ }
148
+
149
+ .video-slide .content { align-content: center; justify-items: center; }
150
+ .video-slide video {
151
+ width: min(92%, 960px); aspect-ratio: 16 / 9;
152
+ border-radius: 12px; background: #000;
153
+ box-shadow: 0 8px 32px rgba(0,0,0,0.18);
154
+ }
155
+
156
+ .thankyou h2 { font-size: clamp(52px,5.8vw,110px); color: var(--accent); }
157
+ .thankyou .md-block { font-size: clamp(26px,2.4vw,48px); color: var(--gray-600); }
158
+
159
+ footer {
160
+ display: flex; align-items: center; justify-content: space-between;
161
+ gap: 14px; border-top: 1px solid var(--gray-200);
162
+ padding-top: clamp(10px,1.2vw,16px); padding-right: clamp(20px,2vw,40px);
163
+ }
164
+
165
+ .chip {
166
+ font-weight: 600; font-size: clamp(11px,0.95vw,17px);
167
+ letter-spacing: 0.06em; text-transform: uppercase;
168
+ color: var(--accent); background: var(--accent-soft);
169
+ border: 1px solid rgba(61,107,74,0.2); border-radius: 999px; padding: 7px 12px;
170
+ }
171
+ .page {
172
+ font-weight: 600; font-size: clamp(13px,1.1vw,20px);
173
+ color: var(--gray-500); letter-spacing: 0.06em;
174
+ }
175
+
176
+ .hint {
177
+ position: fixed; left: 50%; bottom: max(16px, env(safe-area-inset-bottom));
178
+ transform: translateX(-50%); z-index: 3; font-size: 12px;
179
+ color: var(--gray-500); background: rgba(245,241,232,0.84);
180
+ border: 1px solid var(--gray-200); border-radius: 999px;
181
+ padding: 6px 10px; backdrop-filter: blur(4px);
182
+ }
183
+
184
+ .launch-layer {
185
+ position: fixed; inset: 0; z-index: 4; display: grid; place-items: center; padding: 20px;
186
+ background: rgba(26,46,31,0.48); backdrop-filter: blur(3px);
187
+ opacity: 1; transition: opacity 220ms ease;
188
+ }
189
+ .launch-layer.hidden { opacity: 0; pointer-events: none; }
190
+
191
+ .launch-btn {
192
+ border: 1px solid var(--gray-200);
193
+ background: linear-gradient(180deg, rgba(245,241,232,0.97), rgba(245,241,232,0.9));
194
+ color: var(--ink); border-radius: 16px;
195
+ padding: clamp(16px,2.2vw,24px) clamp(20px,2.8vw,32px);
196
+ min-width: min(88vw, 560px); display: grid; gap: 10px; text-align: left;
197
+ box-shadow: 0 20px 52px rgba(0,0,0,0.28); cursor: pointer;
198
+ }
199
+ .launch-title {
200
+ font-size: clamp(28px,3.2vw,48px);
201
+ font-weight: 700; line-height: 1.12; display: inline-flex; align-items: center; gap: 10px;
202
+ }
203
+ .launch-sub { font-size: clamp(14px,1.2vw,20px); color: var(--gray-600); line-height: 1.4; font-weight: 500; }
204
+
205
+ .slide-preview {
206
+ margin-top: 8px; max-width: clamp(180px,22vw,360px);
207
+ border-radius: 8px; overflow: hidden;
208
+ box-shadow: 0 4px 16px rgba(0,0,0,0.12); border: 1px solid var(--gray-200);
209
+ }
210
+ .slide-preview img { width: 100%; height: auto; display: block; }
211
+
212
+ @keyframes fadeUp {
213
+ from { opacity: 0; transform: translateY(12px); }
214
+ to { opacity: 1; transform: translateY(0); }
215
+ }
216
+ .slide.active h1, .slide.active h2, .slide.active .md-block { animation: fadeUp 320ms ease both; }
217
+ .slide.active .md-block:nth-of-type(2) { animation-delay: 60ms; }
218
+ .slide.active .md-block:nth-of-type(3) { animation-delay: 120ms; }
219
+
220
+ @media (max-width: 900px) {
221
+ .viewport { padding: 10px; }
222
+ .deck { width: calc(100vw - 20px); }
223
+ .slide { grid-template-columns: 10px 1fr; }
224
+ .slide-main { padding: clamp(16px,4.4vw,28px); gap: 8px; }
225
+ h1 { font-size: clamp(34px,7.2vw,56px); }
226
+ h2 { font-size: clamp(30px,6vw,52px); }
227
+ .md-block { font-size: clamp(16px,3.2vw,24px); }
228
+ .cover-slide h1 { font-size: clamp(32px,6.5vw,52px); }
229
+ }
230
+ </style>
231
+ </head>
232
+ <body>
233
+ <div class="viewport">
234
+ <main class="deck">
235
+ <section class="slides" id="slides"></section>
236
+ </main>
237
+ </div>
238
+
239
+ <div class="launch-layer" id="launchLayer">
240
+ <button class="launch-btn" id="launchBtn" type="button">
241
+ <span class="launch-title">
242
+ <i class="fa-solid fa-expand" aria-hidden="true"></i>
243
+ <span id="launchTitle">开始演示(全屏)</span>
244
+ </span>
245
+ <span class="launch-sub">按 F 切换全屏 · ← → 翻页 · 点击左右翻页</span>
246
+ </button>
247
+ </div>
248
+
249
+ <div class="hint">← → / Space / 点击左右 / 滑动</div>
250
+
251
+ <script>
252
+ (function () {
253
+ // ─── Markdown parser ───────────────────────────────────────────────────────
254
+
255
+ function parseFrontmatter(text) {
256
+ const meta = {};
257
+ const match = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
258
+ if (!match) return { meta, body: text };
259
+ match[1].split('\n').forEach(line => {
260
+ const [k, ...v] = line.split(':');
261
+ if (k && v.length) meta[k.trim()] = v.join(':').trim();
262
+ });
263
+ return { meta, body: match[2] };
264
+ }
265
+
266
+ function parseDirective(line) {
267
+ // <!-- type: cover, bg: cover-v2.png -->
268
+ const match = line.match(/<!--\s*(.*?)\s*-->/);
269
+ if (!match) return {};
270
+ const result = {};
271
+ match[1].split(',').forEach(pair => {
272
+ const [k, ...v] = pair.split(':');
273
+ if (k) result[k.trim()] = v.join(':').trim();
274
+ });
275
+ return result;
276
+ }
277
+
278
+ function parseSlides(body) {
279
+ // Strip multi-line HTML comments before splitting into slides
280
+ const stripped = body.replace(/<!--[\s\S]*?-->/g, '');
281
+ return stripped.split(/\n---\n/).map(raw => {
282
+ const lines = raw.trim().split('\n');
283
+ const slide = { type: 'section', title: '', blocks: [] };
284
+
285
+ // Check first line for directive comment (single-line only, already stripped above)
286
+ if (lines[0] && lines[0].trim().startsWith('<!--')) {
287
+ Object.assign(slide, parseDirective(lines.shift()));
288
+ }
289
+
290
+ lines.forEach(line => {
291
+ if (line.startsWith('# ')) {
292
+ slide.title = line.slice(2).trim();
293
+ if (!slide.type || slide.type === 'section') slide.type = 'cover';
294
+ } else if (line.startsWith('## ')) {
295
+ slide.title = line.slice(3).trim();
296
+ } else if (line.trim()) {
297
+ slide.blocks.push(line.trim());
298
+ }
299
+ });
300
+
301
+ slide.blocks = mergeBlocks(raw, slide);
302
+
303
+ return slide;
304
+ }).filter(s => s.type || s.title || s.blocks.length);
305
+ }
306
+
307
+ // Re-parse blocks respecting blank-line paragraph breaks
308
+ // Blocks can be text strings or {type:'image', src, alt} objects
309
+ function mergeBlocks(raw, slide) {
310
+ const stripped = raw.replace(/<!--[\s\S]*?-->/g, '');
311
+ const lines = stripped.trim().split('\n');
312
+ const blocks = [];
313
+ let current = [];
314
+
315
+ function flushText() {
316
+ if (current.length) { blocks.push(current.join('\n')); current = []; }
317
+ }
318
+
319
+ lines.forEach(line => {
320
+ if (line.startsWith('#')) return;
321
+ const imgMatch = line.trim().match(/^!\[([^\]]*)\]\(([^)]+)\)$/);
322
+ if (imgMatch) {
323
+ flushText();
324
+ blocks.push({ type: 'image', alt: imgMatch[1], src: imgMatch[2] });
325
+ return;
326
+ }
327
+ if (line.trim() === '') {
328
+ flushText();
329
+ } else {
330
+ current.push(line.trim());
331
+ }
332
+ });
333
+ flushText();
334
+ return blocks;
335
+ }
336
+
337
+ // ─── Render ────────────────────────────────────────────────────────────────
338
+
339
+ function buildDeck(slides, meta) {
340
+ const slidesEl = document.getElementById('slides');
341
+ const kicker = meta.kicker || '';
342
+ const chip = meta.chip || '';
343
+ const page = meta.page || '';
344
+
345
+ // Set launch title from first slide
346
+ const firstTitle = slides[0] && slides[0].title;
347
+ if (firstTitle) document.getElementById('launchTitle').textContent = firstTitle + '(全屏)';
348
+ document.title = firstTitle || 'Slide Deck';
349
+
350
+ slides.forEach((item, idx) => {
351
+ const article = document.createElement('article');
352
+ const classes = ['slide'];
353
+ if (idx === 0) classes.push('active');
354
+ if (item.type === 'cover') classes.push('cover-slide');
355
+ if (item.type === 'statement') classes.push('statement-only');
356
+ if (item.type === 'video') classes.push('video-slide');
357
+ if (item.type === 'thankyou') classes.push('thankyou');
358
+ article.className = classes.join(' ');
359
+ article.dataset.index = String(idx);
360
+
361
+ const axis = document.createElement('div');
362
+ axis.className = 'axis-bar';
363
+
364
+ const main = document.createElement('div');
365
+ main.className = 'slide-main';
366
+
367
+ if (item.type === 'cover') {
368
+ if (item.bg) {
369
+ main.style.background = `linear-gradient(rgba(0,0,0,0.38), rgba(0,0,0,0.52)), url('${item.bg}') center/cover no-repeat`;
370
+ }
371
+ }
372
+
373
+ // Header
374
+ const header = document.createElement('header');
375
+ const kickerEl = document.createElement('span');
376
+ kickerEl.className = 'kicker';
377
+ kickerEl.textContent = idx === 0 ? (meta.kicker || '') : kicker;
378
+ const line = document.createElement('span');
379
+ line.className = 'top-line';
380
+ const marker = document.createElement('span');
381
+ marker.className = 'marker';
382
+ marker.innerHTML = '<i class="fa-solid fa-plus"></i>';
383
+ header.append(kickerEl, line, marker);
384
+
385
+ // Content
386
+ const content = document.createElement('div');
387
+ content.className = 'content';
388
+
389
+ if (item.title) {
390
+ const heading = document.createElement(idx === 0 ? 'h1' : 'h2');
391
+ heading.textContent = item.title;
392
+ content.appendChild(heading);
393
+ }
394
+
395
+ item.blocks.forEach(block => {
396
+ if (block && typeof block === 'object' && block.type === 'image') {
397
+ const wrap = document.createElement('div');
398
+ wrap.className = 'slide-preview';
399
+ const img = document.createElement('img');
400
+ img.src = block.src;
401
+ if (block.alt) img.alt = block.alt;
402
+ wrap.appendChild(img);
403
+ content.appendChild(wrap);
404
+ } else {
405
+ const p = document.createElement('p');
406
+ p.className = 'md-block';
407
+ p.textContent = block;
408
+ content.appendChild(p);
409
+ }
410
+ });
411
+
412
+ if (item.src) {
413
+ const video = document.createElement('video');
414
+ video.src = item.src;
415
+ video.controls = true;
416
+ video.playsInline = true;
417
+ video.preload = 'metadata';
418
+ content.appendChild(video);
419
+ }
420
+
421
+ if (item.preview) {
422
+ const wrap = document.createElement('div');
423
+ wrap.className = 'slide-preview';
424
+ const img = document.createElement('img');
425
+ img.src = item.preview;
426
+ wrap.appendChild(img);
427
+ content.appendChild(wrap);
428
+ }
429
+
430
+ // Footer
431
+ const footer = document.createElement('footer');
432
+ const chipEl = document.createElement('span');
433
+ chipEl.className = 'chip';
434
+ chipEl.textContent = chip;
435
+ const pageEl = document.createElement('span');
436
+ pageEl.className = 'page';
437
+ pageEl.textContent = idx === 0 ? (meta.coverPage || page) : page;
438
+ footer.append(chipEl, pageEl);
439
+
440
+ main.append(header, content, footer);
441
+ article.append(axis, main);
442
+ slidesEl.appendChild(article);
443
+ });
444
+ }
445
+
446
+ // ─── Navigation ────────────────────────────────────────────────────────────
447
+
448
+ function initNav() {
449
+ const slides = Array.from(document.querySelectorAll('.slide'));
450
+ const launchLayer = document.getElementById('launchLayer');
451
+ const launchBtn = document.getElementById('launchBtn');
452
+ let index = 0;
453
+ let touchStartX = 0;
454
+
455
+ function render(next) {
456
+ index = Math.max(0, Math.min(slides.length - 1, next));
457
+ slides.forEach((s, i) => {
458
+ s.classList.toggle('active', i === index);
459
+ if (i !== index) {
460
+ const v = s.querySelector('video');
461
+ if (v && !v.paused) v.pause();
462
+ }
463
+ });
464
+ }
465
+
466
+ function getFS() { return document.fullscreenElement || document.webkitFullscreenElement || null; }
467
+ async function reqFS() {
468
+ if (getFS()) return;
469
+ const r = document.documentElement;
470
+ const fn = r.requestFullscreen || r.webkitRequestFullscreen;
471
+ if (fn) try { await fn.call(r); } catch(e) {}
472
+ }
473
+ async function toggleFS() {
474
+ if (getFS()) {
475
+ const fn = document.exitFullscreen || document.webkitExitFullscreen;
476
+ if (fn) try { await fn.call(document); } catch(e) {}
477
+ } else { await reqFS(); }
478
+ }
479
+ function hideLL() {
480
+ if (!launchLayer || launchLayer.classList.contains('hidden')) return;
481
+ launchLayer.classList.add('hidden');
482
+ setTimeout(() => { if (launchLayer.parentNode) launchLayer.parentNode.removeChild(launchLayer); }, 240);
483
+ }
484
+ async function startPres(e) {
485
+ if (e) { e.preventDefault(); e.stopPropagation(); }
486
+ await reqFS(); hideLL();
487
+ }
488
+
489
+ window.addEventListener('keydown', e => {
490
+ if (e.key === 'Enter' && launchLayer && !launchLayer.classList.contains('hidden')) { startPres(e); return; }
491
+ if (e.key === 'f' || e.key === 'F') { e.preventDefault(); toggleFS(); return; }
492
+ if (e.key === 'ArrowRight' || e.key === 'PageDown' || e.key === ' ') { e.preventDefault(); render(index + 1); }
493
+ if (e.key === 'ArrowLeft' || e.key === 'PageUp') { e.preventDefault(); render(index - 1); }
494
+ if (e.key === 'Home') { e.preventDefault(); render(0); }
495
+ if (e.key === 'End') { e.preventDefault(); render(slides.length - 1); }
496
+ });
497
+
498
+ document.addEventListener('click', e => {
499
+ if (launchLayer && !launchLayer.classList.contains('hidden')) return;
500
+ if (e.target.closest('video')) return;
501
+ e.clientX > window.innerWidth * 0.5 ? render(index + 1) : render(index - 1);
502
+ });
503
+
504
+ document.addEventListener('touchstart', e => {
505
+ if (e.changedTouches.length) touchStartX = e.changedTouches[0].clientX;
506
+ }, { passive: true });
507
+
508
+ document.addEventListener('touchend', e => {
509
+ if (launchLayer && !launchLayer.classList.contains('hidden')) return;
510
+ if (!e.changedTouches.length) return;
511
+ const d = e.changedTouches[0].clientX - touchStartX;
512
+ if (Math.abs(d) < 30) return;
513
+ d < 0 ? render(index + 1) : render(index - 1);
514
+ }, { passive: true });
515
+
516
+ if (launchBtn) launchBtn.addEventListener('click', e => startPres(e));
517
+ if (launchLayer) launchLayer.addEventListener('click', e => { if (e.target === launchLayer) startPres(e); });
518
+
519
+ render(0);
520
+ }
521
+
522
+ // ─── Boot: fetch slides.md ──────────────────────────────────────────────────
523
+
524
+ fetch('slides.md')
525
+ .then(r => r.text())
526
+ .then(text => {
527
+ const { meta, body } = parseFrontmatter(text);
528
+ const slides = parseSlides(body);
529
+ buildDeck(slides, meta);
530
+ initNav();
531
+ })
532
+ .catch(err => {
533
+ document.body.innerHTML = `<div style="padding:40px;font-family:monospace;color:red">
534
+ Failed to load slides.md<br>${err.message}
535
+ </div>`;
536
+ });
537
+ })();
538
+ </script>
539
+ </body>
540
+ </html>