@autumnsgrove/groveengine 0.8.0 → 0.8.5

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 (86) hide show
  1. package/dist/components/OnboardingChecklist.svelte +2 -2
  2. package/dist/components/WispButton.svelte +83 -0
  3. package/dist/components/WispButton.svelte.d.ts +49 -0
  4. package/dist/components/WispPanel.svelte +1093 -0
  5. package/dist/components/WispPanel.svelte.d.ts +49 -0
  6. package/dist/components/custom/TableOfContents.svelte +12 -1
  7. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  8. package/dist/config/wisp.d.ts +145 -0
  9. package/dist/config/wisp.js +175 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +3 -0
  12. package/dist/server/inference-client.d.ts +139 -0
  13. package/dist/server/inference-client.js +294 -0
  14. package/dist/ui/components/nature/Logo.svelte +55 -19
  15. package/dist/ui/components/nature/botanical/LeafFalling.svelte +2 -2
  16. package/dist/ui/components/nature/botanical/PetalFalling.svelte +7 -7
  17. package/dist/ui/components/nature/ground/Crocus.svelte +3 -3
  18. package/dist/ui/components/nature/ground/Daffodil.svelte +3 -3
  19. package/dist/ui/components/nature/ground/Tulip.svelte +5 -5
  20. package/dist/ui/components/nature/palette.d.ts +187 -76
  21. package/dist/ui/components/nature/palette.js +169 -81
  22. package/dist/ui/components/nature/trees/TreeCherry.svelte +3 -3
  23. package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +1 -1
  24. package/dist/ui/components/nature/trees/TreePine.svelte +2 -2
  25. package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +1 -1
  26. package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
  27. package/dist/ui/components/typography/Alagard.svelte +17 -0
  28. package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
  29. package/dist/ui/components/typography/Atkinson.svelte +17 -0
  30. package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
  31. package/dist/ui/components/typography/BodoniModa.svelte +17 -0
  32. package/dist/ui/components/typography/BodoniModa.svelte.d.ts +10 -0
  33. package/dist/ui/components/typography/Calistoga.svelte +17 -0
  34. package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
  35. package/dist/ui/components/typography/Caveat.svelte +17 -0
  36. package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
  37. package/dist/ui/components/typography/Cormorant.svelte +17 -0
  38. package/dist/ui/components/typography/Cormorant.svelte.d.ts +10 -0
  39. package/dist/ui/components/typography/Cozette.svelte +17 -0
  40. package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
  41. package/dist/ui/components/typography/EBGaramond.svelte +17 -0
  42. package/dist/ui/components/typography/EBGaramond.svelte.d.ts +10 -0
  43. package/dist/ui/components/typography/FontProvider.svelte +98 -0
  44. package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
  45. package/dist/ui/components/typography/Fraunces.svelte +17 -0
  46. package/dist/ui/components/typography/Fraunces.svelte.d.ts +10 -0
  47. package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
  48. package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
  49. package/dist/ui/components/typography/InstrumentSans.svelte +17 -0
  50. package/dist/ui/components/typography/InstrumentSans.svelte.d.ts +10 -0
  51. package/dist/ui/components/typography/Lexend.svelte +17 -0
  52. package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
  53. package/dist/ui/components/typography/Lora.svelte +17 -0
  54. package/dist/ui/components/typography/Lora.svelte.d.ts +10 -0
  55. package/dist/ui/components/typography/Luciole.svelte +17 -0
  56. package/dist/ui/components/typography/Luciole.svelte.d.ts +10 -0
  57. package/dist/ui/components/typography/Manrope.svelte +17 -0
  58. package/dist/ui/components/typography/Manrope.svelte.d.ts +10 -0
  59. package/dist/ui/components/typography/Merriweather.svelte +17 -0
  60. package/dist/ui/components/typography/Merriweather.svelte.d.ts +10 -0
  61. package/dist/ui/components/typography/Nunito.svelte +17 -0
  62. package/dist/ui/components/typography/Nunito.svelte.d.ts +10 -0
  63. package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
  64. package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
  65. package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
  66. package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
  67. package/dist/ui/components/typography/Quicksand.svelte +17 -0
  68. package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
  69. package/dist/ui/components/typography/README.md +153 -0
  70. package/dist/ui/components/typography/index.d.ts +23 -0
  71. package/dist/ui/components/typography/index.js +42 -0
  72. package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
  73. package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
  74. package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
  75. package/dist/ui/components/ui/GlassLogo.svelte +2 -1
  76. package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
  77. package/dist/ui/components/ui/index.d.ts +1 -0
  78. package/dist/ui/components/ui/index.js +1 -0
  79. package/dist/ui/index.d.ts +1 -0
  80. package/dist/ui/index.js +2 -0
  81. package/dist/ui/vineyard/index.d.ts +9 -0
  82. package/dist/ui/vineyard/index.js +8 -0
  83. package/dist/utils/csrf.js +5 -2
  84. package/dist/utils/readability.d.ts +89 -0
  85. package/dist/utils/readability.js +204 -0
  86. package/package.json +17 -1
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Readability Analysis - Local Calculations
3
+ *
4
+ * Readability scoring using Flesch-Kincaid and other metrics.
5
+ * No AI needed - purely algorithmic analysis.
6
+ *
7
+ * @see docs/specs/writing-assistant-unified-spec.md
8
+ */
9
+ /**
10
+ * @typedef {Object} ReadabilityResult
11
+ * @property {number} fleschKincaid - Grade level (e.g., 8.5)
12
+ * @property {string} readingTime - Human-readable time (e.g., "5 min read")
13
+ * @property {number} wordCount - Total words
14
+ * @property {number} sentenceCount - Total sentences
15
+ * @property {Object} sentenceStats - Sentence statistics
16
+ * @property {number} sentenceStats.average - Average words per sentence
17
+ * @property {number} sentenceStats.longest - Longest sentence word count
18
+ * @property {number} sentenceStats.shortest - Shortest sentence word count
19
+ * @property {string[]} suggestions - Improvement suggestions
20
+ */
21
+ /**
22
+ * Calculate readability metrics for content
23
+ *
24
+ * @param {string} content - The text to analyze (can include markdown)
25
+ * @returns {ReadabilityResult}
26
+ */
27
+ export function calculateReadability(content: string): ReadabilityResult;
28
+ /**
29
+ * Strip markdown syntax for cleaner readability analysis
30
+ *
31
+ * @param {string} content - Markdown content
32
+ * @returns {string} Plain text
33
+ */
34
+ export function stripMarkdownForAnalysis(content: string): string;
35
+ /**
36
+ * Count syllables in a word (approximate)
37
+ *
38
+ * NOTE: This is a regex-based approximation that works reasonably well for
39
+ * common English words but will be inaccurate for:
40
+ * - Words with silent vowels (e.g., "subtle", "queue")
41
+ * - Compound words and contractions
42
+ * - Words borrowed from other languages
43
+ * - Proper nouns and technical terms
44
+ *
45
+ * For readability scoring purposes, this approximation is sufficient since
46
+ * Flesch-Kincaid is already an estimate and small syllable miscounts don't
47
+ * significantly impact the final grade level calculation.
48
+ *
49
+ * @param {string} word - The word to count syllables for
50
+ * @returns {number} Estimated syllable count
51
+ */
52
+ export function countSyllables(word: string): number;
53
+ /**
54
+ * Get a human-readable description of the grade level
55
+ *
56
+ * @param {number} grade - Flesch-Kincaid grade level
57
+ * @returns {string} Description
58
+ */
59
+ export function getGradeDescription(grade: number): string;
60
+ export type ReadabilityResult = {
61
+ /**
62
+ * - Grade level (e.g., 8.5)
63
+ */
64
+ fleschKincaid: number;
65
+ /**
66
+ * - Human-readable time (e.g., "5 min read")
67
+ */
68
+ readingTime: string;
69
+ /**
70
+ * - Total words
71
+ */
72
+ wordCount: number;
73
+ /**
74
+ * - Total sentences
75
+ */
76
+ sentenceCount: number;
77
+ /**
78
+ * - Sentence statistics
79
+ */
80
+ sentenceStats: {
81
+ average: number;
82
+ longest: number;
83
+ shortest: number;
84
+ };
85
+ /**
86
+ * - Improvement suggestions
87
+ */
88
+ suggestions: string[];
89
+ };
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Readability Analysis - Local Calculations
3
+ *
4
+ * Readability scoring using Flesch-Kincaid and other metrics.
5
+ * No AI needed - purely algorithmic analysis.
6
+ *
7
+ * @see docs/specs/writing-assistant-unified-spec.md
8
+ */
9
+
10
+ /**
11
+ * @typedef {Object} ReadabilityResult
12
+ * @property {number} fleschKincaid - Grade level (e.g., 8.5)
13
+ * @property {string} readingTime - Human-readable time (e.g., "5 min read")
14
+ * @property {number} wordCount - Total words
15
+ * @property {number} sentenceCount - Total sentences
16
+ * @property {Object} sentenceStats - Sentence statistics
17
+ * @property {number} sentenceStats.average - Average words per sentence
18
+ * @property {number} sentenceStats.longest - Longest sentence word count
19
+ * @property {number} sentenceStats.shortest - Shortest sentence word count
20
+ * @property {string[]} suggestions - Improvement suggestions
21
+ */
22
+
23
+ /**
24
+ * Calculate readability metrics for content
25
+ *
26
+ * @param {string} content - The text to analyze (can include markdown)
27
+ * @returns {ReadabilityResult}
28
+ */
29
+ export function calculateReadability(content) {
30
+ // Strip markdown syntax for clean text analysis
31
+ const text = stripMarkdownForAnalysis(content);
32
+
33
+ const sentences = text.split(/[.!?]+/).filter((s) => s.trim().length > 0);
34
+ const words = text.split(/\s+/).filter((w) => w.length > 0);
35
+ const syllables = words.reduce((sum, word) => sum + countSyllables(word), 0);
36
+
37
+ const sentenceCount = Math.max(sentences.length, 1);
38
+ const wordCount = Math.max(words.length, 1);
39
+
40
+ const wordsPerSentence = wordCount / sentenceCount;
41
+ const syllablesPerWord = syllables / wordCount;
42
+
43
+ // Flesch-Kincaid Grade Level
44
+ const fleschKincaid = Math.max(
45
+ 0,
46
+ 0.39 * wordsPerSentence + 11.8 * syllablesPerWord - 15.59
47
+ );
48
+
49
+ // Reading time (~200 words per minute for focused reading)
50
+ const minutes = Math.ceil(wordCount / 200);
51
+
52
+ // Sentence length stats
53
+ const sentenceLengths = sentences.map(
54
+ (s) => s.split(/\s+/).filter((w) => w.length > 0).length
55
+ );
56
+
57
+ return {
58
+ fleschKincaid: Math.round(fleschKincaid * 10) / 10,
59
+ readingTime: `${minutes} min read`,
60
+ wordCount,
61
+ sentenceCount,
62
+ sentenceStats: {
63
+ average: Math.round(wordsPerSentence),
64
+ longest: sentenceLengths.length > 0 ? Math.max(...sentenceLengths) : 0,
65
+ shortest: sentenceLengths.length > 0 ? Math.min(...sentenceLengths) : 0
66
+ },
67
+ suggestions: generateSuggestions(fleschKincaid, wordsPerSentence, sentenceLengths)
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Strip markdown syntax for cleaner readability analysis
73
+ *
74
+ * @param {string} content - Markdown content
75
+ * @returns {string} Plain text
76
+ */
77
+ export function stripMarkdownForAnalysis(content) {
78
+ return content
79
+ .replace(/```[\s\S]*?```/g, '') // Remove code blocks
80
+ .replace(/`[^`]+`/g, '') // Remove inline code
81
+ .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Replace links with text
82
+ .replace(/[#*_~>]/g, '') // Remove markdown chars
83
+ .replace(/^\s*[-+*]\s+/gm, '') // Remove list markers
84
+ .replace(/^\s*\d+\.\s+/gm, '') // Remove numbered list markers
85
+ .trim();
86
+ }
87
+
88
+ /**
89
+ * Count syllables in a word (approximate)
90
+ *
91
+ * NOTE: This is a regex-based approximation that works reasonably well for
92
+ * common English words but will be inaccurate for:
93
+ * - Words with silent vowels (e.g., "subtle", "queue")
94
+ * - Compound words and contractions
95
+ * - Words borrowed from other languages
96
+ * - Proper nouns and technical terms
97
+ *
98
+ * For readability scoring purposes, this approximation is sufficient since
99
+ * Flesch-Kincaid is already an estimate and small syllable miscounts don't
100
+ * significantly impact the final grade level calculation.
101
+ *
102
+ * @param {string} word - The word to count syllables for
103
+ * @returns {number} Estimated syllable count
104
+ */
105
+ export function countSyllables(word) {
106
+ word = word.toLowerCase().replace(/[^a-z]/g, '');
107
+ if (word.length <= 3) return 1;
108
+
109
+ word = word.replace(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, '');
110
+ word = word.replace(/^y/, '');
111
+
112
+ const matches = word.match(/[aeiouy]{1,2}/g);
113
+ return matches ? Math.max(matches.length, 1) : 1;
114
+ }
115
+
116
+ /**
117
+ * Generate readability improvement suggestions
118
+ *
119
+ * @param {number} grade - Flesch-Kincaid grade level
120
+ * @param {number} avgSentence - Average words per sentence
121
+ * @param {number[]} sentenceLengths - Array of sentence lengths
122
+ * @returns {string[]} Suggestions (max 4)
123
+ */
124
+ function generateSuggestions(grade, avgSentence, sentenceLengths) {
125
+ const suggestions = [];
126
+
127
+ // Grade level suggestions
128
+ if (grade > 14) {
129
+ suggestions.push(
130
+ 'Your writing is quite complex. Consider simplifying for broader accessibility.'
131
+ );
132
+ } else if (grade > 12) {
133
+ suggestions.push(
134
+ 'College-level reading. Consider if this matches your audience.'
135
+ );
136
+ }
137
+
138
+ // Sentence length suggestions
139
+ if (avgSentence > 30) {
140
+ suggestions.push(
141
+ 'Many sentences are quite long. Breaking them up could improve clarity.'
142
+ );
143
+ } else if (avgSentence > 25) {
144
+ suggestions.push(
145
+ 'Some sentences are on the longer side. Variety in length can improve flow.'
146
+ );
147
+ }
148
+
149
+ // Very long sentences
150
+ const veryLong = sentenceLengths.filter((l) => l > 40);
151
+ if (veryLong.length > 0) {
152
+ suggestions.push(
153
+ `Found ${veryLong.length} sentence${veryLong.length > 1 ? 's' : ''} over 40 words.`
154
+ );
155
+ }
156
+
157
+ // Very simple
158
+ if (grade < 6 && avgSentence < 10) {
159
+ suggestions.push(
160
+ 'Very simple sentences. This works well for accessibility or quick reads.'
161
+ );
162
+ }
163
+
164
+ // Sentence variety
165
+ if (sentenceLengths.length > 5) {
166
+ const variance = calculateVariance(sentenceLengths);
167
+ if (variance < 10) {
168
+ suggestions.push(
169
+ 'Sentence lengths are very uniform. Varying rhythm can make writing more engaging.'
170
+ );
171
+ }
172
+ }
173
+
174
+ return suggestions.slice(0, 4); // Max 4 suggestions
175
+ }
176
+
177
+ /**
178
+ * Calculate variance for sentence length variety
179
+ *
180
+ * @param {number[]} numbers - Array of numbers
181
+ * @returns {number} Variance
182
+ */
183
+ function calculateVariance(numbers) {
184
+ if (numbers.length === 0) return 0;
185
+ const mean = numbers.reduce((a, b) => a + b, 0) / numbers.length;
186
+ return (
187
+ numbers.reduce((sum, n) => sum + Math.pow(n - mean, 2), 0) / numbers.length
188
+ );
189
+ }
190
+
191
+ /**
192
+ * Get a human-readable description of the grade level
193
+ *
194
+ * @param {number} grade - Flesch-Kincaid grade level
195
+ * @returns {string} Description
196
+ */
197
+ export function getGradeDescription(grade) {
198
+ if (grade <= 5) return 'Elementary school level - very easy to read';
199
+ if (grade <= 8) return 'Middle school level - easy to read';
200
+ if (grade <= 10) return 'High school level - fairly easy to read';
201
+ if (grade <= 12) return 'High school senior level - moderately difficult';
202
+ if (grade <= 14) return 'College level - difficult';
203
+ return 'Graduate level - very difficult';
204
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autumnsgrove/groveengine",
3
- "version": "0.8.0",
3
+ "version": "0.8.5",
4
4
  "description": "Multi-tenant blog engine for Grove Platform. Features gutter annotations, markdown editing, magic code auth, and Cloudflare Workers deployment.",
5
5
  "author": "AutumnsGrove",
6
6
  "license": "AGPL-3.0-only",
@@ -73,6 +73,11 @@
73
73
  "svelte": "./dist/ui/components/states/index.js",
74
74
  "default": "./dist/ui/components/states/index.js"
75
75
  },
76
+ "./ui/typography": {
77
+ "types": "./dist/ui/components/typography/index.d.ts",
78
+ "svelte": "./dist/ui/components/typography/index.js",
79
+ "default": "./dist/ui/components/typography/index.js"
80
+ },
76
81
  "./ui/nature": {
77
82
  "types": "./dist/ui/components/nature/index.d.ts",
78
83
  "svelte": "./dist/ui/components/nature/index.js",
@@ -141,6 +146,11 @@
141
146
  "./services/*": {
142
147
  "types": "./dist/server/services/*.d.ts",
143
148
  "default": "./dist/server/services/*.js"
149
+ },
150
+ "./vineyard": {
151
+ "types": "./dist/ui/vineyard/index.d.ts",
152
+ "svelte": "./dist/ui/vineyard/index.js",
153
+ "default": "./dist/ui/vineyard/index.js"
144
154
  }
145
155
  },
146
156
  "files": [
@@ -163,6 +173,8 @@
163
173
  "@tailwindcss/typography": "^0.5.19",
164
174
  "@testing-library/jest-dom": "^6.9.1",
165
175
  "@testing-library/svelte": "^5.2.9",
176
+ "@types/react": "^19.2.7",
177
+ "@types/react-dom": "^19.2.3",
166
178
  "@vitest/coverage-v8": "^4.0.16",
167
179
  "@vitest/ui": "^4.0.14",
168
180
  "autoprefixer": "^10.4.22",
@@ -170,15 +182,19 @@
170
182
  "happy-dom": "^20.0.11",
171
183
  "jsdom": "^27.2.0",
172
184
  "postcss": "^8.5.6",
185
+ "react": "^19.2.3",
186
+ "react-dom": "^19.2.3",
173
187
  "svelte": "^5.1.9",
174
188
  "svelte-check": "^4.0.0",
175
189
  "tailwind-variants": "^0.3.0",
176
190
  "tailwindcss": "^3.4.18",
177
191
  "typescript": "^5.6.0",
192
+ "vibe-kanban-web-companion": "^0.0.5",
178
193
  "vite": "^5.4.10",
179
194
  "vitest": "^4.0.14"
180
195
  },
181
196
  "dependencies": {
197
+ "@autumnsgrove/vineyard": "link:../../../Vineyard",
182
198
  "chart.js": "^4.5.1",
183
199
  "clsx": "^2.1.1",
184
200
  "dompurify": "^3.3.0",