@autumnsgrove/groveengine 0.8.0 → 0.8.6

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 (76) 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 +1092 -0
  5. package/dist/components/WispPanel.svelte.d.ts +49 -0
  6. package/dist/components/custom/ContentWithGutter.svelte +7 -13
  7. package/dist/components/custom/TableOfContents.svelte +12 -1
  8. package/dist/components/quota/UpgradePrompt.svelte +1 -0
  9. package/dist/config/wisp.d.ts +145 -0
  10. package/dist/config/wisp.js +175 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +3 -0
  13. package/dist/server/inference-client.d.ts +139 -0
  14. package/dist/server/inference-client.js +294 -0
  15. package/dist/ui/components/forms/SearchInput.svelte +0 -1
  16. package/dist/ui/components/gallery/ImageGallery.svelte +14 -3
  17. package/dist/ui/components/gallery/Lightbox.svelte +8 -3
  18. package/dist/ui/components/gallery/ZoomableImage.svelte +12 -2
  19. package/dist/ui/components/nature/Logo.svelte +55 -19
  20. package/dist/ui/components/nature/botanical/LeafFalling.svelte +2 -2
  21. package/dist/ui/components/nature/botanical/PetalFalling.svelte +7 -7
  22. package/dist/ui/components/nature/ground/Crocus.svelte +3 -3
  23. package/dist/ui/components/nature/ground/Daffodil.svelte +3 -3
  24. package/dist/ui/components/nature/ground/Tulip.svelte +5 -5
  25. package/dist/ui/components/nature/palette.d.ts +187 -76
  26. package/dist/ui/components/nature/palette.js +169 -81
  27. package/dist/ui/components/nature/trees/TreeCherry.svelte +3 -3
  28. package/dist/ui/components/nature/trees/TreeCherry.svelte.d.ts +1 -1
  29. package/dist/ui/components/nature/trees/TreePine.svelte +2 -2
  30. package/dist/ui/components/nature/trees/TreePine.svelte.d.ts +1 -1
  31. package/dist/ui/components/primitives/textarea/textarea.svelte +1 -1
  32. package/dist/ui/components/typography/Alagard.svelte +17 -0
  33. package/dist/ui/components/typography/Alagard.svelte.d.ts +10 -0
  34. package/dist/ui/components/typography/Atkinson.svelte +17 -0
  35. package/dist/ui/components/typography/Atkinson.svelte.d.ts +10 -0
  36. package/dist/ui/components/typography/Calistoga.svelte +17 -0
  37. package/dist/ui/components/typography/Calistoga.svelte.d.ts +10 -0
  38. package/dist/ui/components/typography/Caveat.svelte +17 -0
  39. package/dist/ui/components/typography/Caveat.svelte.d.ts +10 -0
  40. package/dist/ui/components/typography/Cozette.svelte +17 -0
  41. package/dist/ui/components/typography/Cozette.svelte.d.ts +10 -0
  42. package/dist/ui/components/typography/FontProvider.svelte +98 -0
  43. package/dist/ui/components/typography/FontProvider.svelte.d.ts +17 -0
  44. package/dist/ui/components/typography/IBMPlexMono.svelte +17 -0
  45. package/dist/ui/components/typography/IBMPlexMono.svelte.d.ts +10 -0
  46. package/dist/ui/components/typography/Lexend.svelte +17 -0
  47. package/dist/ui/components/typography/Lexend.svelte.d.ts +10 -0
  48. package/dist/ui/components/typography/OpenDyslexic.svelte +17 -0
  49. package/dist/ui/components/typography/OpenDyslexic.svelte.d.ts +10 -0
  50. package/dist/ui/components/typography/PlusJakartaSans.svelte +17 -0
  51. package/dist/ui/components/typography/PlusJakartaSans.svelte.d.ts +10 -0
  52. package/dist/ui/components/typography/Quicksand.svelte +17 -0
  53. package/dist/ui/components/typography/Quicksand.svelte.d.ts +10 -0
  54. package/dist/ui/components/typography/README.md +153 -0
  55. package/dist/ui/components/typography/index.d.ts +13 -0
  56. package/dist/ui/components/typography/index.js +31 -0
  57. package/dist/ui/components/ui/CollapsibleSection.svelte +10 -0
  58. package/dist/ui/components/ui/GlassCarousel.svelte +446 -0
  59. package/dist/ui/components/ui/GlassCarousel.svelte.d.ts +57 -0
  60. package/dist/ui/components/ui/GlassConfirmDialog.svelte +2 -1
  61. package/dist/ui/components/ui/GlassLogo.svelte +2 -1
  62. package/dist/ui/components/ui/GlassOverlay.svelte +1 -1
  63. package/dist/ui/components/ui/index.d.ts +1 -0
  64. package/dist/ui/components/ui/index.js +1 -0
  65. package/dist/ui/index.d.ts +1 -0
  66. package/dist/ui/index.js +2 -0
  67. package/dist/ui/tokens/fonts.d.ts +1 -1
  68. package/dist/ui/tokens/fonts.js +0 -126
  69. package/dist/ui/vineyard/index.d.ts +9 -0
  70. package/dist/ui/vineyard/index.js +8 -0
  71. package/dist/utils/csrf.js +5 -2
  72. package/dist/utils/readability.d.ts +89 -0
  73. package/dist/utils/readability.js +204 -0
  74. package/package.json +38 -21
  75. package/static/fonts/alagard.ttf +0 -0
  76. package/LICENSE +0 -378
