Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e6cecfe27 | ||
|
|
d52ba6373a | ||
|
|
002c2888ac | ||
|
|
5d85e898d6 | ||
|
|
eed890dc81 | ||
|
|
57fabffe60 | ||
|
|
89fb670f93 | ||
|
|
8e51390018 | ||
|
|
e7e54619ae | ||
|
|
9c51cc94ee | ||
|
|
df674426c5 | ||
|
|
24d120004d | ||
|
|
88f57ce6df | ||
|
|
3a5dc0f1c8 | ||
|
|
3fff9ef140 | ||
|
|
ca1c6d8602 | ||
|
|
e6bcf20807 | ||
|
|
1ee25b3dd2 | ||
|
|
468bdebe3a | ||
|
|
2eb3ff3406 | ||
|
|
efbe99a9e2 | ||
|
|
fdc882cb04 | ||
|
|
a7778c648d | ||
|
|
7e2f580877 |
83
CHANGELOG.md
83
CHANGELOG.md
@@ -1,3 +1,86 @@
|
||||
## [4.20.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.6...v4.20.7) (2025-10-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **home:** use Panda CSS token() for dynamic colors and center arrows properly ([d52ba63](https://github.com/antialias/soroban-abacus-flashcards/commit/d52ba6373a4577655dc1e5f5ff4926af7f7d96c3))
|
||||
|
||||
## [4.20.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.5...v4.20.6) (2025-10-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **homepage:** use inline styles for journey level colors ([5d85e89](https://github.com/antialias/soroban-abacus-flashcards/commit/5d85e898d65d44d8d09bee952fad44b5a9c0cd20)), closes [#4ade80](https://github.com/antialias/soroban-abacus-flashcards/issues/4ade80) [#60a5](https://github.com/antialias/soroban-abacus-flashcards/issues/60a5) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78) [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
|
||||
|
||||
## [4.20.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.4...v4.20.5) (2025-10-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **docker:** include Panda CSS styled-system in production image ([57fabff](https://github.com/antialias/soroban-abacus-flashcards/commit/57fabffe605d953b4a4d7e05032401cbf1ab2d14))
|
||||
|
||||
## [4.20.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.3...v4.20.4) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **homepage:** use inline styles for Your Journey text contrast ([8e51390](https://github.com/antialias/soroban-abacus-flashcards/commit/8e5139001818d7013e1b2654ac707f7429316d58)), closes [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#e5e7](https://github.com/antialias/soroban-abacus-flashcards/issues/e5e7) [#9ca3](https://github.com/antialias/soroban-abacus-flashcards/issues/9ca3) [#d1d5](https://github.com/antialias/soroban-abacus-flashcards/issues/d1d5)
|
||||
|
||||
## [4.20.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.2...v4.20.3) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **homepage:** use explicit RGBA colors for Your Journey text ([9c51cc9](https://github.com/antialias/soroban-abacus-flashcards/commit/9c51cc94eec4efcab9c0b9d1190f5b79c0c7d365))
|
||||
|
||||
## [4.20.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.1...v4.20.2) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **homepage:** improve text contrast in Your Journey section ([24d1200](https://github.com/antialias/soroban-abacus-flashcards/commit/24d120004dccecc1ce2f08c1b73eec902868fb23))
|
||||
* **tutorial:** resolve TypeScript errors in TutorialPlayer ([88f57ce](https://github.com/antialias/soroban-abacus-flashcards/commit/88f57ce6df125142d6ea7feec60c475926bd4929))
|
||||
|
||||
## [4.20.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.20.0...v4.20.1) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **homepage:** correct positioning of progression arrows in Your Journey section ([3fff9ef](https://github.com/antialias/soroban-abacus-flashcards/commit/3fff9ef140bf1f462042f8319ed6c5e2a376e4ba))
|
||||
|
||||
|
||||
### Code Refactoring
|
||||
|
||||
* **homepage:** move What You'll Learn above tutorial ([ca1c6d8](https://github.com/antialias/soroban-abacus-flashcards/commit/ca1c6d86029c891e019a96ba161e49b08b5be1bf))
|
||||
|
||||
## [4.20.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.19.0...v4.20.0) (2025-10-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tutorial:** add hideTooltip prop and improve dark mode coaching bar ([1ee25b3](https://github.com/antialias/soroban-abacus-flashcards/commit/1ee25b3dd2f0ee9dd7ed571ba818b7ca5a247f85))
|
||||
|
||||
## [4.19.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.18.1...v4.19.0) (2025-10-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tutorial:** add fill color support for dark mode column posts and reckoning bar ([2eb3ff3](https://github.com/antialias/soroban-abacus-flashcards/commit/2eb3ff340613301df20bf14f5b461371a27d7f05))
|
||||
|
||||
## [4.18.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.18.0...v4.18.1) (2025-10-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tutorial:** use correct customStyles API for dark mode frame styling ([fdc882c](https://github.com/antialias/soroban-abacus-flashcards/commit/fdc882cb046e3d8835fbca59841e9af5329bcc52))
|
||||
|
||||
## [4.18.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.17.2...v4.18.0) (2025-10-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **tutorial:** add dark mode styling for coaching bar and abacus frame ([7e2f580](https://github.com/antialias/soroban-abacus-flashcards/commit/7e2f580877af9d21409f427778fa3569c950fcf5))
|
||||
|
||||
## [4.17.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.17.1...v4.17.2) (2025-10-19)
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,9 @@ RUN adduser --system --uid 1001 nextjs
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./apps/web/.next
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public
|
||||
|
||||
# Copy Panda CSS generated styles
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/styled-system ./apps/web/styled-system
|
||||
|
||||
# Copy server files (compiled from TypeScript)
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/server.js ./apps/web/
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/web/dist ./apps/web/dist
|
||||
|
||||
76
apps/web/.claude/PANDA_CSS_DYNAMIC_TOKENS.md
Normal file
76
apps/web/.claude/PANDA_CSS_DYNAMIC_TOKENS.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Panda CSS Dynamic Token Usage
|
||||
|
||||
## Problem: Dynamic Color Tokens Not Working
|
||||
|
||||
When using Panda CSS, color tokens like `blue.400`, `purple.400`, etc. don't work when used dynamically through variables in the `css()` function.
|
||||
|
||||
## Root Cause
|
||||
|
||||
Panda CSS's `css()` function requires **static values at build time**. It cannot process dynamic token references like:
|
||||
|
||||
```typescript
|
||||
// ❌ This doesn't work
|
||||
const color = 'blue.400'
|
||||
css({ color: color }) // Panda can't resolve this at build time
|
||||
```
|
||||
|
||||
The `css()` function performs static analysis during the build process to generate CSS classes. It cannot handle runtime-dynamic token paths.
|
||||
|
||||
## Solution: Use the `token()` Function
|
||||
|
||||
Panda CSS provides a `token()` function specifically for resolving token paths to their actual values at runtime:
|
||||
|
||||
```typescript
|
||||
import { token } from '../../styled-system/tokens'
|
||||
|
||||
// ✅ This works
|
||||
const stages = [
|
||||
{ level: '10 Kyu', label: 'Beginner', color: 'colors.green.400' },
|
||||
{ level: '5 Kyu', label: 'Intermediate', color: 'colors.blue.400' },
|
||||
{ level: '1 Kyu', label: 'Advanced', color: 'colors.violet.400' },
|
||||
{ level: 'Dan', label: 'Master', color: 'colors.amber.400' },
|
||||
] as const
|
||||
|
||||
// Use with inline styles, not css()
|
||||
<div style={{ color: token(stage.color) }}>
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. **Use `as const`**: TypeScript needs the array marked as `const` so the token strings are treated as literal types, not generic strings. The `token()` function expects the `Token` literal type.
|
||||
|
||||
2. **Use inline styles**: When using `token()`, apply colors via the `style` prop, not through the `css()` function:
|
||||
```typescript
|
||||
// ✅ Correct
|
||||
<div style={{ color: token(stage.color) }}>
|
||||
|
||||
// ❌ Won't work
|
||||
<div className={css({ color: token(stage.color) })}>
|
||||
```
|
||||
|
||||
3. **Static tokens in css()**: For static usage, you CAN use tokens directly in `css()`:
|
||||
```typescript
|
||||
// ✅ This works because it's static
|
||||
css({ color: 'blue.400' })
|
||||
```
|
||||
|
||||
## How token() Works
|
||||
|
||||
The `token()` function:
|
||||
- Takes a token path like `"colors.blue.400"`
|
||||
- Looks it up in the generated token registry (`styled-system/tokens/index.mjs`)
|
||||
- Returns the actual CSS value (e.g., `"#60a5fa"`)
|
||||
- Happens at runtime, not build time
|
||||
|
||||
## Token Type Definition
|
||||
|
||||
The `Token` type is a union of all valid token paths:
|
||||
```typescript
|
||||
type Token = "colors.blue.400" | "colors.green.400" | "colors.violet.400" | ...
|
||||
```
|
||||
|
||||
This is defined in `styled-system/tokens/tokens.d.ts`.
|
||||
|
||||
## Reference Implementation
|
||||
|
||||
See `src/app/page.tsx` lines 404-434 for a working example of dynamic token usage in the "Your Journey" section.
|
||||
@@ -6,6 +6,7 @@ import { TutorialPlayer } from '@/components/tutorial/TutorialPlayer'
|
||||
import { getTutorialForEditor } from '@/utils/tutorialConverter'
|
||||
import { css } from '../../styled-system/css'
|
||||
import { container, grid, hstack, stack } from '../../styled-system/patterns'
|
||||
import { token } from '../../styled-system/tokens'
|
||||
|
||||
export default function HomePage() {
|
||||
// Extract just the "Friends of 5" step (2+3=5) for homepage demo
|
||||
@@ -219,21 +220,12 @@ export default function HomePage() {
|
||||
mx: 'auto',
|
||||
})}
|
||||
>
|
||||
<TutorialPlayer
|
||||
tutorial={friendsOf5Tutorial}
|
||||
isDebugMode={false}
|
||||
showDebugPanel={false}
|
||||
hideNavigation={true}
|
||||
abacusColumns={2}
|
||||
theme="dark"
|
||||
/>
|
||||
|
||||
{/* What you'll learn - below tutorial */}
|
||||
{/* What you'll learn - above tutorial */}
|
||||
<div
|
||||
className={css({
|
||||
mt: '8',
|
||||
pt: '6',
|
||||
borderTop: '1px solid',
|
||||
mb: '8',
|
||||
pb: '6',
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'gray.700',
|
||||
})}
|
||||
>
|
||||
@@ -262,6 +254,16 @@ export default function HomePage() {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TutorialPlayer
|
||||
tutorial={friendsOf5Tutorial}
|
||||
isDebugMode={false}
|
||||
showDebugPanel={false}
|
||||
hideNavigation={true}
|
||||
hideTooltip={true}
|
||||
abacusColumns={2}
|
||||
theme="dark"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -378,9 +380,7 @@ export default function HomePage() {
|
||||
>
|
||||
Your Journey
|
||||
</h2>
|
||||
<p className={css({ color: 'gray.400', fontSize: 'md' })}>
|
||||
Progress from beginner to master
|
||||
</p>
|
||||
<p style={{ color: '#e5e7eb', fontSize: '16px' }}>Progress from beginner to master</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -401,31 +401,53 @@ export default function HomePage() {
|
||||
flexWrap: 'wrap',
|
||||
})}
|
||||
>
|
||||
{[
|
||||
{ level: '10 Kyu', label: 'Beginner', color: 'green.400' },
|
||||
{ level: '5 Kyu', label: 'Intermediate', color: 'blue.400' },
|
||||
{ level: '1 Kyu', label: 'Advanced', color: 'purple.400' },
|
||||
{ level: 'Dan', label: 'Master', color: 'yellow.400' },
|
||||
].map((stage, i) => (
|
||||
<div key={i} className={stack({ gap: '2', textAlign: 'center', flex: '1' })}>
|
||||
{(
|
||||
[
|
||||
{ level: '10 Kyu', label: 'Beginner', color: 'colors.green.400' },
|
||||
{ level: '5 Kyu', label: 'Intermediate', color: 'colors.blue.400' },
|
||||
{ level: '1 Kyu', label: 'Advanced', color: 'colors.violet.400' },
|
||||
{ level: 'Dan', label: 'Master', color: 'colors.amber.400' },
|
||||
] as const
|
||||
).map((stage, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={stack({
|
||||
gap: '2',
|
||||
textAlign: 'center',
|
||||
flex: '1',
|
||||
position: 'relative',
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={css({
|
||||
fontSize: 'xl',
|
||||
fontWeight: 'bold',
|
||||
color: stage.color,
|
||||
})}
|
||||
style={{ color: token(stage.color) }}
|
||||
>
|
||||
{stage.level}
|
||||
</div>
|
||||
<div className={css({ fontSize: 'sm', color: 'gray.400' })}>{stage.label}</div>
|
||||
<div
|
||||
className={css({
|
||||
fontSize: 'sm',
|
||||
color: 'gray.300',
|
||||
})}
|
||||
>
|
||||
{stage.label}
|
||||
</div>
|
||||
{i < 3 && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '100%',
|
||||
marginLeft: '0.5rem',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
fontSize: '20px',
|
||||
color: '#9ca3af',
|
||||
}}
|
||||
className={css({
|
||||
display: { base: 'none', md: 'block' },
|
||||
position: 'absolute',
|
||||
right: '-50%',
|
||||
fontSize: 'xl',
|
||||
color: 'gray.600',
|
||||
})}
|
||||
>
|
||||
→
|
||||
@@ -435,12 +457,14 @@ export default function HomePage() {
|
||||
))}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
fontSize: '14px',
|
||||
color: '#d1d5db',
|
||||
fontStyle: 'italic',
|
||||
}}
|
||||
className={css({
|
||||
mt: '6',
|
||||
textAlign: 'center',
|
||||
fontSize: 'sm',
|
||||
color: 'gray.500',
|
||||
fontStyle: 'italic',
|
||||
})}
|
||||
>
|
||||
You'll progress through all these levels eventually ↑
|
||||
|
||||
@@ -216,6 +216,7 @@ interface TutorialPlayerProps {
|
||||
isDebugMode?: boolean
|
||||
showDebugPanel?: boolean
|
||||
hideNavigation?: boolean
|
||||
hideTooltip?: boolean
|
||||
abacusColumns?: number
|
||||
theme?: 'light' | 'dark'
|
||||
onStepChange?: (stepIndex: number, step: TutorialStep) => void
|
||||
@@ -231,6 +232,7 @@ function TutorialPlayerContent({
|
||||
isDebugMode = false,
|
||||
showDebugPanel = false,
|
||||
hideNavigation = false,
|
||||
hideTooltip = false,
|
||||
abacusColumns = 5,
|
||||
theme = 'light',
|
||||
onStepChange,
|
||||
@@ -437,8 +439,7 @@ function TutorialPlayerContent({
|
||||
const filteredHighlightBeads = useMemo(() => {
|
||||
if (!currentStep.highlightBeads) return undefined
|
||||
return currentStep.highlightBeads.filter((highlight) => {
|
||||
const placeValue = highlight.placeValue ?? 4 - (highlight.columnIndex ?? 0)
|
||||
return placeValue < abacusColumns
|
||||
return highlight.placeValue < abacusColumns
|
||||
})
|
||||
}, [currentStep.highlightBeads, abacusColumns])
|
||||
|
||||
@@ -896,8 +897,8 @@ function TutorialPlayerContent({
|
||||
// Check if this is the correct action
|
||||
if (currentStep.highlightBeads && Array.isArray(currentStep.highlightBeads)) {
|
||||
const isCorrectBead = currentStep.highlightBeads.some((highlight) => {
|
||||
// Get place value from highlight (convert columnIndex to placeValue if needed)
|
||||
const highlightPlaceValue = highlight.placeValue ?? 4 - highlight.columnIndex
|
||||
// Get place value from highlight
|
||||
const highlightPlaceValue = highlight.placeValue
|
||||
// Get place value from bead click event
|
||||
const beadPlaceValue = beadInfo.bead ? beadInfo.bead.placeValue : 4 - beadInfo.columnIndex
|
||||
|
||||
@@ -909,9 +910,10 @@ function TutorialPlayerContent({
|
||||
})
|
||||
|
||||
if (!isCorrectBead) {
|
||||
const errorMessage = "That's not the highlighted bead. Try clicking the highlighted bead."
|
||||
dispatch({
|
||||
type: 'SET_ERROR',
|
||||
error: currentStep.errorMessages.wrongBead,
|
||||
error: errorMessage,
|
||||
})
|
||||
|
||||
dispatch({
|
||||
@@ -919,7 +921,7 @@ function TutorialPlayerContent({
|
||||
event: {
|
||||
type: 'ERROR_OCCURRED',
|
||||
stepId: currentStep.id,
|
||||
error: currentStep.errorMessages.wrongBead,
|
||||
error: errorMessage,
|
||||
timestamp: new Date(),
|
||||
},
|
||||
})
|
||||
@@ -1044,8 +1046,7 @@ function TutorialPlayerContent({
|
||||
if (currentStep.highlightBeads && Array.isArray(currentStep.highlightBeads)) {
|
||||
currentStep.highlightBeads.forEach((highlight) => {
|
||||
// Convert placeValue to columnIndex for AbacusReact compatibility
|
||||
const columnIndex =
|
||||
highlight.placeValue !== undefined ? 4 - highlight.placeValue : highlight.columnIndex
|
||||
const columnIndex = abacusColumns - 1 - highlight.placeValue
|
||||
|
||||
// Skip highlights for columns that don't exist
|
||||
if (columnIndex < minValidColumn) {
|
||||
@@ -1094,8 +1095,32 @@ function TutorialPlayerContent({
|
||||
Object.assign(mergedHighlights[columnIndex], dynamicColumnHighlights[columnIndex])
|
||||
})
|
||||
|
||||
return Object.keys(mergedHighlights).length > 0 ? { columns: mergedHighlights } : undefined
|
||||
}, [currentStep.highlightBeads, dynamicColumnHighlights, abacusColumns])
|
||||
// Build the custom styles object
|
||||
const styles: any = {}
|
||||
|
||||
// Add column highlights if any
|
||||
if (Object.keys(mergedHighlights).length > 0) {
|
||||
styles.columns = mergedHighlights
|
||||
}
|
||||
|
||||
// Add frame styling for dark mode
|
||||
if (theme === 'dark') {
|
||||
// Column dividers (global for all columns)
|
||||
styles.columnPosts = {
|
||||
fill: 'rgba(255, 255, 255, 0.3)', // High contrast fill for visibility
|
||||
stroke: 'rgba(255, 255, 255, 0.2)',
|
||||
strokeWidth: 2,
|
||||
}
|
||||
// Reckoning bar (horizontal middle bar)
|
||||
styles.reckoningBar = {
|
||||
fill: 'rgba(255, 255, 255, 0.4)', // High contrast fill for visibility
|
||||
stroke: 'rgba(255, 255, 255, 0.25)',
|
||||
strokeWidth: 3,
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(styles).length > 0 ? styles : undefined
|
||||
}, [currentStep.highlightBeads, dynamicColumnHighlights, abacusColumns, theme])
|
||||
|
||||
if (!currentStep) {
|
||||
return <div>No steps available</div>
|
||||
@@ -1115,9 +1140,9 @@ function TutorialPlayerContent({
|
||||
<div
|
||||
className={css({
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'gray.200',
|
||||
borderColor: theme === 'dark' ? 'rgba(255, 255, 255, 0.1)' : 'gray.200',
|
||||
p: 4,
|
||||
bg: 'white',
|
||||
bg: theme === 'dark' ? 'rgba(30, 30, 40, 0.6)' : 'white',
|
||||
})}
|
||||
>
|
||||
<div
|
||||
@@ -1386,7 +1411,8 @@ function TutorialPlayerContent({
|
||||
</div>
|
||||
|
||||
{/* Multi-step instructions panel */}
|
||||
{currentStep.multiStepInstructions &&
|
||||
{!hideTooltip &&
|
||||
currentStep.multiStepInstructions &&
|
||||
currentStep.multiStepInstructions.length > 0 && (
|
||||
<div
|
||||
className={css({
|
||||
@@ -1522,7 +1548,10 @@ function TutorialPlayerContent({
|
||||
className={css({
|
||||
mb: 1,
|
||||
fontWeight: 'bold',
|
||||
color: 'yellow.900',
|
||||
color: theme === 'dark' ? 'yellow.200' : 'yellow.900',
|
||||
textShadow:
|
||||
theme === 'dark' ? '0 0 12px rgba(251, 191, 36, 0.4)' : 'none',
|
||||
fontSize: theme === 'dark' ? 'lg' : 'base',
|
||||
})}
|
||||
>
|
||||
{currentInstruction}
|
||||
@@ -1640,7 +1669,7 @@ function TutorialPlayerContent({
|
||||
</div>
|
||||
|
||||
{/* Tooltip */}
|
||||
{currentStep.tooltip && (
|
||||
{!hideTooltip && currentStep.tooltip && (
|
||||
<div
|
||||
className={css({
|
||||
maxW: '500px',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "4.17.2",
|
||||
"version": "4.20.7",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface BeadStyle {
|
||||
}
|
||||
|
||||
export interface ColumnPostStyle {
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
strokeWidth?: number;
|
||||
opacity?: number;
|
||||
@@ -34,6 +35,7 @@ export interface ColumnPostStyle {
|
||||
}
|
||||
|
||||
export interface ReckoningBarStyle {
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
strokeWidth?: number;
|
||||
opacity?: number;
|
||||
@@ -1979,7 +1981,10 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
|
||||
const columnStyles = customStyles?.columns?.[colIndex];
|
||||
const globalColumnPosts = customStyles?.columnPosts;
|
||||
const rodStyle = {
|
||||
fill: "rgb(0, 0, 0, 0.1)", // Default Typst color
|
||||
fill:
|
||||
columnStyles?.columnPost?.fill ||
|
||||
globalColumnPosts?.fill ||
|
||||
"rgb(0, 0, 0, 0.1)", // Default Typst color
|
||||
stroke:
|
||||
columnStyles?.columnPost?.stroke ||
|
||||
globalColumnPosts?.stroke ||
|
||||
@@ -2017,8 +2022,10 @@ export const AbacusReact: React.FC<AbacusConfig> = ({
|
||||
(effectiveColumns - 1) * dimensions.rodSpacing + dimensions.beadSize
|
||||
}
|
||||
height={dimensions.barThickness}
|
||||
fill="black" // Typst uses black
|
||||
stroke="none"
|
||||
fill={customStyles?.reckoningBar?.fill || "black"} // Typst default is black
|
||||
stroke={customStyles?.reckoningBar?.stroke || "none"}
|
||||
strokeWidth={customStyles?.reckoningBar?.strokeWidth ?? 0}
|
||||
opacity={customStyles?.reckoningBar?.opacity ?? 1}
|
||||
/>
|
||||
|
||||
{/* Beads */}
|
||||
|
||||
Reference in New Issue
Block a user