Skip to content

Commit 868fdb6

Browse files
committed
update components, add welcome screen, fixed some display logic
1 parent 303bbe0 commit 868fdb6

9 files changed

Lines changed: 300 additions & 45 deletions

File tree

app/globals.css

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,59 @@
115115
}
116116
}
117117

118+
@keyframes float {
119+
0%,
120+
100% {
121+
transform: translateY(0px) rotate(0deg);
122+
}
123+
50% {
124+
transform: translateY(-30px) rotate(5deg);
125+
}
126+
}
127+
128+
@keyframes gradientPulse {
129+
0%,
130+
100% {
131+
color: #f42f5f;
132+
transform: scale(1);
133+
opacity: 0.6;
134+
filter: drop-shadow(0 0 2rem rgba(244, 47, 95, 0.4));
135+
}
136+
50% {
137+
color: #fe8d5c;
138+
transform: scale(1.15);
139+
opacity: 1;
140+
filter: drop-shadow(0 0 4rem rgba(254, 141, 92, 0.6));
141+
}
142+
}
143+
144+
@keyframes slideUp {
145+
from {
146+
opacity: 0;
147+
transform: translateY(20px);
148+
}
149+
to {
150+
opacity: 1;
151+
transform: translateY(0);
152+
}
153+
}
154+
155+
.animate-float {
156+
animation: float 8s ease-in-out infinite;
157+
}
158+
159+
.animate-gradient-pulse {
160+
animation: gradientPulse 3s ease-in-out infinite;
161+
}
162+
163+
.animate-slide-up {
164+
animation: slideUp 0.5s ease-out;
165+
}
166+
167+
.animate-cursor-blink {
168+
animation: cursorBlink 1s step-end infinite;
169+
}
170+
118171
/* Sonner Toast Custom Styling */
119172
[data-sonner-toast][data-type="success"] {
120173
background-color: rgb(240 253 244) !important; /* bg-green-50 */

app/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import SocketGenerator from "@/components/socket-generator";
1+
import AppWrapper from "@/components/app-wrapper";
22

33
export default function Home() {
4-
return <SocketGenerator />;
4+
return <AppWrapper />;
55
}

components/app-wrapper.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/**
2+
* ========================================
3+
* APP WRAPPER COMPONENT
4+
* ========================================
5+
* Client-side wrapper that handles welcome screen logic.
6+
* This keeps app/page.tsx clean as a server component entry point.
7+
*
8+
* Responsibilities:
9+
* - Check localStorage for welcome screen state
10+
* - Manage welcome screen display/hide
11+
* - Prevent hydration mismatches
12+
*/
13+
14+
"use client";
15+
16+
import React, { useState, useEffect } from "react";
17+
import SocketGenerator from "@/components/socket-generator";
18+
import WelcomeScreen from "@/components/welcome-screen";
19+
20+
export default function AppWrapper() {
21+
const [showWelcome, setShowWelcome] = useState(false);
22+
const [isLoading, setIsLoading] = useState(true);
23+
24+
useEffect(() => {
25+
// Check localStorage to see if user has seen welcome screen
26+
const hasSeenWelcome = localStorage.getItem(
27+
"socket-generator-has-seen-welcome"
28+
);
29+
if (hasSeenWelcome !== "true") {
30+
setShowWelcome(true);
31+
}
32+
setIsLoading(false);
33+
}, []);
34+
35+
const handleWelcomeClose = () => {
36+
setShowWelcome(false);
37+
// Save that user has seen welcome screen
38+
localStorage.setItem("socket-generator-has-seen-welcome", "true");
39+
};
40+
41+
// Show loading state briefly to prevent hydration mismatch
42+
if (isLoading) {
43+
return (
44+
<div className="flex h-screen w-screen bg-[#0a0a0a] items-center justify-center">
45+
<div className="opacity-0">
46+
<SocketGenerator />
47+
</div>
48+
</div>
49+
);
50+
}
51+
52+
// Show welcome screen first time
53+
if (showWelcome) {
54+
return <WelcomeScreen onClose={handleWelcomeClose} />;
55+
}
56+
57+
// Show main application
58+
return <SocketGenerator />;
59+
}

components/control-panel.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ export default function ControlPanel({
614614
<div className="relative">
615615
<Input
616616
type="text"
617+
placeholder="40.0"
617618
value={plateInputs[plate.id]?.width || ""}
618619
onFocus={() => {
619620
setSelectedPlateInput(`${plate.id}-width`);
@@ -661,6 +662,7 @@ export default function ControlPanel({
661662
<div className="relative">
662663
<Input
663664
type="text"
665+
placeholder="40.0"
664666
value={plateInputs[plate.id]?.height || ""}
665667
onFocus={() => {
666668
setSelectedPlateInput(`${plate.id}-height`);
@@ -718,13 +720,14 @@ export default function ControlPanel({
718720

719721
{/* Add plate item button */}
720722
<div className="flex justify-end mt-4 mb-8">
721-
<button
723+
<Button
722724
onClick={addPlate}
723-
className="w-fit px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
725+
size={undefined}
726+
className="w-fit h-auto px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
724727
>
725728
Rückwand hinzufügen
726729
<Plus className="h-4 w-4 stroke-[3] text-green-500 hover:text-green-600 transition-colors" />
727-
</button>
730+
</Button>
728731
</div>
729732
</div>
730733
</div>
@@ -1040,7 +1043,8 @@ export default function ControlPanel({
10401043
<div className="flex justify-end mt-4 mb-8">
10411044
<Button
10421045
onClick={handleConfirmSocketGroup}
1043-
className="w-fit px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
1046+
size={undefined}
1047+
className="w-fit h-auto px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
10441048
>
10451049
Steckdose bestätigen
10461050
</Button>
@@ -1133,7 +1137,8 @@ export default function ControlPanel({
11331137
<div className="flex justify-end mt-4 mb-4">
11341138
<Button
11351139
onClick={handleAddSocketGroup}
1136-
className="w-fit px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
1140+
size={undefined}
1141+
className="w-fit h-auto px-6 py-2.5 bg-green-50 border-2 border-green-300 text-green-500 font-semibold rounded-lg flex items-center justify-center gap-2 transition-colors hover:bg-green-200 hover:text-green-600 shadow-lg active:bg-green-300 active:text-green-700"
11371142
>
11381143
Steckdose hinzufügen
11391144
</Button>

components/plate-canvas.tsx

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -384,36 +384,48 @@ const PlateCanvas = forwardRef<HTMLDivElement, PlateCanvasProps>(
384384
})}
385385
</div>
386386
{/* Plate dimensions label */}
387-
<div className="text-xs text-gray-400">
388-
Rückwand {plates.findIndex((p) => p.id === plate.id) + 1}:{" "}
389-
{plate.width.toFixed(1)} x {plate.height.toFixed(1)} cm
390-
</div>
387+
{/* When selectedPlate is set, show "Rückwand" prefix only for selected plate */}
388+
{/* When selectedPlate is empty, show all plates without "Rückwand" prefix */}
389+
{(!selectedPlate || selectedPlate === plate.id) && (
390+
<div className="text-xs text-gray-400">
391+
{selectedPlate === plate.id ? "Rückwand " : ""}
392+
{plates.findIndex((p) => p.id === plate.id) + 1}:{" "}
393+
{plate.width.toFixed(1)} x {plate.height.toFixed(1)} cm
394+
</div>
395+
)}
391396
{/* Socket group positions - only show when single plate is selected */}
392397
{isSinglePlate && plateSocketGroups.length > 0 && (
393-
<div className="mt-2 max-h-32 overflow-y-auto space-y-1">
394-
{plateSocketGroups.map((sg, idx) => {
395-
const isDragging = dragState?.socketGroupId === sg.id;
396-
// Use live drag values if dragging, otherwise use stored position values
397-
const positionX =
398-
isDragging && dragState?.liveDistanceX !== undefined
399-
? dragState.liveDistanceX
400-
: sg.positionX;
401-
const positionY =
402-
isDragging && dragState?.liveDistanceY !== undefined
403-
? dragState.liveDistanceY
404-
: sg.positionY;
405-
return (
406-
<div
407-
key={sg.id}
408-
className={`text-[10px] sm:text-xs text-gray-400 ${
409-
isDragging ? "text-green-400 font-semibold" : ""
410-
}`}
411-
>
412-
Steckdosengr. {idx + 1}: X: {positionX.toFixed(1)}{" "}
413-
cm | Y: {positionY.toFixed(1)} cm
414-
</div>
415-
);
416-
})}
398+
<div className="mt-2">
399+
{/* Title for socket groups */}
400+
<div className="text-[10px] sm:text-xs text-gray-400 font-medium text-center mb-1">
401+
Steckdosengr.
402+
</div>
403+
{/* List of socket group positions */}
404+
<div className="max-h-32 overflow-y-auto space-y-1 text-center">
405+
{plateSocketGroups.map((sg, idx) => {
406+
const isDragging = dragState?.socketGroupId === sg.id;
407+
// Use live drag values if dragging, otherwise use stored position values
408+
const positionX =
409+
isDragging && dragState?.liveDistanceX !== undefined
410+
? dragState.liveDistanceX
411+
: sg.positionX;
412+
const positionY =
413+
isDragging && dragState?.liveDistanceY !== undefined
414+
? dragState.liveDistanceY
415+
: sg.positionY;
416+
return (
417+
<div
418+
key={sg.id}
419+
className={`text-[10px] sm:text-xs text-gray-400 ${
420+
isDragging ? "text-green-400 font-semibold" : ""
421+
}`}
422+
>
423+
{idx + 1}: X: {positionX.toFixed(1)} cm | Y:{" "}
424+
{positionY.toFixed(1)} cm
425+
</div>
426+
);
427+
})}
428+
</div>
417429
</div>
418430
)}
419431
</div>

components/socket-generator.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,12 @@ export default function SocketGenerator() {
931931
setPlates((prev) => prev.filter((p) => p.id !== plateId));
932932
setSocketGroups((prev) => prev.filter((sg) => sg.plateId !== plateId));
933933

934+
// If the deleted plate was selected, reset selection to show all plates
935+
if (selectedPlate === plateId) {
936+
setSelectedPlate("");
937+
setSelectedSocketGroup(null);
938+
}
939+
934940
// Show success toast notification with plate details
935941
if (deletedPlate) {
936942
toast.success("Rückwand gelöscht", {
@@ -1015,8 +1021,9 @@ export default function SocketGenerator() {
10151021
const handleAddSocketGroup = () => {
10161022
// Reset selection to allow adding a NEW socket group (not editing an existing one)
10171023
setSelectedSocketGroup(null);
1018-
// Find the first valid plate (40x40cm or larger) to set as default selection
1019-
setSelectedPlate(plates.find(isPlateLargeEnoughForSockets)?.id || "");
1024+
// Reset selectedPlate to empty string to show all plates (like toggle-on behavior)
1025+
// This displays all plates with socket groups on canvas instead of a single selected plate
1026+
setSelectedPlate("");
10201027
// Reset all configuration fields to default values
10211028
setSocketCount(1);
10221029
setSocketDirection("vertical");
@@ -1790,10 +1797,9 @@ export default function SocketGenerator() {
17901797

17911798
{/* Mobile/Tablet sidebar overlay from right */}
17921799
<div
1793-
className={`xl:hidden fixed top-0 right-0 h-full z-50 overflow-x-hidden transition-transform duration-300 ease-out bg-white text-black shadow-2xl ${
1800+
className={`xl:hidden fixed top-0 right-0 h-full z-50 overflow-x-hidden transition-transform duration-300 ease-out bg-white text-black shadow-2xl w-[80vw] ${
17941801
isSidebarOpen ? "translate-x-0" : "translate-x-full"
17951802
}`}
1796-
style={{ width: "80vw" }}
17971803
onClick={(e) => e.stopPropagation()}
17981804
>
17991805
<div className="h-full overflow-y-auto">

0 commit comments

Comments
 (0)