diff --git a/pages/music/edit.ts b/pages/music/edit.ts index b3adc38..7f3971b 100644 --- a/pages/music/edit.ts +++ b/pages/music/edit.ts @@ -1,10 +1,10 @@ +import { permCheck, RegisterAuthRefresh, renewAccessTokenIfNeeded, saveBlob, showPreviewImage, streamingImages } from "shared/helper.ts"; import { API, stupidErrorAlert } from "shared/mod.ts"; import { appendBody, asRef, Color, Empty, Grid, isMobile, Label } from "webgen/mod.ts"; import "../../assets/css/main.css"; import "../../assets/css/music.css"; import { DynaNavigation } from "../../components/nav.ts"; import { Drop, DropType, Share } from "../../spec/music.ts"; -import { permCheck, RegisterAuthRefresh, renewAccessTokenIfNeeded, saveBlob, showPreviewImage, streamingImages } from "../shared/helper.ts"; import { ChangeDrop } from "./views/changeDrop.ts"; import { ChangeSongs } from "./views/changeSongs.ts"; import { DropTypeToText } from "./views/list.ts"; diff --git a/pages/music/pages/draftDrops.ts b/pages/music/pages/draftDrops.ts index 71ff3a7..2f198c0 100644 --- a/pages/music/pages/draftDrops.ts +++ b/pages/music/pages/draftDrops.ts @@ -1,6 +1,7 @@ import { API, stupidErrorAlert } from "shared/restSpec.ts"; -import { asRef, Box, Content, createPage, createRoute, Entry, Grid, Label, Spinner } from "webgen/mod.ts"; +import { asRef, Box, Content, createPage, createRoute, Grid, Spinner } from "webgen/mod.ts"; import { Drop, DropType } from "../../../spec/music.ts"; +import { musicList } from "../views/list.ts"; const data = asRef<"loading" | Drop[]>("loading"); @@ -23,15 +24,7 @@ export const draftsDropsPage = createPage( Content( Box(data.map((data) => data === "loading" ? Spinner() : [])), Grid( - source.map((items) => - items.map((item) => - Entry( - Label(item.title ?? "(Untitled)") - .setMargin("35px 0"), - ) - .onClick(() => location.href = `/c/music/new-drop?id=${item._id}`) - ) - ), + source.map((items) => musicList(items, DropType.Unsubmitted)), ), ), ); diff --git a/pages/music/pages/publishedDrops.ts b/pages/music/pages/publishedDrops.ts index bcd8fc8..e5e12f0 100644 --- a/pages/music/pages/publishedDrops.ts +++ b/pages/music/pages/publishedDrops.ts @@ -1,6 +1,7 @@ import { API, stupidErrorAlert } from "shared/mod.ts"; -import { asRef, Box, Content, createPage, createRoute, Entry, Grid, Label, Spinner } from "webgen/mod.ts"; +import { asRef, Box, Content, createPage, createRoute, Grid, Spinner } from "webgen/mod.ts"; import { Drop, DropType } from "../../../spec/music.ts"; +import { musicList } from "../views/list.ts"; const data = asRef<"loading" | Drop[]>("loading"); @@ -23,13 +24,7 @@ export const publishedDrops = createPage( Content( Box(data.map((data) => data === "loading" ? Spinner() : [])), Grid( - source.map((items) => - items.map((item) => - Entry( - Label(item.title), - ) - ) - ), + source.map((items) => musicList(items, DropType.Published)), ), ), ); diff --git a/pages/music/pages/unpublishedDrops.ts b/pages/music/pages/unpublishedDrops.ts index 28c2803..790728e 100644 --- a/pages/music/pages/unpublishedDrops.ts +++ b/pages/music/pages/unpublishedDrops.ts @@ -1,6 +1,7 @@ import { API, stupidErrorAlert } from "shared/mod.ts"; -import { asRef, Box, Content, createPage, createRoute, Entry, Grid, Label, Spinner } from "webgen/mod.ts"; +import { asRef, Box, Content, createPage, createRoute, Grid, Spinner } from "webgen/mod.ts"; import { Drop, DropType } from "../../../spec/music.ts"; +import { musicList } from "../views/list.ts"; const data = asRef<"loading" | Drop[]>("loading"); @@ -27,13 +28,7 @@ export const unpublishedDropsPage = createPage( Content( Box(data.map((data) => data === "loading" ? Spinner() : [])), Grid( - source.map((items) => - items.map((item) => - Entry( - Label(item.title), - ) - ) - ), + source.map((items) => musicList(items, DropType.Private)), ), ), ); diff --git a/pages/music/views/list.ts b/pages/music/views/list.ts index 304a952..d4886ab 100644 --- a/pages/music/views/list.ts +++ b/pages/music/views/list.ts @@ -1,29 +1,22 @@ import { showPreviewImage } from "shared/helper.ts"; -import { placeholder } from "shared/mod.ts"; -import { CenterV, Component, Empty, Entry, Image, isMobile, Label, Vertical } from "webgen/mod.ts"; +import { placeholder } from "shared/list.ts"; +import { asRef, Box, Empty, Entry, Grid, Image, Label } from "webgen/mod.ts"; import { templateArtwork } from "../../../assets/imports.ts"; import { type Artist, Drop, DropType } from "../../../spec/music.ts"; export function DropEntry(x: Drop) { - return Entry({ - title: x.title ?? "(no drop name)", - subtitle: `${x.release ?? "(no release date)"} - ${x.gtin ?? "(no GTIN)"}`, - }) - .addClass(isMobile.map((mobile) => mobile ? "small" : "normal")) - .addPrefix(showPreviewImage(x).addClass("image-square")) + return Entry(Grid( + Label(x.title ?? "(no drop name)"), + Label(`${x.release ?? "(no release date)"} - ${x.gtin ?? "(no GTIN)"}`), + )) + .addPrefix(showPreviewImage(x)) .addSuffix((() => { if (x.type == DropType.UnderReview) { - return CenterV( - Label("Under Review") - .addClass("entry-subtitle", "under-review"), - ); + return Label("Under Review"); } if (x.type == DropType.ReviewDeclined) { - return CenterV( - Label("Declined") - .addClass("entry-subtitle", "under-review"), - ); + return Label("Declined"); } return Empty(); @@ -43,12 +36,11 @@ export function ArtistEntry(x: Artist) { // LinkButton("Apple Music", "fdgdf"), // ).setGap(), // ) - .addPrefix(Image(templateArtwork, "Artist Profile Picture").addClass("image-square")) - .addClass(isMobile.map((mobile) => mobile ? "small" : "normal")); + .addPrefix(Image(templateArtwork, "Artist Profile Picture")); } export const musicList = (list: Drop[], type: DropType) => - Vertical( + Grid( CategoryRender( list.filter((_, i) => i == 0), "Latest Drop", @@ -57,19 +49,18 @@ export const musicList = (list: Drop[], type: DropType) => list.filter((_, i) => i > 0), "History", ), - list.length == 0 ? placeholder("No Drops", `You don’t have any ${EnumToDisplay(type)} Drops`) : null, + list.length == 0 ? placeholder("No Drops", `You don’t have any ${EnumToDisplay(type)} Drops`) : Empty(), ) .setGap("20px"); -export function CategoryRender(dropList: Drop[], title: string): Component[] | null { +export function CategoryRender(dropList: Drop[], title: string) { if (dropList.length == 0) { - return null; + return Empty(); } - return [ - Label(title) - .addClass("list-title"), - Vertical(...dropList.map((x) => DropEntry(x))).setGap("1rem"), - ]; + return Box( + Label(title), + Grid(asRef(dropList.map((x) => DropEntry(x)))).setGap("1rem"), + ); } export function EnumToDisplay(state: DropType) { diff --git a/pages/shared/helper.ts b/pages/shared/helper.ts index 5476cb6..058f16b 100644 --- a/pages/shared/helper.ts +++ b/pages/shared/helper.ts @@ -1,7 +1,8 @@ import { fail } from "@std/assert/fail"; import { LruCache, memoize } from "@std/cache"; import { API, fileCache, Permission, stupidErrorAlert } from "shared/mod.ts"; -import { asRef, asRefRecord, Async, Component, DropDown, Empty, Grid, Image, ImageComponent, PrimaryButton, SheetHeader, Sheets, Spinner, WriteSignal } from "webgen/mod.ts"; +import { asRef, asRefRecord, Async, Component, DropDown, Grid, Image, ImageComponent, PrimaryButton, SheetHeader, Sheets, Spinner, WriteSignal } from "webgen/mod.ts"; +import { templateArtwork } from "../../assets/imports.ts"; import { loginRequired } from "../../components/pages.ts"; import { Drop, Song } from "../../spec/music.ts"; @@ -182,8 +183,15 @@ export function saveBlob(blob: Blob, fileName: string) { } export function showPreviewImage(x: Drop) { - return Empty(); - // return x.artwork ? Cache(`image-preview-${x.artwork}`, () => Promise.resolve(), (type) => type == "loaded" ? Image({ type: "direct", source: () => loadImage(x) }, "A Song Artwork") : Box()) : Image(templateArtwork, "A Placeholder Artwork."); + return x.artwork + ? Async( + (async () => { + const image = await API.music.id(x._id).artwork().then(stupidErrorAlert); + return Image(URL.createObjectURL(image), ""); + })(), + Spinner(), + ) + : Image(templateArtwork, "A Placeholder Artwork."); } async function loadImage(x: Drop) { diff --git a/pages/user/settings.ts b/pages/user/settings.ts index 6ca65d9..180a7f2 100644 --- a/pages/user/settings.ts +++ b/pages/user/settings.ts @@ -1,10 +1,8 @@ -import { logOut, RegisterAuthRefresh } from "shared/helper.ts"; -import { API, Navigation } from "shared/mod.ts"; -import { appendBody, asRefRecord, WebGenTheme } from "webgen/mod.ts"; +import { RegisterAuthRefresh } from "shared/helper.ts"; +import { appendBody, asRefRecord, Empty, WebGenTheme } from "webgen/mod.ts"; import { z } from "zod/mod.ts"; import "../../assets/css/main.css"; import { DynaNavigation } from "../../components/nav.ts"; -import { ChangePersonal } from "./settings.personal.ts"; await RegisterAuthRefresh(); @@ -14,126 +12,126 @@ const state = asRefRecord({ validationState: undefined, }); -const settingsMenu = Navigation({ - title: "Settings", - children: [ - { - id: "personal", - title: "Personal", - subtitle: "Username, Email, Profile Picture...", - children: [ - ChangePersonal(), - ], - }, - { - id: "change-password", - title: "Change Password", - children: [ - Vertical( - Grid([ - { width: 2 }, - Vertical( - TextInput("password", "New Password").ref(state.$newPassword), - TextInput("password", "Verify New Password").ref(state.$verifyNewPassword), - ).setGap("20px"), - ]) - .setDynamicColumns(1, "12rem") - .setJustifyContent("center") - .setGap("15px"), - Horizontal( - Spacer(), - Box( - state.$validationState.map((error) => - error - ? CenterV( - Label(getErrorMessage(error)) - .addClass("error-message") - .setMargin("0 0.5rem 0 0"), - ) - : Empty() - ).asRefComponent(), - ), - Button("Save").onClick(async () => { - const { error, validate } = Validate( - state, - zod.object({ - newPassword: zod.string({ invalid_type_error: "New password is missing" }).min(8), - verifyNewPassword: zod.string({ invalid_type_error: "Verify New password is missing" }).min(8).refine((val) => val == state.newPassword, "Your new password didn't match"), - }), - ); +// const settingsMenu = Navigation({ +// title: "Settings", +// children: [ +// { +// id: "personal", +// title: "Personal", +// subtitle: "Username, Email, Profile Picture...", +// children: [ +// ChangePersonal(), +// ], +// }, +// { +// id: "change-password", +// title: "Change Password", +// children: [ +// Vertical( +// Grid([ +// { width: 2 }, +// Vertical( +// TextInput("password", "New Password").ref(state.$newPassword), +// TextInput("password", "Verify New Password").ref(state.$verifyNewPassword), +// ).setGap("20px"), +// ]) +// .setDynamicColumns(1, "12rem") +// .setJustifyContent("center") +// .setGap("15px"), +// Horizontal( +// Spacer(), +// Box( +// state.$validationState.map((error) => +// error +// ? CenterV( +// Label(getErrorMessage(error)) +// .addClass("error-message") +// .setMargin("0 0.5rem 0 0"), +// ) +// : Empty() +// ).asRefComponent(), +// ), +// Button("Save").onClick(async () => { +// const { error, validate } = Validate( +// state, +// zod.object({ +// newPassword: zod.string({ invalid_type_error: "New password is missing" }).min(8), +// verifyNewPassword: zod.string({ invalid_type_error: "Verify New password is missing" }).min(8).refine((val) => val == state.newPassword, "Your new password didn't match"), +// }), +// ); - const data = validate(); - if (error.getValue()) return state.validationState = error.getValue(); - if (data) await API.user.setMe.post({ password: data.newPassword }); - logOut(); - state.validationState = undefined; - }), - ), - ).setGap("20px"), - ], - }, - { - id: "logout", - title: "Logout", - clickHandler: () => logOut(), - }, - ], -}).addClass( - isMobile.map((mobile) => mobile ? "mobile-navigation" : "navigation"), - "limited-width", -); +// const data = validate(); +// if (error.getValue()) return state.validationState = error.getValue(); +// if (data) await API.user.setMe.post({ password: data.newPassword }); +// logOut(); +// state.validationState = undefined; +// }), +// ), +// ).setGap("20px"), +// ], +// }, +// { +// id: "logout", +// title: "Logout", +// clickHandler: () => logOut(), +// }, +// ], +// }).addClass( +// isMobile.map((mobile) => mobile ? "mobile-navigation" : "navigation"), +// "limited-width", +// ); appendBody(WebGenTheme( DynaNavigation("Settings"), - settingsMenu, + Empty(), )); -const publicKey = { - // challenge: new Uint8Array([ 117, 61, 252, 231, 191, 241 ]), - // rp: { id: "localhost", name: "BBN Holding" }, - // user: { - // id: new TextEncoder().encode(activeUser.id ?? ""), - // name: activeUser.email ?? "", - // displayName: activeUser.username ?? "" - // }, - // excludeCredentials: [ - // { id: new Uint8Array([ 79, 252, 83, 72, 214, 7, 89, 26 ]), type: "public-key" as PublicKeyCredentialType, transports: [ "usb", "nfc", "ble" ] as AuthenticatorTransport[] } - // ], - // pubKeyCredParams: [ { type: "public-key" as PublicKeyCredentialType, alg: -7 }, { type: "public-key" as PublicKeyCredentialType, alg: -257 } ] - // }; +// const publicKey = { +// challenge: new Uint8Array([ 117, 61, 252, 231, 191, 241 ]), +// rp: { id: "localhost", name: "BBN Holding" }, +// user: { +// id: new TextEncoder().encode(activeUser.id ?? ""), +// name: activeUser.email ?? "", +// displayName: activeUser.username ?? "" +// }, +// excludeCredentials: [ +// { id: new Uint8Array([ 79, 252, 83, 72, 214, 7, 89, 26 ]), type: "public-key" as PublicKeyCredentialType, transports: [ "usb", "nfc", "ble" ] as AuthenticatorTransport[] } +// ], +// pubKeyCredParams: [ { type: "public-key" as PublicKeyCredentialType, alg: -7 }, { type: "public-key" as PublicKeyCredentialType, alg: -257 } ] +// }; - // const credential = await navigator.credentials.create({ publicKey }) as PublicKeyCredential; +// const credential = await navigator.credentials.create({ publicKey }) as PublicKeyCredential; - // console.log(credential); +// console.log(credential); - // const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; +// const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'; - // // Use a lookup table to find the index. - // const lookup = new Uint8Array(256); - // for (let i = 0; i < chars.length; i++) { - // lookup[ chars.charCodeAt(i) ] = i; - // } +// // Use a lookup table to find the index. +// const lookup = new Uint8Array(256); +// for (let i = 0; i < chars.length; i++) { +// lookup[ chars.charCodeAt(i) ] = i; +// } - // const encode = (arraybuffer: ArrayBuffer): string => { - // const bytes = new Uint8Array(arraybuffer); - // const len = bytes.length; - // let base64 = ''; +// const encode = (arraybuffer: ArrayBuffer): string => { +// const bytes = new Uint8Array(arraybuffer); +// const len = bytes.length; +// let base64 = ''; - // for (let i = 0; i < len; i += 3) { - // base64 += chars[ bytes[ i ] >> 2 ]; - // base64 += chars[ ((bytes[ i ] & 3) << 4) | (bytes[ i + 1 ] >> 4) ]; - // base64 += chars[ ((bytes[ i + 1 ] & 15) << 2) | (bytes[ i + 2 ] >> 6) ]; - // base64 += chars[ bytes[ i + 2 ] & 63 ]; - // } +// for (let i = 0; i < len; i += 3) { +// base64 += chars[ bytes[ i ] >> 2 ]; +// base64 += chars[ ((bytes[ i ] & 3) << 4) | (bytes[ i + 1 ] >> 4) ]; +// base64 += chars[ ((bytes[ i + 1 ] & 15) << 2) | (bytes[ i + 2 ] >> 6) ]; +// base64 += chars[ bytes[ i + 2 ] & 63 ]; +// } - // if (len % 3 === 2) { - // base64 = base64.substring(0, base64.length - 1); - // } else if (len % 3 === 1) { - // base64 = base64.substring(0, base64.length - 2); - // } +// if (len % 3 === 2) { +// base64 = base64.substring(0, base64.length - 1); +// } else if (len % 3 === 1) { +// base64 = base64.substring(0, base64.length - 2); +// } - // return base64; - // }; +// return base64; +// }; - // console.log(encode(credential.response.clientDataJSON)); - // console.log(encode((credential.response as AuthenticatorAttestationResponse).attestationObject)); - // console.log(credential.getClientExtensionResults()); \ No newline at end of file +// console.log(encode(credential.response.clientDataJSON)); +// console.log(encode((credential.response as AuthenticatorAttestationResponse).attestationObject)); +// console.log(credential.getClientExtensionResults())