Compare commits

...

8 commits

Author SHA1 Message Date
Jan-Henrik Bruhn
ea879640a2
Merge pull request #26 from jhbruhn/fix/skeleton-fixes
Some checks failed
Build, Test, and Lint / Build, Test, and Lint (push) Has been cancelled
Draft Release / Draft Release (push) Has been cancelled
Draft Release / Build Web App (push) Has been cancelled
Draft Release / Build Release - macos-latest (push) Has been cancelled
Draft Release / Build Release - ubuntu-latest (push) Has been cancelled
Draft Release / Build Release - windows-latest (push) Has been cancelled
Draft Release / Upload to GitHub Release (push) Has been cancelled
Fix: skeleton fixes and upload button disable logic
2025-12-22 12:06:00 +01:00
943f117191 style: Apply linter auto-fixes
Add missing semicolons and adjust line breaks per ESLint rules.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 12:03:49 +01:00
5aa4e15922 fix: Improve destructive Alert variant styling
Update the destructive variant to use proper danger colors (light red background with dark red text in light mode, dark red background with light text in dark mode) instead of the previous white background with red text.

This allows semantic use of variant="destructive" throughout the app without custom styling overrides.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 12:00:54 +01:00
4593b66356 fix: Restore correct destructive variant colors
Swap destructive and destructive-foreground colors back to correct values. The previous commit accidentally reversed them, causing error states to show white background with red text instead of red background with white text.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 11:59:02 +01:00
469d9860de fix: Apply chart/catalogNumber duplicate detection to all components
Extend the duplicate detection logic from PatternCanvas to ProgressMonitor and PatternInfo. Now all components only show the chart field when it differs from catalogNumber, preventing redundant information display.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 11:54:30 +01:00
6e38ba855c fix: Prevent button activation during post-upload state synchronization
Fix the Choose File button remaining clickable during the brief window between upload completion and pattern info retrieval. The issue was that labels don't support the disabled attribute, so when using asChild with a label, the disabled state was ignored.

Changes:
- Only use asChild when button is enabled (labels can't be disabled)
- Keep input and button disabled conditions synchronized
- Add uploadProgress check to prevent re-enabling before patternUploaded is true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 11:52:18 +01:00
b995eb898e fix: Update PatternInfoSkeleton to match actual PatternInfo layout
Replace generic key-value skeleton with a proper representation that matches the actual PatternInfo component structure:
- Three-column grid for Size, Stitches, and Colors stats
- Separator line between sections
- Color swatches row with circular placeholders

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 11:11:47 +01:00
9337fdf347 fix: Adjust shadcn config 2025-12-22 11:07:20 +01:00
12 changed files with 98 additions and 28 deletions

View file

@ -4,18 +4,19 @@
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"config": "tailwind.config.js",
"css": "src/App.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "lucide",
"aliases": {
"components": "src/components",
"utils": "src/lib/utils",
"ui": "src/components/ui",
"lib": "src/lib",
"hooks": "src/hooks"
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
"registries": {}
}

10
package-lock.json generated
View file

@ -32,6 +32,7 @@
"react-konva": "^19.2.1",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tailwindcss-animate": "^1.0.7",
"tw-animate-css": "^1.4.0",
"update-electron-app": "^3.1.2",
"zustand": "^5.0.9"
@ -16685,6 +16686,15 @@
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
"license": "MIT"
},
"node_modules/tailwindcss-animate": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
"integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
"license": "MIT",
"peerDependencies": {
"tailwindcss": ">=3.0.0 || insiders"
}
},
"node_modules/tapable": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",

View file

@ -45,6 +45,7 @@
"react-konva": "^19.2.1",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tailwindcss-animate": "^1.0.7",
"tw-animate-css": "^1.4.0",
"update-electron-app": "^3.1.2",
"zustand": "^5.0.9"

View file

