tangled
alpha
login
or
join now
e.xyehr.cn
/
One-Calendar
5
fork
atom
One Calendar is a privacy-first calendar web app built with Next.js. It has modern security features, including e2ee, password-protected sharing, and self-destructing share links ๐
calendar.xyehr.cn
5
fork
atom
overview
issues
pulls
pipelines
Update hero reveal animation and encrypted comparison demo
Evan Huang
3 weeks ago
6fe73a7f
c55d62c3
+54
-42
3 changed files
expand all
collapse all
unified
split
app
globals.css
components
landing
landing-hero-demo.tsx
landing-hero.tsx
+17
app/globals.css
···
10
10
.text-balance {
11
11
text-wrap: balance;
12
12
}
13
13
+
14
14
+
.landing-hero-reveal {
15
15
+
animation: landing-hero-reveal 900ms cubic-bezier(0.22, 1, 0.36, 1) both;
16
16
+
}
17
17
+
}
18
18
+
19
19
+
@keyframes landing-hero-reveal {
20
20
+
from {
21
21
+
opacity: 0;
22
22
+
filter: blur(12px);
23
23
+
transform: translateY(10px);
24
24
+
}
25
25
+
to {
26
26
+
opacity: 1;
27
27
+
filter: blur(0);
28
28
+
transform: translateY(0);
29
29
+
}
13
30
}
14
31
15
32
@layer components {
+33
-38
components/landing/landing-hero-demo.tsx
···
1
1
"use client";
2
2
3
3
+
import { Fragment } from "react";
3
4
import { cn } from "@/lib/utils";
4
5
5
6
type DemoEvent = {
···
38
39
},
39
40
];
40
41
41
41
-
const dayColumns = ["Mon", "Tue", "Wed", "Thu", "Fri"];
42
42
+
const encryptedRows = [
43
43
+
{
44
44
+
cipher: "A9F4-77C1-98D2-E31B",
45
45
+
plain: "Project roadmap planning",
46
46
+
},
47
47
+
{
48
48
+
cipher: "7B22-4D11-C0EF-6A8A",
49
49
+
plain: "Design review with team",
50
50
+
},
51
51
+
{
52
52
+
cipher: "EE91-23AA-44B8-90F2",
53
53
+
plain: "Focus block: implementation",
54
54
+
},
55
55
+
];
42
56
43
57
function WeekViewEventBlock({ event }: { event: DemoEvent }) {
44
58
return (
···
61
75
<div className="mt-6 grid gap-4 lg:grid-cols-[1.2fr_1fr]">
62
76
<div className="rounded-xl border border-white/10 bg-[var(--landing-panel)] p-4">
63
77
<p className="mb-3 text-xs uppercase tracking-[0.14em] text-[var(--landing-subtle)]">Week View</p>
64
64
-
<div className="grid grid-cols-5 gap-2">
65
65
-
{dayColumns.map((day) => (
66
66
-
<div key={day} className="rounded-md border border-white/10 bg-black/20 p-2 text-center text-xs text-[var(--landing-muted)]">
67
67
-
{day}
68
68
-
</div>
69
69
-
))}
70
70
-
</div>
71
71
-
<div className="mt-3 space-y-2">
78
78
+
<div className="space-y-2">
72
79
{demoEvents.map((event) => (
73
80
<WeekViewEventBlock key={event.id} event={event} />
74
81
))}
···
76
83
</div>
77
84
78
85
<div className="rounded-xl border border-white/10 bg-[var(--landing-panel)] p-4">
79
79
-
<p className="mb-3 text-xs uppercase tracking-[0.14em] text-[var(--landing-subtle)]">Planning Insights</p>
80
80
-
<div className="space-y-3">
81
81
-
<div>
82
82
-
<div className="mb-1 flex items-center justify-between text-xs text-[var(--landing-muted)]">
83
83
-
<span>Focus time</span>
84
84
-
<span>68%</span>
85
85
-
</div>
86
86
-
<div className="h-2 rounded-full bg-white/10">
87
87
-
<div className="h-2 w-[68%] rounded-full bg-white/80" />
88
88
-
</div>
89
89
-
</div>
90
90
-
<div>
91
91
-
<div className="mb-1 flex items-center justify-between text-xs text-[var(--landing-muted)]">
92
92
-
<span>Meetings</span>
93
93
-
<span>22%</span>
94
94
-
</div>
95
95
-
<div className="h-2 rounded-full bg-white/10">
96
96
-
<div className="h-2 w-[22%] rounded-full bg-white/60" />
97
97
-
</div>
98
98
-
</div>
99
99
-
<div>
100
100
-
<div className="mb-1 flex items-center justify-between text-xs text-[var(--landing-muted)]">
101
101
-
<span>Buffer</span>
102
102
-
<span>10%</span>
103
103
-
</div>
104
104
-
<div className="h-2 rounded-full bg-white/10">
105
105
-
<div className="h-2 w-[10%] rounded-full bg-white/50" />
106
106
-
</div>
107
107
-
</div>
86
86
+
<p className="mb-3 text-xs uppercase tracking-[0.14em] text-[var(--landing-subtle)]">Encrypted vs Plain</p>
87
87
+
<div className="grid grid-cols-[1fr_auto_1fr] gap-3 text-xs text-[var(--landing-muted)]">
88
88
+
<div className="mb-1 uppercase tracking-[0.12em]">Encrypted</div>
89
89
+
<div className="opacity-0">|</div>
90
90
+
<div className="mb-1 uppercase tracking-[0.12em]">Readable</div>
91
91
+
92
92
+
{encryptedRows.map((row) => (
93
93
+
<Fragment key={row.cipher}>
94
94
+
<div className="rounded-md border border-white/10 bg-black/20 px-2 py-2 font-mono text-[11px] text-white/75">
95
95
+
{row.cipher}
96
96
+
</div>
97
97
+
<div className="w-px bg-white/20" />
98
98
+
<div className="rounded-md border border-white/10 bg-black/10 px-2 py-2 text-[11px] text-white/85">
99
99
+
{row.plain}
100
100
+
</div>
101
101
+
</Fragment>
102
102
+
))}
108
103
</div>
109
104
</div>
110
105
</div>
+4
-4
components/landing/landing-hero.tsx
···
4
4
return (
5
5
<section id="top" className="py-14 md:py-20">
6
6
<div className="mx-auto max-w-4xl text-center">
7
7
-
<h1 className="text-3xl font-semibold leading-tight tracking-tight text-white md:text-5xl">
8
8
-
Plan smarter.
7
7
+
<h1 className="landing-hero-reveal text-4xl font-semibold leading-tight tracking-tight text-white md:text-[56px]">
8
8
+
The calendar that keeps
9
9
<br />
10
10
-
Ship faster.
10
10
+
your life private
11
11
</h1>
12
12
<p className="mx-auto mt-5 max-w-2xl text-sm text-[var(--landing-muted)] md:text-base">
13
13
-
One Calendar keeps planning clear, collaborative, and calm across your product workflow.
13
13
+
Secure by design. Powerful by default.
14
14
</p>
15
15
<div className="mt-8 flex justify-center gap-3">
16
16
<a href="/sign-up" aria-label="Get started" className="rounded-md bg-white px-5 py-2.5 text-sm font-medium text-black transition duration-200 hover:-translate-y-0.5 hover:brightness-110">