@@ -61,39 +61,7 @@ export const fonts = [
61
61
  "sans-serif",
62
62
  ],
63
63
  },
64
- {
65
- id: "luciole",
66
- name: "Luciole",
67
- file: "Luciole-Regular.ttf",
68
- format: "truetype",
69
- fontFamily: "Luciole",
70
- category: "accessibility",
71
- description: "French accessibility font designed for visually impaired readers.",
72
- fallback: [
73
- "-apple-system",
74
- "BlinkMacSystemFont",
75
- "Segoe UI",
76
- "Roboto",
77
- "sans-serif",
78
- ],
79
- },
80
64
  // Modern sans-serif fonts
81
- {
82
- id: "nunito",
83
- name: "Nunito",
84
- file: "Nunito-Regular.ttf",
85
- format: "truetype",
86
- fontFamily: "Nunito",
87
- category: "sans-serif",
88
- description: "Friendly rounded sans-serif. Warm and approachable.",
89
- fallback: [
90
- "-apple-system",
91
- "BlinkMacSystemFont",
92
- "Segoe UI",
93
- "Roboto",
94
- "sans-serif",
95
- ],
96
- },
97
65
  {
98
66
  id: "quicksand",
99
67
  name: "Quicksand",
@@ -110,38 +78,6 @@ export const fonts = [
110
78
  "sans-serif",
111
79
  ],
112
80
  },
113
- {
114
- id: "manrope",
115
- name: "Manrope",
116
- file: "Manrope-Regular.ttf",
117
- format: "truetype",
118
- fontFamily: "Manrope",
119
- category: "sans-serif",
120
- description: "Professional geometric sans. Clean and contemporary.",
121
- fallback: [
122
- "-apple-system",
123
- "BlinkMacSystemFont",
124
- "Segoe UI",
125
- "Roboto",
126
- "sans-serif",
127
- ],
128
- },
129
- {
130
- id: "instrument-sans",
131
- name: "Instrument Sans",
132
- file: "InstrumentSans-Regular.ttf",
133
- format: "truetype",
134
- fontFamily: "Instrument Sans",
135
- category: "sans-serif",
136
- description: "Low contrast sans with humanist touches. Elegant simplicity.",
137
- fallback: [
138
- "-apple-system",
139
- "BlinkMacSystemFont",
140
- "Segoe UI",
141
- "Roboto",
142
- "sans-serif",
143
- ],
144
- },
145
81
  {
146
82
  id: "plus-jakarta-sans",
147
83
  name: "Plus Jakarta Sans",
@@ -158,67 +94,6 @@ export const fonts = [
158
94
  "sans-serif",
159
95
  ],
160
96
  },
