Skip to content

Commit 623eb83

Browse files
k11kirkycharlesvien
authored andcommitted
feat: light twig styling
1 parent 671bd95 commit 623eb83

File tree

14 files changed

+353
-113
lines changed

14 files changed

+353
-113
lines changed

apps/array/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"@parcel/watcher": "^2.5.1",
9797
"@phosphor-icons/react": "^2.1.10",
9898
"@posthog/agent": "workspace:*",
99+
"@posthog/electron-trpc": "workspace:*",
99100
"@radix-ui/react-collapsible": "^1.1.12",
100101
"@radix-ui/react-icons": "^1.3.2",
101102
"@radix-ui/themes": "^3.2.1",
@@ -125,6 +126,7 @@
125126
"electron-log": "^5.4.3",
126127
"electron-store": "^11.0.0",
127128
"file-icon": "^6.0.0",
129+
"framer-motion": "^12.26.2",
128130
"idb-keyval": "^6.2.2",
129131
"immer": "^11.0.1",
130132
"inversify": "^7.10.6",
@@ -146,7 +148,6 @@
146148
"remark-gfm": "^4.0.1",
147149
"sonner": "^2.0.7",
148150
"tippy.js": "^6.3.7",
149-
"@posthog/electron-trpc": "workspace:*",
150151
"uuid": "^9.0.1",
151152
"vscode-icons-js": "^11.6.1",
152153
"zod": "^4.1.12",

apps/array/src/renderer/App.tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { CursorGlow } from "@components/CursorGlow";
2+
import { LoginTransition } from "@components/LoginTransition";
13
import { MainLayout } from "@components/MainLayout";
24
import { AuthScreen } from "@features/auth/components/AuthScreen";
35
import { useAuthStore } from "@features/auth/stores/authStore";
@@ -6,11 +8,14 @@ import { initializePostHog } from "@renderer/lib/analytics";
68
import { initializeConnectivityStore } from "@renderer/stores/connectivityStore";
79
import { trpcVanilla } from "@renderer/trpc/client";
810
import { toast } from "@utils/toast";
9-
import { useEffect, useState } from "react";
11+
import { AnimatePresence, motion } from "framer-motion";
12+
import { useEffect, useRef, useState } from "react";
1013