@ -1,4 +1,6 @@
@import "tailwindcss";
@plugin "tailwindcss-animate";
@import "tw-animate-css";
/* ============================================

View file

@ -256,16 +256,34 @@ export function FileUpload() {
onChange={handleFileChange}
id="file-input"
className="hidden"
disabled={isLoading || patternUploaded || isUploading}
disabled={
isLoading ||
patternUploaded ||
isUploading ||
(uploadProgress > 0 && !patternUploaded)
}
/>
<Button
asChild={!fileService.hasNativeDialogs()}
asChild={
!fileService.hasNativeDialogs() &&
!(
isLoading ||
patternUploaded ||
isUploading ||
(uploadProgress > 0 && !patternUploaded)
)
}
onClick={
fileService.hasNativeDialogs()
? () => handleFileChange()
: undefined
}
disabled={isLoading || patternUploaded || isUploading}
disabled={
isLoading ||
patternUploaded ||
isUploading ||
(uploadProgress > 0 && !patternUploaded)
}
variant="outline"
className="flex-[2]"
>
@ -289,7 +307,10 @@ export function FileUpload() {
)}
</>
) : (
<label htmlFor="file-input" className="flex items-center gap-2">
<label
htmlFor="file-input"
className="flex items-center gap-2 cursor-pointer"
>
{isLoading ? (
<>
<Loader2 className="w-3.5 h-3.5 animate-spin" />
@ -386,11 +407,8 @@ export function FileUpload() {
)}
{pesData && boundsCheck.error && (
<Alert
variant="destructive"
className="bg-danger-100 dark:bg-danger-900/20 border-danger-200 dark:border-danger-800"
>
<AlertDescription className="text-danger-800 dark:text-danger-200 text-sm">
<Alert variant="destructive">
<AlertDescription>
<strong>Pattern too large:</strong> {boundsCheck.error}
</AlertDescription>
</Alert>

View file

@ -117,7 +117,13 @@ export function PatternInfo({
.join(" ");
// Secondary metadata: chart and description
const secondaryMetadata = [color.chart, color.description]
// Only show chart if it's different from catalogNumber
const secondaryMetadata = [
color.chart && color.chart !== color.catalogNumber
? color.chart
: null,
color.description,
]
.filter(Boolean)
.join(" ");

View file

@ -281,8 +281,13 @@ export function ProgressMonitor() {
.join(" ");
// Secondary metadata: chart and description
// Only show chart if it's different from catalogNumber
const secondaryMetadata = [
block.threadChart,
block.threadChart &&
block.threadChart !==
block.threadCatalogNumber
? block.threadChart
: null,
block.threadDescription,
]
.filter(Boolean)

View file

@ -65,16 +65,33 @@ export function PatternCanvasSkeleton() {
export function PatternInfoSkeleton() {
return (
<div className="mt-4">
<SkeletonLoader className="h-6 w-40 mb-4" variant="text" />
<div className="bg-gray-200 dark:bg-gray-900 p-4 rounded-lg space-y-3">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="flex justify-between">
<SkeletonLoader className="h-4 w-24" variant="text" />
<SkeletonLoader className="h-4 w-32" variant="text" />
<div className="mb-3">
{/* Three column grid matching PatternInfo stats */}
<div className="grid grid-cols-3 gap-2 text-xs mb-2">
{[1, 2, 3].map((i) => (
<div key={i} className="bg-gray-200 dark:bg-gray-700/50 p-2 rounded">
<SkeletonLoader className="h-3 w-12 mb-1" variant="text" />
<SkeletonLoader className="h-4 w-16" variant="text" />
</div>
))}
</div>
{/* Separator */}
<div className="h-px bg-gray-200 dark:bg-gray-700 mb-3" />
{/* Color swatches row */}
<div className="flex items-center gap-2 mb-2">
<SkeletonLoader className="h-3 w-12" variant="text" />
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((i) => (
<SkeletonLoader
key={i}
className="w-3 h-3 rounded-full"
variant="circle"
/>
))}
</div>
</div>
</div>
);
}

View file

@ -10,7 +10,7 @@ const alertVariants = cva(
variant: {
default: "bg-card text-card-foreground",
destructive:
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
"bg-danger-100 dark:bg-danger-900/20 border-danger-200 dark:border-danger-800 text-danger-900 dark:text-danger-100 [&>svg]:text-current *:data-[slot=alert-description]:text-danger-900 dark:*:data-[slot=alert-description]:text-danger-100",
},
},
defaultVariants: {

View file

@ -1,4 +1,4 @@
import { type ClassValue, clsx } from "clsx";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {

View file

@ -1,6 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"module": "commonjs",
"outDir": "dist-electron",
"types": ["node"]

View file

@ -3,5 +3,11 @@
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
],
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}