+73
-23
main.tsx
+73
-23
main.tsx
···
176
<GalleryPage favs={favs} gallery={gallery} currentUserDid={did} />,
177
);
178
}),
179
-
route("/upload", (_req, _params, ctx) => {
180
requireAuth(ctx);
181
const photos = getActorPhotos(ctx.currentUser.did, ctx);
182
ctx.state.meta = [{ title: "Upload — Grain" }, getPageMeta("/upload")];
183
-
return ctx.render(<UploadPage photos={photos} />);
184
}),
185
route("/dialogs/gallery/new", (_req, _params, ctx) => {
186
requireAuth(ctx);
···
1165
{loggedInUserDid === profile.did
1166
? (
1167
<div class="flex self-start gap-2 w-full sm:w-fit flex-col sm:flex-row">
1168
-
<Button variant="secondary" class="w-full sm:w-fit" asChild>
1169
<a href="/upload">
1170
<i class="fa-solid fa-upload mr-2" />
1171
Upload
···
1280
);
1281
}
1282
1283
-
function UploadPage({ photos }: Readonly<{ photos: PhotoView[] }>) {
1284
return (
1285
-
<div class="px-4 pt-4 mb-4">
1286
-
<Button variant="primary" class="mb-2" asChild>
1287
<label class="w-fit">
1288
<i class="fa fa-plus"></i> Add photos
1289
<input
···
1434
const isLoggedIn = !!currentUserDid;
1435
return (
1436
<div class="px-4">
1437
-
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between my-4 gap-2">
1438
-
<div>
1439
<div>
1440
-
<h1 class="font-bold text-2xl">
1441
-
{(gallery.record as Gallery).title}
1442
-
</h1>
1443
Gallery by{" "}
1444
<a
1445
href={profileLink(gallery.creator.handle)}
···
1452
</span>
1453
</a>
1454
</div>
1455
-
{(gallery.record as Gallery).description}
1456
</div>
1457
{isLoggedIn && isCreator
1458
? (
···
1837
}>) {
1838
return (
1839
<Dialog id="photo-select-dialog" class="z-30">
1840
-
<Dialog.Content class="w-full max-w-5xl dark:bg-zinc-950">
1841
<Dialog.Title>Add photos</Dialog.Title>
1842
-
<div class="grid grid-cols-2 sm:grid-cols-3 gap-4 my-4">
1843
-
{photos.map((photo) => (
1844
-
<PhotoSelectButton
1845
-
key={photo.cid}
1846
-
galleryUri={galleryUri}
1847
-
itemUris={itemUris}
1848
-
photo={photo}
1849
-
/>
1850
-
))}
1851
-
</div>
1852
<div class="w-full flex flex-col gap-2 mt-2">
1853
<Dialog.Close class="w-full">Close</Dialog.Close>
1854
</div>
···
176
<GalleryPage favs={favs} gallery={gallery} currentUserDid={did} />,
177
);
178
}),
179
+
route("/upload", (req, _params, ctx) => {
180
requireAuth(ctx);
181
+
const url = new URL(req.url);
182
+
const galleryRkey = url.searchParams.get("returnTo");
183
const photos = getActorPhotos(ctx.currentUser.did, ctx);
184
ctx.state.meta = [{ title: "Upload — Grain" }, getPageMeta("/upload")];
185
+
return ctx.render(
186
+
<UploadPage
187
+
handle={ctx.currentUser.handle}
188
+
photos={photos}
189
+
returnTo={galleryRkey
190
+
? galleryLink(ctx.currentUser.handle, galleryRkey)
191
+
: undefined}
192
+
/>,
193
+
);
194
}),
195
route("/dialogs/gallery/new", (_req, _params, ctx) => {
196
requireAuth(ctx);
···
1175
{loggedInUserDid === profile.did
1176
? (
1177
<div class="flex self-start gap-2 w-full sm:w-fit flex-col sm:flex-row">
1178
+
<Button variant="primary" class="w-full sm:w-fit" asChild>
1179
<a href="/upload">
1180
<i class="fa-solid fa-upload mr-2" />
1181
Upload
···
1290
);
1291
}
1292
1293
+
function UploadPage(
1294
+
{ handle, photos, returnTo }: Readonly<
1295
+
{ handle: string; photos: PhotoView[]; returnTo?: string }
1296
+
>,
1297
+
) {
1298
return (
1299
+
<div class="flex flex-col px-4 pt-4 mb-4 space-y-4">
1300
+
{returnTo
1301
+
? (
1302
+
<a
1303
+
href={returnTo}
1304
+
class="hover:underline"
1305
+
>
1306
+
<i class="fa-solid fa-arrow-left mr-2" />
1307
+
Back to gallery
1308
+
</a>
1309
+
)
1310
+
: (
1311
+
<a href={profileLink(handle)} class="hover:underline">
1312
+
<i class="fa-solid fa-arrow-left mr-2" />
1313
+
Back to profile
1314
+
</a>
1315
+
)}
1316
+
<Button variant="primary" class="mb-4" asChild>
1317
<label class="w-fit">
1318
<i class="fa fa-plus"></i> Add photos
1319
<input
···
1464
const isLoggedIn = !!currentUserDid;
1465
return (
1466
<div class="px-4">
1467
+
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between my-4">
1468
+
<div class="flex flex-col space-y-1">
1469
+
<h1 class="font-bold text-2xl">
1470
+
{(gallery.record as Gallery).title}
1471
+
</h1>
1472
<div>
1473
Gallery by{" "}
1474
<a
1475
href={profileLink(gallery.creator.handle)}
···
1482
</span>
1483
</a>
1484
</div>
1485
+
<p>{(gallery.record as Gallery).description}</p>
1486
</div>
1487
{isLoggedIn && isCreator
1488
? (
···
1867
}>) {
1868
return (
1869
<Dialog id="photo-select-dialog" class="z-30">
1870
+
<Dialog.Content class="w-full max-w-5xl dark:bg-zinc-950 min-h-screen flex flex-col">
1871
<Dialog.Title>Add photos</Dialog.Title>
1872
+
<p class="my-2 text-center">
1873
+
Choose photos to add/remove from your gallery. Click close when done.
1874
+
</p>
1875
+
{photos?.length
1876
+
? (
1877
+
<div class="grid grid-cols-2 sm:grid-cols-3 gap-4 my-4 flex-1">
1878
+
{photos.map((photo) => (
1879
+
<PhotoSelectButton
1880
+
key={photo.cid}
1881
+
galleryUri={galleryUri}
1882
+
itemUris={itemUris}
1883
+
photo={photo}
1884
+
/>
1885
+
))}
1886
+
</div>
1887
+
)
1888
+
: (
1889
+
<div class="flex-1 flex justify-center items-center">
1890
+
<p>
1891
+
No photos yet.{" "}
1892
+
<a
1893
+
href={`/upload?returnTo=${new AtUri(galleryUri).rkey}`}
1894
+
class="hover:underline font-semibold text-sky-500"
1895
+
>
1896
+
Upload
1897
+
</a>{" "}
1898
+
photos and return to add.
1899
+
</p>
1900
+
</div>
1901
+
)}
1902
<div class="w-full flex flex-col gap-2 mt-2">
1903
<Dialog.Close class="w-full">Close</Dialog.Close>
1904
</div>
+13
static/styles.css
+13
static/styles.css
···
337
.h-full {
338
height: 100%;
339
}
340
.w-1\/3 {
341
width: calc(1/3 * 100%);
342
}
···
399
}
400
.gap-4 {
401
gap: calc(var(--spacing) * 4);
402
}
403
.space-y-2 {
404
:where(& > :not(:last-child)) {
···
487
}
488
.pt-4 {
489
padding-top: calc(var(--spacing) * 4);
490
}
491
.text-left {
492
text-align: left;
···
337
.h-full {
338
height: 100%;
339
}
340
+
.min-h-screen {
341
+
min-height: 100vh;
342
+
}
343
.w-1\/3 {
344
width: calc(1/3 * 100%);
345
}
···
402
}
403
.gap-4 {
404
gap: calc(var(--spacing) * 4);
405
+
}
406
+
.space-y-1 {
407
+
:where(& > :not(:last-child)) {
408
+
--tw-space-y-reverse: 0;
409
+
margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));
410
+
margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));
411
+
}
412
}
413
.space-y-2 {
414
:where(& > :not(:last-child)) {
···
497
}
498
.pt-4 {
499
padding-top: calc(var(--spacing) * 4);
500
+
}
501
+
.text-center {
502
+
text-align: center;
503
}
504
.text-left {
505
text-align: left;