1114
function App() {
1215
const { isAuthenticated, initializeOAuth } = useAuthStore();
1316
const [isLoading, setIsLoading] = useState(true);
17+
const [showTransition, setShowTransition] = useState(false);
18+
const wasAuthenticated = useRef(isAuthenticated);
1419

1520
// Initialize PostHog analytics
1621
useEffect(() => {
@@ -36,6 +41,19 @@ function App() {
3641
initializeOAuth().finally(() => setIsLoading(false));
3742
}, [initializeOAuth]);
3843

44+
// Handle auth state change for transition
45+
useEffect(() => {
46+
if (!wasAuthenticated.current && isAuthenticated) {
47+
// User just logged in - trigger transition
48+
setShowTransition(true);
49+
}
50+
wasAuthenticated.current = isAuthenticated;
51+
}, [isAuthenticated]);
52+
53+
const handleTransitionComplete = () => {
54+
setShowTransition(false);
55+
};
56+
3957
if (isLoading) {
4058
return (
4159
<Flex align="center" justify="center" minHeight="100vh">
@@ -47,7 +65,36 @@ function App() {
4765
);
4866
}
4967

50-
return isAuthenticated ? <MainLayout /> : <AuthScreen />;
68+
return (
69+
<>
70+
<CursorGlow />
71+
<AnimatePresence mode="wait">
72+
{!isAuthenticated ? (
73+
<motion.div
74+
key="auth"
75+
initial={{ opacity: 1 }}
76+
exit={{ opacity: 0 }}
77+
transition={{ duration: 0.5 }}
78+
>
79+
<AuthScreen />
80+
</motion.div>
81+
) : (
82+
<motion.div
83+
key="main"
84+
initial={{ opacity: 0 }}
85+
animate={{ opacity: 1 }}
86+
transition={{ duration: 0.5, delay: showTransition ? 1.5 : 0 }}
87+
>
88+
<MainLayout />
89+
</motion.div>
90+
)}
91+
</AnimatePresence>
92+
<LoginTransition
93+
isAnimating={showTransition}
94+
onComplete={handleTransitionComplete}
95+
/>
96+
</>
97+
);
5198
}
5299

53100
export default App;
19.7 KB
Binary file not shown.
1.13 MB
Loading

apps/array/src/renderer/assets/images/twig-logo.svg

Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Campfire } from "@phosphor-icons/react";
2+
import { IconButton, Tooltip } from "@radix-ui/themes";
3+
import { useThemeStore } from "@stores/themeStore";
4+
5+
export function CampfireToggle() {
6+
const { isDarkMode, toggleDarkMode } = useThemeStore();
7+
8+
return (
9+
<Tooltip content={isDarkMode ? "Light mode" : "Dark mode"}>
10+
<IconButton
11+
size="1"
12+
variant="ghost"
13+
onClick={toggleDarkMode}
14+
style={{
15+
color: isDarkMode ? "var(--orange-9)" : "var(--gray-9)",
16+
}}
17+
>
18+
<Campfire size={16} weight={isDarkMode ? "fill" : "regular"} />
19+
</IconButton>
20+
</Tooltip>
21+
);
22+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useThemeStore } from "@stores/themeStore";
2+
import { useEffect, useState } from "react";
3+
4+
export function CursorGlow() {
5+
const isDarkMode = useThemeStore((state) => state.isDarkMode);
6+
const [mousePos, setMousePos] = useState<{ x: number; y: number } | null>(
7+
null,
8+
);
9+
10+
useEffect(() => {
11+
const handleMouseMove = (e: MouseEvent) => {
12+
setMousePos({ x: e.clientX, y: e.clientY });
13+
};
14+
15+
window.addEventListener("mousemove", handleMouseMove);
16+
return () => window.removeEventListener("mousemove", handleMouseMove);
17+
}, []);
18+
19+
// Only show in dark mode
20+
if (!isDarkMode || !mousePos) return null;
21+
22+
return (
23+
<div
24+
style={{
25+
position: "fixed",
26+
left: mousePos.x - 100,
27+
top: mousePos.y - 100,
28+
width: 200,
29+
height: 200,
30+
pointerEvents: "none",
31+
background:
32+
"radial-gradient(circle at center, var(--fire-glow) 0%, transparent 70%)",
33+
zIndex: 9999,
34+
}}
35+
/>
36+
);
37+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { motion } from "framer-motion";
2+
3+
interface LoginTransitionProps {
4+
isAnimating: boolean;
5+
onComplete: () => void;
6+
}
7+
8+
export function LoginTransition({
9+
isAnimating,
10+
onComplete,
11+
}: LoginTransitionProps) {
12+
if (!isAnimating) return null;
13+
14+
return (
15+
<motion.div
16+
style={{
17+
position: "fixed",
18+
inset: 0,
19+
zIndex: 10000,
20+
background: "var(--cave-charcoal)",
21+
}}
22+
initial={{ opacity: 0 }}
23+
animate={{ opacity: 1 }}
24+
transition={{ duration: 0.5 }}
25+
onAnimationComplete={onComplete}
26+
/>
27+
);
28+
}

apps/array/src/renderer/components/StatusBar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CampfireToggle } from "@components/CampfireToggle";
12
import { StatusBarMenu } from "@components/StatusBarMenu";
23
import { Badge, Box, Code, Flex, Kbd } from "@radix-ui/themes";
34
import { useStatusBarStore } from "@stores/statusBarStore";
@@ -43,6 +44,7 @@ export function StatusBar({ showKeyHints = true }: StatusBarProps) {
4344
)}
4445

4546
<Flex align="center" gap="2">
47+
<CampfireToggle />
4648
{IS_DEV && (
4749
<Badge size="1">
4850
<Code size="1" variant="ghost">

0 commit comments

Comments
 (0)