tangled
alpha
login
or
join now
t1c.dev
/
rocksky
forked from
rocksky.app/rocksky
2
fork
atom
A decentralized music tracking and discovery platform built on AT Protocol 🎵
2
fork
atom
overview
issues
pulls
pipelines
add link to Rocksky's tangled repo
tsiry-sandratraina.com
5 months ago
907b627b
7543c478
+210
-203
1 changed file
expand all
collapse all
unified
split
apps
web
src
layouts
Main.tsx
+210
-203
apps/web/src/layouts/Main.tsx
···
51
`;
52
53
export type MainProps = {
54
-
children: React.ReactNode;
55
-
withRightPane?: boolean;
56
};
57
58
function Main(props: MainProps) {
59
-
const { children } = props;
60
-
const withRightPane = props.withRightPane ?? true;
61
-
const [handle, setHandle] = useState("");
62
-
const jwt = localStorage.getItem("token");
63
-
const profile = useAtomValue(profileAtom);
64
-
const [token, setToken] = useState<string | null>(null);
65
-
const { did, cli } = useSearch({ strict: false });
66
67
-
useEffect(() => {
68
-
if (did && did !== "null") {
69
-
localStorage.setItem("did", did);
70
71
-
const fetchToken = async () => {
72
-
try {
73
-
const response = await fetch(`${API_URL}/token`, {
74
-
method: "GET",
75
-
headers: {
76
-
"session-did": did,
77
-
},
78
-
});
79
-
const data = await response.json();
80
-
localStorage.setItem("token", data.token);
81
-
setToken(data.token);
82
83
-
if (cli) {
84
-
await fetch("http://localhost:6996/token", {
85
-
method: "POST",
86
-
headers: {
87
-
"Content-Type": "application/json",
88
-
},
89
-
body: JSON.stringify({ token: data.token }),
90
-
});
91
-
}
92
93
-
if (!jwt && data.token) {
94
-
window.location.href = "/";
95
-
}
96
-
} catch (e) {
97
-
console.error(e);
98
-
}
99
-
};
100
-
fetchToken();
101
-
}
102
-
// eslint-disable-next-line react-hooks/exhaustive-deps
103
-
}, []);
104
105
-
useProfile(token || localStorage.getItem("token"));
106
107
-
const onLogin = async () => {
108
-
if (!handle.trim()) {
109
-
return;
110
-
}
111
112
-
if (API_URL.includes("localhost")) {
113
-
window.location.href = `${API_URL}/login?handle=${handle}`;
114
-
return;
115
-
}
116
117
-
window.location.href = `https://rocksky.pages.dev/loading?handle=${handle}`;
118
-
};
119
120
-
return (
121
-
<Container className="bg-[var(--color-background)] text-[var(--color-text)]">
122
-
<ToasterContainer
123
-
placement={PLACEMENT.top}
124
-
overrides={{
125
-
ToastBody: {
126
-
style: {
127
-
zIndex: 2,
128
-
boxShadow: "none",
129
-
},
130
-
},
131
-
}}
132
-
/>
133
-
<Flex style={{ width: withRightPane ? "770px" : "1090px" }}>
134
-
<Navbar />
135
-
<div
136
-
style={{
137
-
position: "relative",
138
-
}}
139
-
>
140
-
{children}
141
-
</div>
142
-
</Flex>
143
-
{withRightPane && (
144
-
<RightPane className="relative w-[300px]">
145
-
<div className="fixed top-[100px] w-[300px] bg-white p-[20px]">
146
-
<div className="mb-[30px]">
147
-
<Search />
148
-
</div>
149
-
{jwt && profile && !profile.spotifyConnected && <SpotifyLogin />}
150
-
{jwt && profile && <CloudDrive />}
151
-
{!jwt && (
152
-
<div className="mt-[40px]">
153
-
<div className="mb-[20px]">
154
-
<div className="mb-[15px]">
155
-
<LabelMedium className="!text-[var(--color-text)]">
156
-
Bluesky handle
157
-
</LabelMedium>
158
-
</div>
159
-
<Input
160
-
name="handle"
161
-
startEnhancer={
162
-
<div className="text-[var(--color-text-muted)] bg-[var(--color-input-background)]">
163
-
@
164
-
</div>
165
-
}
166
-
placeholder="<username>.bsky.social"
167
-
value={handle}
168
-
onChange={(e) => setHandle(e.target.value)}
169
-
overrides={{
170
-
Root: {
171
-
style: {
172
-
backgroundColor: "var(--color-input-background)",
173
-
borderColor: "var(--color-input-background)",
174
-
},
175
-
},
176
-
StartEnhancer: {
177
-
style: {
178
-
backgroundColor: "var(--color-input-background)",
179
-
},
180
-
},
181
-
InputContainer: {
182
-
style: {
183
-
backgroundColor: "var(--color-input-background)",
184
-
},
185
-
},
186
-
Input: {
187
-
style: {
188
-
color: "var(--color-text)",
189
-
caretColor: "var(--color-text)",
190
-
},
191
-
},
192
-
}}
193
-
/>
194
-
</div>
195
-
<Button
196
-
onClick={onLogin}
197
-
overrides={{
198
-
BaseButton: {
199
-
style: {
200
-
width: "100%",
201
-
backgroundColor: "var(--color-primary)",
202
-
":hover": {
203
-
backgroundColor: "var(--color-primary)",
204
-
},
205
-
":focus": {
206
-
backgroundColor: "var(--color-primary)",
207
-
},
208
-
},
209
-
},
210
-
}}
211
-
>
212
-
Sign In
213
-
</Button>
214
-
<LabelMedium className="text-center mt-[20px] !text-[var(--color-text-muted)]">
215
-
Don't have an account?
216
-
</LabelMedium>
217
-
<div className="text-center text-[var(--color-text-muted)] ">
218
-
<a
219
-
href="https://bsky.app"
220
-
className="no-underline cursor-pointer !text-[var(--color-primary)]"
221
-
target="_blank"
222
-
>
223
-
Sign up for Bluesky
224
-
</a>{" "}
225
-
to create one now!
226
-
</div>
227
-
</div>
228
-
)}
229
230
-
<div className="mt-[40px]">
231
-
<ScrobblesAreaChart />
232
-
</div>
233
-
<ExternalLinks />
234
-
<div className="inline-flex mt-[40px]">
235
-
<Link
236
-
href="https://docs.rocksky.app/introduction-918639m0"
237
-
target="_blank"
238
-
className="mr-[10px] text-[var(--color-primary)]"
239
-
>
240
-
About
241
-
</Link>
242
-
<Link
243
-
href="https://docs.rocksky.app/faq-918661m0"
244
-
target="_blank"
245
-
className="mr-[10px] text-[var(--color-primary)]"
246
-
>
247
-
FAQ
248
-
</Link>
249
-
<Link
250
-
href="https://doc.rocksky.app/"
251
-
target="_blank"
252
-
className="mr-[10px] text-[var(--color-primary)]"
253
-
>
254
-
API Docs
255
-
</Link>
256
257
-
<Link
258
-
href="https://discord.gg/EVcBy2fVa3"
259
-
target="_blank"
260
-
className="text-[var(--color-primary)]"
261
-
>
262
-
Discord
263
-
</Link>
264
-
</div>
265
-
</div>
266
-
</RightPane>
267
-
)}
268
-
<StickyPlayer />
269
-
</Container>
270
-
);
0
0
0
0
0
0
0
271
}
272
273
export default Main;
···
51
`;
52
53
export type MainProps = {
54
+
children: React.ReactNode;
55
+
withRightPane?: boolean;
56
};
57
58
function Main(props: MainProps) {
59
+
const { children } = props;
60
+
const withRightPane = props.withRightPane ?? true;
61
+
const [handle, setHandle] = useState("");
62
+
const jwt = localStorage.getItem("token");
63
+
const profile = useAtomValue(profileAtom);
64
+
const [token, setToken] = useState<string | null>(null);
65
+
const { did, cli } = useSearch({ strict: false });
66
67
+
useEffect(() => {
68
+
if (did && did !== "null") {
69
+
localStorage.setItem("did", did);
70
71
+
const fetchToken = async () => {
72
+
try {
73
+
const response = await fetch(`${API_URL}/token`, {
74
+
method: "GET",
75
+
headers: {
76
+
"session-did": did,
77
+
},
78
+
});
79
+
const data = await response.json();
80
+
localStorage.setItem("token", data.token);
81
+
setToken(data.token);
82
83
+
if (cli) {
84
+
await fetch("http://localhost:6996/token", {
85
+
method: "POST",
86
+
headers: {
87
+
"Content-Type": "application/json",
88
+
},
89
+
body: JSON.stringify({ token: data.token }),
90
+
});
91
+
}
92
93
+
if (!jwt && data.token) {
94
+
window.location.href = "/";
95
+
}
96
+
} catch (e) {
97
+
console.error(e);
98
+
}
99
+
};
100
+
fetchToken();
101
+
}
102
+
// eslint-disable-next-line react-hooks/exhaustive-deps
103
+
}, []);
104
105
+
useProfile(token || localStorage.getItem("token"));
106
107
+
const onLogin = async () => {
108
+
if (!handle.trim()) {
109
+
return;
110
+
}
111
112
+
if (API_URL.includes("localhost")) {
113
+
window.location.href = `${API_URL}/login?handle=${handle}`;
114
+
return;
115
+
}
116
117
+
window.location.href = `https://rocksky.pages.dev/loading?handle=${handle}`;
118
+
};
119
120
+
return (
121
+
<Container className="bg-[var(--color-background)] text-[var(--color-text)]">
122
+
<ToasterContainer
123
+
placement={PLACEMENT.top}
124
+
overrides={{
125
+
ToastBody: {
126
+
style: {
127
+
zIndex: 2,
128
+
boxShadow: "none",
129
+
},
130
+
},
131
+
}}
132
+
/>
133
+
<Flex style={{ width: withRightPane ? "770px" : "1090px" }}>
134
+
<Navbar />
135
+
<div
136
+
style={{
137
+
position: "relative",
138
+
}}
139
+
>
140
+
{children}
141
+
</div>
142
+
</Flex>
143
+
{withRightPane && (
144
+
<RightPane className="relative w-[300px]">
145
+
<div className="fixed top-[100px] w-[300px] bg-white p-[20px]">
146
+
<div className="mb-[30px]">
147
+
<Search />
148
+
</div>
149
+
{jwt && profile && !profile.spotifyConnected && <SpotifyLogin />}
150
+
{jwt && profile && <CloudDrive />}
151
+
{!jwt && (
152
+
<div className="mt-[40px]">
153
+
<div className="mb-[20px]">
154
+
<div className="mb-[15px]">
155
+
<LabelMedium className="!text-[var(--color-text)]">
156
+
Bluesky handle
157
+
</LabelMedium>
158
+
</div>
159
+
<Input
160
+
name="handle"
161
+
startEnhancer={
162
+
<div className="text-[var(--color-text-muted)] bg-[var(--color-input-background)]">
163
+
@
164
+
</div>
165
+
}
166
+
placeholder="<username>.bsky.social"
167
+
value={handle}
168
+
onChange={(e) => setHandle(e.target.value)}
169
+
overrides={{
170
+
Root: {
171
+
style: {
172
+
backgroundColor: "var(--color-input-background)",
173
+
borderColor: "var(--color-input-background)",
174
+
},
175
+
},
176
+
StartEnhancer: {
177
+
style: {
178
+
backgroundColor: "var(--color-input-background)",
179
+
},
180
+
},
181
+
InputContainer: {
182
+
style: {
183
+
backgroundColor: "var(--color-input-background)",
184
+
},
185
+
},
186
+
Input: {
187
+
style: {
188
+
color: "var(--color-text)",
189
+
caretColor: "var(--color-text)",
190
+
},
191
+
},
192
+
}}
193
+
/>
194
+
</div>
195
+
<Button
196
+
onClick={onLogin}
197
+
overrides={{
198
+
BaseButton: {
199
+
style: {
200
+
width: "100%",
201
+
backgroundColor: "var(--color-primary)",
202
+
":hover": {
203
+
backgroundColor: "var(--color-primary)",
204
+
},
205
+
":focus": {
206
+
backgroundColor: "var(--color-primary)",
207
+
},
208
+
},
209
+
},
210
+
}}
211
+
>
212
+
Sign In
213
+
</Button>
214
+
<LabelMedium className="text-center mt-[20px] !text-[var(--color-text-muted)]">
215
+
Don't have an account?
216
+
</LabelMedium>
217
+
<div className="text-center text-[var(--color-text-muted)] ">
218
+
<a
219
+
href="https://bsky.app"
220
+
className="no-underline cursor-pointer !text-[var(--color-primary)]"
221
+
target="_blank"
222
+
>
223
+
Sign up for Bluesky
224
+
</a>{" "}
225
+
to create one now!
226
+
</div>
227
+
</div>
228
+
)}
229
230
+
<div className="mt-[40px]">
231
+
<ScrobblesAreaChart />
232
+
</div>
233
+
<ExternalLinks />
234
+
<div className="inline-flex mt-[40px]">
235
+
<Link
236
+
href="https://docs.rocksky.app/introduction-918639m0"
237
+
target="_blank"
238
+
className="mr-[10px] text-[var(--color-primary)]"
239
+
>
240
+
About
241
+
</Link>
242
+
<Link
243
+
href="https://docs.rocksky.app/faq-918661m0"
244
+
target="_blank"
245
+
className="mr-[10px] text-[var(--color-primary)]"
246
+
>
247
+
FAQ
248
+
</Link>
249
+
<Link
250
+
href="https://doc.rocksky.app/"
251
+
target="_blank"
252
+
className="mr-[10px] text-[var(--color-primary)]"
253
+
>
254
+
API Docs
255
+
</Link>
256
257
+
<Link
258
+
href="https://discord.gg/EVcBy2fVa3"
259
+
target="_blank"
260
+
className="text-[var(--color-primary)]"
261
+
>
262
+
Discord
263
+
</Link>
264
+
<Link
265
+
href="https://tangled.org/@rocksky.app/rocksky"
266
+
target="_blank"
267
+
className="text-[var(--color-primary)]"
268
+
>
269
+
Source
270
+
</Link>
271
+
</div>
272
+
</div>
273
+
</RightPane>
274
+
)}
275
+
<StickyPlayer />
276
+
</Container>
277
+
);
278
}
279
280
export default Main;