feat: Extend worksheet generation age range to 10 years, refine generator parameters, and add PDF watermarks.
This commit is contained in:
parent
ed9c118fef
commit
5630c6cee7
File diff suppressed because one or more lines are too long
@ -120,7 +120,7 @@ const illustrations = {
|
|||||||
<circle cx='15' cy='30' r='2' fill='none' stroke='#000' stroke-width='1'/>
|
<circle cx='15' cy='30' r='2' fill='none' stroke='#000' stroke-width='1'/>
|
||||||
<path d='M10,40 Q15,45 20,42' fill='none' stroke='#000' stroke-width='1'/>
|
<path d='M10,40 Q15,45 20,42' fill='none' stroke='#000' stroke-width='1'/>
|
||||||
<path d='M25,75 L25,95' stroke='#000' stroke-width='3'/>
|
<path d='M25,75 L25,95' stroke='#000' stroke-width='3'/>
|
||||||
<path d='M40' y1='75' L40,95' stroke='#000' stroke-width='3'/>
|
<path d='M40,75 L40,95' stroke='#000' stroke-width='3'/>
|
||||||
<path d='M60,75 L60,95' stroke='#000' stroke-width='3'/>
|
<path d='M60,75 L60,95' stroke='#000' stroke-width='3'/>
|
||||||
<path d='M75,75 L75,95' stroke='#000' stroke-width='3'/>
|
<path d='M75,75 L75,95' stroke='#000' stroke-width='3'/>
|
||||||
<path d='M85,50 Q100,45 95,55 Q105,60 90,65' fill='none' stroke='#000' stroke-width='2'/>
|
<path d='M85,50 Q100,45 95,55 Q105,60 90,65' fill='none' stroke='#000' stroke-width='2'/>
|
||||||
|
|||||||
@ -19,6 +19,19 @@ const themedObjects = {
|
|||||||
|
|
||||||
const objectNames = Object.keys(themedObjects);
|
const objectNames = Object.keys(themedObjects);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pluralize object names correctly
|
||||||
|
*/
|
||||||
|
function pluralize(word) {
|
||||||
|
const irregulars = {
|
||||||
|
'fish': 'Fish',
|
||||||
|
'butterfly': 'Butterflies',
|
||||||
|
'moon': 'Moons'
|
||||||
|
};
|
||||||
|
if (irregulars[word]) return irregulars[word];
|
||||||
|
return word.charAt(0).toUpperCase() + word.slice(1) + 's';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate random quantities that are all different
|
* Generate random quantities that are all different
|
||||||
*/
|
*/
|
||||||
@ -151,7 +164,16 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
|
|||||||
const objectType = pickObjectForTheme(theme, shape);
|
const objectType = pickObjectForTheme(theme, shape);
|
||||||
|
|
||||||
// ALWAYS generate random quantities for variety (LLM is deterministic)
|
// ALWAYS generate random quantities for variety (LLM is deterministic)
|
||||||
const maxValue = age <= 4 ? 5 : 10;
|
let maxValue;
|
||||||
|
if (age <= 4) {
|
||||||
|
maxValue = 5;
|
||||||
|
} else if (age <= 6) {
|
||||||
|
maxValue = 10;
|
||||||
|
} else if (age <= 8) {
|
||||||
|
maxValue = 15;
|
||||||
|
} else {
|
||||||
|
maxValue = 20;
|
||||||
|
}
|
||||||
const rowCount = 8;
|
const rowCount = 8;
|
||||||
const finalQuantities = generateRandomQuantities(rowCount, maxValue);
|
const finalQuantities = generateRandomQuantities(rowCount, maxValue);
|
||||||
|
|
||||||
@ -169,7 +191,7 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
|
|||||||
|
|
||||||
// Dotted separator line between rows (except first row)
|
// Dotted separator line between rows (except first row)
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
objectRows += `<line x1='15' y1='${rowY}' x2='485' y2='${rowY}' stroke='#CCCCCC' stroke-width='1' stroke-dasharray='5,5'/>`;
|
objectRows += `<line x1='15' y1='${rowY}' x2='485' y2='${rowY}' stroke='#AAAAAA' stroke-width='1' stroke-dasharray='5,5'/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Row number indicator - vertically centered in row
|
// Row number indicator - vertically centered in row
|
||||||
@ -191,7 +213,7 @@ export function generateCountingWorksheet({ theme, shape, quantities, age }) {
|
|||||||
</svg>`;
|
</svg>`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: `Count the ${objectType.charAt(0).toUpperCase() + objectType.slice(1)}s!`,
|
title: `Count the ${pluralize(objectType)}!`,
|
||||||
subtitle: 'Count each group and write the number',
|
subtitle: 'Count each group and write the number',
|
||||||
sections: [{
|
sections: [{
|
||||||
id: 'counting-main',
|
id: 'counting-main',
|
||||||
|
|||||||
@ -44,7 +44,7 @@ function generateMazeGrid(rows, cols, startEdge, endEdge) {
|
|||||||
startRow = 0; startCol = 0;
|
startRow = 0; startCol = 0;
|
||||||
break;
|
break;
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
startRow = rows - 1; startCol = rows - 1;
|
startRow = rows - 1; startCol = cols - 1;
|
||||||
break;
|
break;
|
||||||
case 'left':
|
case 'left':
|
||||||
startRow = 0; startCol = 0;
|
startRow = 0; startCol = 0;
|
||||||
@ -169,9 +169,15 @@ export function generateMazeWorksheet({ theme, difficulty = 1, age }) {
|
|||||||
} else if (age <= 5 || difficulty === 2) {
|
} else if (age <= 5 || difficulty === 2) {
|
||||||
rows = 5;
|
rows = 5;
|
||||||
cols = 5;
|
cols = 5;
|
||||||
} else {
|
} else if (age <= 7) {
|
||||||
rows = 6;
|
rows = 6;
|
||||||
cols = 6;
|
cols = 6;
|
||||||
|
} else if (age <= 9) {
|
||||||
|
rows = 7;
|
||||||
|
cols = 7;
|
||||||
|
} else {
|
||||||
|
rows = 8;
|
||||||
|
cols = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Randomly select start and end edges - favor opposite edges for better gameplay
|
// Randomly select start and end edges - favor opposite edges for better gameplay
|
||||||
|
|||||||
@ -96,7 +96,7 @@ function generateCharacterRow(text, y, baseScale = 1, color = '#000000') {
|
|||||||
*/
|
*/
|
||||||
function generateBaseline(y, width = 400) {
|
function generateBaseline(y, width = 400) {
|
||||||
const startX = (500 - width) / 2;
|
const startX = (500 - width) / 2;
|
||||||
return `<line x1='${startX}' y1='${y}' x2='${startX + width}' y2='${y}' stroke='#CCCCCC' stroke-width='1'/>`;
|
return `<line x1='${startX}' y1='${y}' x2='${startX + width}' y2='${y}' stroke='#AAAAAA' stroke-width='1'/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -10,8 +10,7 @@ import { GoogleGenerativeAI } from '@google/generative-ai';
|
|||||||
import {
|
import {
|
||||||
generateWritingWorksheet,
|
generateWritingWorksheet,
|
||||||
generateCountingWorksheet,
|
generateCountingWorksheet,
|
||||||
generateMazeWorksheet,
|
generateMazeWorksheet
|
||||||
generateColoringPage
|
|
||||||
} from './generators/index.js';
|
} from './generators/index.js';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@ -75,9 +74,9 @@ function addToGallery(item) {
|
|||||||
const parameterPrompts = {
|
const parameterPrompts = {
|
||||||
writing: (theme, age) => {
|
writing: (theme, age) => {
|
||||||
const randomSeed = Math.floor(Math.random() * 1000);
|
const randomSeed = Math.floor(Math.random() * 1000);
|
||||||
const wordLength = `${age} letters`;
|
const wordLength = age <= 4 ? '3-4 letters' : age <= 6 ? '4-5 letters' : age <= 8 ? '5-6 letters' : '6-8 letters';
|
||||||
const numberRange = age <= 4 ? '1-5' : '1-9';
|
const numberRange = age <= 4 ? '1-5' : age <= 6 ? '1-9' : age <= 8 ? '1-15' : '1-20';
|
||||||
const numberCount = age <= 4 ? '3-4' : '4-5';
|
const numberCount = age <= 4 ? '3-4' : age <= 6 ? '4-5' : '5-6';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
Create a children's tracing worksheet for theme "${theme}".
|
Create a children's tracing worksheet for theme "${theme}".
|
||||||
@ -109,7 +108,7 @@ CRITICAL: You MUST return JSON with BOTH "shape" AND "quantities":
|
|||||||
{"shape": "star", "quantities": [3, 1, 5, 2, 7, 4, 8, 6]}
|
{"shape": "star", "quantities": [3, 1, 5, 2, 7, 4, 8, 6]}
|
||||||
|
|
||||||
- "shape": Choose ONE shape that matches "${theme}". Use the random seed ${randomSeed} to vary your choice - don't always pick the same shape for this theme.
|
- "shape": Choose ONE shape that matches "${theme}". Use the random seed ${randomSeed} to vary your choice - don't always pick the same shape for this theme.
|
||||||
- "quantities": Array of exactly 8 different numbers (1-${age <= 4 ? 5 : 10})
|
- "quantities": Array of exactly 8 different numbers (1-${age <= 4 ? 5 : age <= 6 ? 10 : age <= 8 ? 15 : 20})
|
||||||
|
|
||||||
Return ONLY valid JSON. No explanation.
|
Return ONLY valid JSON. No explanation.
|
||||||
`;
|
`;
|
||||||
@ -126,7 +125,9 @@ Return ONLY a JSON object:
|
|||||||
Rules:
|
Rules:
|
||||||
- difficulty 1 = easy (4x4 grid) for age 3-4
|
- difficulty 1 = easy (4x4 grid) for age 3-4
|
||||||
- difficulty 2 = medium (5x5 grid) for age 5-6
|
- difficulty 2 = medium (5x5 grid) for age 5-6
|
||||||
- difficulty 3 = hard (6x6 grid) for age 7+
|
- difficulty 3 = hard (6x6 grid) for age 7-8
|
||||||
|
- difficulty 4 = challenging (7x7 grid) for age 9
|
||||||
|
- difficulty 5 = expert (8x8 grid) for age 10
|
||||||
|
|
||||||
Return ONLY valid JSON, no explanation.
|
Return ONLY valid JSON, no explanation.
|
||||||
`,
|
`,
|
||||||
@ -183,7 +184,7 @@ app.post('/api/surprise', async (req, res) => {
|
|||||||
Current timestamp: ${timestamp}
|
Current timestamp: ${timestamp}
|
||||||
|
|
||||||
Generate ONE creative, fun, specific theme for a children's worksheet (e.g. "Space-Rex Coding", "Underwater Hamster Tea Party").
|
Generate ONE creative, fun, specific theme for a children's worksheet (e.g. "Space-Rex Coding", "Underwater Hamster Tea Party").
|
||||||
Pick a RANDOM age between 3 and 7.
|
Pick a RANDOM age between 3 and 10.
|
||||||
Pick a RANDOM activity type with EQUAL PROBABILITY from these 4 options:
|
Pick a RANDOM activity type with EQUAL PROBABILITY from these 4 options:
|
||||||
|
|
||||||
1. "coloring" - coloring pages
|
1. "coloring" - coloring pages
|
||||||
|
|||||||
@ -50,96 +50,69 @@ Age: ${age} years old
|
|||||||
|
|
||||||
🎯 YOUR GOAL: Create a coloring page with ONE clear subject that a 3-year-old can immediately identify as "${theme}".
|
🎯 YOUR GOAL: Create a coloring page with ONE clear subject that a 3-year-old can immediately identify as "${theme}".
|
||||||
|
|
||||||
🚨 ABSOLUTE SVG REQUIREMENTS (CRITICAL - NON-NEGOTIABLE):
|
🚨 ABSOLUTE QUALITY RULES (CRITICAL - NON-NEGOTIABLE):
|
||||||
- EVERY single path MUST have fill="none"
|
1. USE WHITE FILLS: Every closed shape (head, body, legs, eyes) MUST have fill="#FFFFFF". This hides lines behind it.
|
||||||
- EVERY single path MUST have stroke="black" or stroke="#000000"
|
2. DRAWING ORDER: Draw from BACK to FRONT. Background parts first (tail, back legs), then main body, then front details (eyes, nose).
|
||||||
- Use stroke-width="2" or "3" for all outlines
|
3. CLOSED PATHS: All shapes must be fully closed paths so they can be filled with white.
|
||||||
- NO filled shapes allowed - children need empty white areas to color
|
4. NO OVERLAPPING MESS: White fills solve this. If you draw a leg over a body, the white fill of the leg must hide the body line behind it.
|
||||||
- Example: <path d="M 100 100 L 200 100" fill="none" stroke="black" stroke-width="2"/>
|
|
||||||
|
|
||||||
📐 STEP-BY-STEP SVG CONSTRUCTION METHOD:
|
🚨 SVG REQUIREMENTS (CRITICAL):
|
||||||
|
- Background: <rect width="500" height="500" fill="#FFFFFF"/> (Start with white canvas)
|
||||||
|
- Stroke: stroke="black" or stroke="#000000"
|
||||||
|
- Stroke Width: stroke-width="2" for main outlines, "2" for details
|
||||||
|
- Fill: fill="#FFFFFF" for all object parts (to block lines behind)
|
||||||
|
- Fill: fill="none" ONLY for open paths like whiskers or smiles
|
||||||
|
- Example Closed Shape: <path d="M..." fill="#FFFFFF" stroke="black" stroke-width="3"/>
|
||||||
|
- Example Open Line: <path d="M..." fill="none" stroke="black" stroke-width="2"/>
|
||||||
|
|
||||||
For ANIMALS (cat, dog, panda, unicorn, etc.):
|
📐 STEP-BY-STEP CONSTRUCTION METHOD (Layer by Layer):
|
||||||
1. HEAD: Draw a large circle or oval for head (100-150px diameter), centered around x=250, y=200
|
|
||||||
2. EARS: Add 2 rounded ears on top of head (circles, triangles, or ovals)
|
|
||||||
3. EYES: 2 circles (30-40px diameter) positioned symmetrically
|
|
||||||
4. NOSE: Small circle or triangle in center below eyes
|
|
||||||
5. MOUTH: Simple curved line (smile) below nose
|
|
||||||
6. BODY: Large oval or rounded rectangle below head (150-200px wide, 180-220px tall)
|
|
||||||
7. LEGS: 4 rounded rectangles or ovals extending down from body
|
|
||||||
8. TAIL: Curved path on one side
|
|
||||||
9. DETAILS: Add characteristic features (whiskers, spots, horn, etc.)
|
|
||||||
|
|
||||||
For OBJECTS (car, rocket, house, etc.):
|
For ANIMALS (Draw in this order):
|
||||||
1. MAIN BODY: Start with basic shape (rectangle for car/house, elongated triangle for rocket)
|
1. BACK LEGS/TAIL (Furthest back): Draw simple shapes, fill="#FFFFFF", stroke="black"
|
||||||
2. MAJOR COMPONENTS: Add 2-4 large recognizable parts (wheels, windows, door, roof)
|
2. BODY (Middle): Large oval/shape, fill="#FFFFFF", stroke="black" (Hides the top of back legs)
|
||||||
3. DETAILS: Add smaller features that make it identifiable
|
3. HEAD (Front): Large circle/shape, fill="#FFFFFF", stroke="black" (Hides neck/body connection)
|
||||||
|
4. FRONT LEGS (Front): Shapes overlapping body, fill="#FFFFFF", stroke="black"
|
||||||
|
5. FACE DETAILS (Topmost): Eyes, nose, mouth. Eyes can have black pupils.
|
||||||
|
|
||||||
For PLANTS (flower, tree, etc.):
|
For OBJECTS (Car, Rocket, etc):
|
||||||
1. CENTER/TRUNK: Main central element
|
1. MAIN CHASSIS/BODY: Large filled shape (fill="#FFFFFF")
|
||||||
2. PETALS/LEAVES: 5-8 symmetrical rounded shapes around center
|
2. WHEELS/WINGS: Draw on top or behind as needed
|
||||||
3. STEM: Vertical line or path
|
3. WINDOWS/DOORS: Draw on top of body (fill="#FFFFFF")
|
||||||
4. BASE: Ground line or pot
|
4. DETAILS: Lines, handles, bolts
|
||||||
|
|
||||||
🎨 SPECIFIC THEME EXAMPLES:
|
For PLANTS:
|
||||||
|
1. STEM/BRANCHES: Main lines
|
||||||
|
2. LEAVES BEHIND: Fill="#FFFFFF"
|
||||||
|
3. FLOWER CENTER: Fill="#FFFFFF" (Draw last so it's on top)
|
||||||
|
4. PETALS: Fill="#FFFFFF"
|
||||||
|
|
||||||
|
🎨 SPECIFIC THEME GUIDES:
|
||||||
|
|
||||||
UNICORN:
|
UNICORN:
|
||||||
- Circle head (cx="250" cy="180", r="70")
|
- Body: Oval (fill="#FFFFFF")
|
||||||
- 2 triangle ears
|
- Legs: 4 rectangles (fill="#FFFFFF") - make sure they attach naturally
|
||||||
- HORN: Triangle pointing up from forehead (30-40px tall)
|
- Head: Oval/Horse shape (fill="#FFFFFF")
|
||||||
- 2 circle eyes
|
- START with separate shapes, but ensure they LOOK connected
|
||||||
- Small nose circle
|
- Horn: Triangle on forehead
|
||||||
- Curved smile
|
- Mane/Tail: Flowing shapes
|
||||||
- Oval body below head
|
|
||||||
- 4 rounded rectangle legs
|
|
||||||
- Flowing curved tail on right side
|
|
||||||
- Mane: 3-4 curved strokes on neck
|
|
||||||
|
|
||||||
PANDA:
|
ROBOT:
|
||||||
- Large circle head (r="80")
|
- Use geometric shapes (rectangles, circles)
|
||||||
- 2 small circle ears on top
|
- Fill ALL shapes with #FFFFFF to look solid
|
||||||
- 2 LARGE circle eye patches (r="25", OUTLINED not filled)
|
- Add buttons/panels on top
|
||||||
- 2 smaller circle eyes inside patches
|
|
||||||
- Small circle nose
|
|
||||||
- Smile below nose
|
|
||||||
- Large oval body
|
|
||||||
- 4 thick rounded legs
|
|
||||||
- Optional: bamboo stick to the side (2 parallel lines)
|
|
||||||
|
|
||||||
CAT:
|
🔍 QUALITY CHECKLIST:
|
||||||
- Circle head (r="60")
|
✓ Is the main subject clearly visible?
|
||||||
- 2 triangle ears pointing up
|
✓ Are lines hidden where shapes overlap? (e.g. body line not visible through arm)
|
||||||
- 2 circle eyes
|
✓ Is everything filled with white (except open lines)?
|
||||||
- Small triangle nose
|
✓ Is the stroke width consistent (bold 3px)?
|
||||||
- Whiskers (3 lines each side)
|
✓ Is the image centered in 500x500?
|
||||||
- Curved smile
|
|
||||||
- Oval body
|
|
||||||
- 4 legs
|
|
||||||
- Curved S-shaped tail
|
|
||||||
|
|
||||||
FLOWER:
|
|
||||||
- Center circle (r="40")
|
|
||||||
- 6-8 rounded petal paths around center (use ellipses or bezier curves)
|
|
||||||
- Straight stem line down from center
|
|
||||||
- 2 leaf shapes on stem (ellipses at angle)
|
|
||||||
- Simple ground line
|
|
||||||
|
|
||||||
🔍 QUALITY CHECKLIST - YOUR SVG MUST:
|
|
||||||
✓ Have 8-15 large closed shapes ready for coloring
|
|
||||||
✓ Be IMMEDIATELY recognizable as "${theme}"
|
|
||||||
✓ Use ONLY stroke outlines (fill="none" on ALL paths)
|
|
||||||
✓ Have bold stroke-width="2" or "3"
|
|
||||||
✓ Be 500x500 viewBox with subject centered
|
|
||||||
✓ Include characteristic features (horn for unicorn, eye patches for panda, etc.)
|
|
||||||
✓ Have simple, rounded, child-friendly shapes
|
|
||||||
✓ Look like it came from a store-bought coloring book
|
|
||||||
|
|
||||||
❌ AVOID:
|
❌ AVOID:
|
||||||
- Abstract or geometric art
|
- fill="none" on main shapes (causes messy overlaps)
|
||||||
- Filled/colored areas
|
- Translucent/opacity effects
|
||||||
- Tiny details (too hard for kids)
|
- Tiny dust/specks
|
||||||
- Complex overlapping shapes
|
- Disconnected lines that should be closed
|
||||||
- Unrecognizable forms
|
|
||||||
|
|
||||||
${baseRules}
|
${baseRules}
|
||||||
${ageRules(age)}
|
${ageRules(age)}
|
||||||
|
|||||||
@ -110,7 +110,10 @@ function App() {
|
|||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
<footer className="bg-white border-t border-slate-200 mt-20 py-12">
|
<footer className="bg-white border-t border-slate-200 mt-20 py-12">
|
||||||
<div className="max-w-7xl mx-auto px-4 text-center text-slate-500 text-sm">
|
<div className="max-w-7xl mx-auto px-4 text-center text-slate-500 text-sm">
|
||||||
<p>© 2024 WonderSheets. All rights reserved.</p>
|
<p className="mb-2">
|
||||||
|
<a href="https://wondersheets.art" className="font-semibold text-primary-600 hover:text-primary-700">wondersheets.art</a>
|
||||||
|
</p>
|
||||||
|
<p>© {new Date().getFullYear()} WonderSheets. All rights reserved.</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -135,6 +135,13 @@ export const Hero = ({ onGenerate, generatedSheet, isGenerating }) => {
|
|||||||
const pdfHeight = (imgProperties.height * pdfWidth) / imgProperties.width;
|
const pdfHeight = (imgProperties.height * pdfWidth) / imgProperties.width;
|
||||||
|
|
||||||
pdf.addImage(data, 'PNG', 0, 0, pdfWidth, pdfHeight);
|
pdf.addImage(data, 'PNG', 0, 0, pdfWidth, pdfHeight);
|
||||||
|
|
||||||
|
// Add watermark at bottom center
|
||||||
|
const pageHeight = pdf.internal.pageSize.getHeight();
|
||||||
|
pdf.setFontSize(10);
|
||||||
|
pdf.setTextColor(150, 150, 150); // Light gray
|
||||||
|
pdf.text('wondersheets.art', pdfWidth / 2, pageHeight - 5, { align: 'center' });
|
||||||
|
|
||||||
return pdf;
|
return pdf;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -190,19 +197,19 @@ export const Hero = ({ onGenerate, generatedSheet, isGenerating }) => {
|
|||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex justify-between items-center px-1">
|
<div className="flex justify-between items-center px-1">
|
||||||
<label className="font-semibold text-slate-700">Age: {age}</label>
|
<label className="font-semibold text-slate-700">Age: {age}</label>
|
||||||
<span className="text-xs font-semibold text-slate-400 uppercase tracking-wider">3 to 7 years</span>
|
<span className="text-xs font-semibold text-slate-400 uppercase tracking-wider">3 to 10 years</span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
min="3"
|
min="3"
|
||||||
max="7"
|
max="10"
|
||||||
value={age}
|
value={age}
|
||||||
disabled={isGenerating}
|
disabled={isGenerating}
|
||||||
onChange={(e) => setAge(parseInt(e.target.value))}
|
onChange={(e) => setAge(parseInt(e.target.value))}
|
||||||
className="w-full h-3 bg-slate-100 rounded-lg appearance-none cursor-pointer accent-primary-600 disabled:opacity-50"
|
className="w-full h-3 bg-slate-100 rounded-lg appearance-none cursor-pointer accent-primary-600 disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
<div className="flex justify-between text-xs text-slate-400 px-1">
|
<div className="flex justify-between text-xs text-slate-400 px-1">
|
||||||
<span>3</span><span>4</span><span>5</span><span>6</span><span>7</span>
|
<span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span><span>10</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user