161
- // Serif fonts
162
- {
163
- id: "cormorant",
164
- name: "Cormorant",
165
- file: "Cormorant-Regular.ttf",
166
- format: "truetype",
167
- fontFamily: "Cormorant",
168
- category: "serif",
169
- description: "Elegant display serif inspired by Garamond. Refined and classic.",
170
- fallback: ["Georgia", "Times New Roman", "serif"],
171
- },
172
- {
173
- id: "bodoni-moda",
174
- name: "Bodoni Moda",
175
- file: "BodoniModa-Regular.ttf",
176
- format: "truetype",
177
- fontFamily: "Bodoni Moda",
178
- category: "serif",
179
- description: "High contrast modern serif. Bold and sophisticated.",
180
- fallback: ["Georgia", "Times New Roman", "serif"],
181
- },
182
- {
183
- id: "lora",
184
- name: "Lora",
185
- file: "Lora-Regular.ttf",
186
- format: "truetype",
187
- fontFamily: "Lora",
188
- category: "serif",
189
- description: "Well-balanced contemporary serif. Excellent for body text.",
190
- fallback: ["Georgia", "Times New Roman", "serif"],
191
- },
192
- {
193
- id: "eb-garamond",
194
- name: "EB Garamond",
195
- file: "EBGaramond-Regular.ttf",
196
- format: "truetype",
197
- fontFamily: "EB Garamond",
198
- category: "serif",
199
- description: "Revival of classic Garamond. Timeless book typography.",
200
- fallback: ["Georgia", "Times New Roman", "serif"],
201
- },
202
- {
203
- id: "merriweather",
204
- name: "Merriweather",
205
- file: "Merriweather-Regular.ttf",
206
- format: "truetype",
207
- fontFamily: "Merriweather",
208
- category: "serif",
209
- description: "Designed for screen reading. Excellent legibility.",
210
- fallback: ["Georgia", "Times New Roman", "serif"],
211
- },
212
- {
213
- id: "fraunces",
214
- name: "Fraunces",
215
- file: "Fraunces-Regular.ttf",
216
- format: "truetype",
217
- fontFamily: "Fraunces",
218
- category: "serif",
219
- description: 'Soft serif with "wonky" optical axes. Warm personality.',
220
- fallback: ["Georgia", "Times New Roman", "serif"],
221
- },
222
97
  // Monospace fonts
223
98
  {
224
99
  id: "ibm-plex-mono",
@@ -335,7 +210,6 @@ export const fontCategoryLabels = {
335
210
  default: "Default",
336
211
  accessibility: "Accessibility",
337
212
  "sans-serif": "Sans-Serif",
338
- serif: "Serif",
339
213
  monospace: "Monospace",
340
214
  display: "Display & Special",
341
215
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Vineyard Components
3
+ * Re-exports from @autumnsgrove/vineyard package
4
+ *
5
+ * Usage:
6
+ * import { VineyardLayout, FeatureCard, StatusBadge } from '@autumnsgrove/groveengine/vineyard';
7
+ */
8
+ export { VineyardLayout, FeatureCard, StatusBadge, DemoContainer, CodeExample, TierGate, RoadmapSection, } from "@autumnsgrove/vineyard/vineyard";
9
+ export type { VineyardStatus, GroveTool, GroveTier, VineyardLayoutProps, FeatureCardProps, StatusBadgeProps, DemoContainerProps, CodeExampleProps, TierGateProps, RoadmapSectionProps, } from "@autumnsgrove/vineyard/vineyard";
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Vineyard Components
3
+ * Re-exports from @autumnsgrove/vineyard package
4
+ *
5
+ * Usage:
6
+ * import { VineyardLayout, FeatureCard, StatusBadge } from '@autumnsgrove/groveengine/vineyard';
7
+ */
8
+ export { VineyardLayout, FeatureCard, StatusBadge, DemoContainer, CodeExample, TierGate, RoadmapSection, } from "@autumnsgrove/vineyard/vineyard";
@@ -44,7 +44,8 @@ export function validateCSRF(request) {
44
44
  }
45
45
 
46
46
  const origin = request.headers.get("origin");
47
- const host = request.headers.get("host");
47
+ // Check X-Forwarded-Host first (set by grove-router proxy), then fall back to host
48
+ const host = request.headers.get("x-forwarded-host") || request.headers.get("host");
48
49
 
49
50
  // Allow same-origin requests
50
51
  if (origin) {
@@ -65,9 +66,11 @@ export function validateCSRF(request) {
65
66
  return false;
66
67
  }
67
68
 
69
+ // Check if origin matches host OR is a *.grove.place subdomain
68
70
  const hostMatches = host && originUrl.host === host;
71
+ const isGroveDomain = originUrl.hostname.endsWith(".grove.place") || originUrl.hostname === "grove.place";
69
72
 
70
- if (!isLocalhost && !hostMatches) {
73
+ if (!isLocalhost && !hostMatches && !isGroveDomain) {
71
74
  return false;
72
75
  }
73
76
  } catch {
@@ -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.6",
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": [
@@ -148,6 +158,26 @@
148
158
  "static",
149
159
  "!dist/**/*.test.*"
150
160
  ],
161
+ "scripts": {
162
+ "dev": "vite dev",
163
+ "dev:wrangler": "wrangler pages dev -- vite dev",
164
+ "build": "vite build",
165
+ "build:package": "svelte-kit sync && svelte-package -o dist",
166
+ "package": "svelte-kit sync && svelte-package -o dist",
167
+ "prepublishOnly": "pnpm run package",
168
+ "preview": "vite preview",
169
+ "deploy": "wrangler pages deploy .svelte-kit/cloudflare --project-name groveengine",
170
+ "audit": "pnpm audit --audit-level=moderate",
171
+ "audit:fix": "pnpm audit --fix",
172
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
173
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
174
+ "test": "vitest",
175
+ "test:ui": "vitest --ui",
176
+ "test:run": "vitest run",
177
+ "test:security": "vitest run tests/security",
178
+ "test:coverage": "vitest run --coverage",
179
+ "test:watch": "vitest watch"
180
+ },
151
181
  "peerDependencies": {
152
182
  "@sveltejs/kit": "^2.0.0",
153
183
  "svelte": "^5.0.0",
@@ -163,6 +193,8 @@
163
193
  "@tailwindcss/typography": "^0.5.19",
164
194
  "@testing-library/jest-dom": "^6.9.1",
165
195
  "@testing-library/svelte": "^5.2.9",
196
+ "@types/react": "^19.2.7",
197
+ "@types/react-dom": "^19.2.3",
166
198
  "@vitest/coverage-v8": "^4.0.16",
167
199
  "@vitest/ui": "^4.0.14",
168
200
  "autoprefixer": "^10.4.22",
@@ -170,15 +202,19 @@
170
202
  "happy-dom": "^20.0.11",
171
203
  "jsdom": "^27.2.0",
172
204
  "postcss": "^8.5.6",
205
+ "react": "^19.2.3",
206
+ "react-dom": "^19.2.3",
173
207
  "svelte": "^5.1.9",
174
208
  "svelte-check": "^4.0.0",
175
209
  "tailwind-variants": "^0.3.0",
176
210
  "tailwindcss": "^3.4.18",
177
211
  "typescript": "^5.6.0",
212
+ "vibe-kanban-web-companion": "^0.0.5",
178
213
  "vite": "^5.4.10",
179
214
  "vitest": "^4.0.14"
180
215
  },
181
216
  "dependencies": {
217
+ "@autumnsgrove/vineyard": "link:../../../Vineyard",
182
218
  "chart.js": "^4.5.1",
183
219
  "clsx": "^2.1.1",
184
220
  "dompurify": "^3.3.0",
@@ -188,24 +224,5 @@
188
224
  "marked": "^17.0.1",
189
225
  "svelte-sonner": "^1.0.7",
190
226
  "tailwind-merge": "^3.4.0"
191
- },
192
- "scripts": {
193
- "dev": "vite dev",
194
- "dev:wrangler": "wrangler pages dev -- vite dev",
195
- "build": "vite build",
196
- "build:package": "svelte-kit sync && svelte-package -o dist",
197
- "package": "svelte-kit sync && svelte-package -o dist",
198
- "preview": "vite preview",
199
- "deploy": "wrangler pages deploy .svelte-kit/cloudflare --project-name groveengine",
200
- "audit": "pnpm audit --audit-level=moderate",
201
- "audit:fix": "pnpm audit --fix",
202
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
203
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
204
- "test": "vitest",
205
- "test:ui": "vitest --ui",
206
- "test:run": "vitest run",
207
- "test:security": "vitest run tests/security",
208
- "test:coverage": "vitest run --coverage",
209
- "test:watch": "vitest watch"
210
227
  }
211
- }
228
+ }
File without changes