From 933350934d0b8dd9a82062c84eaa40540f92809e Mon Sep 17 00:00:00 2001 From: GregTCLTK Date: Tue, 19 Nov 2024 17:39:39 +0100 Subject: [PATCH] more webgen changes --- pages/admin/dialog.ts | 130 +++++++---------- pages/admin/email.ts | 4 +- pages/admin/loading.ts | 8 +- pages/admin/review.ts | 279 ++++++++++++++++++------------------ pages/admin/state.ts | 6 +- pages/holding/imprint.ts | 6 +- pages/holding/index.ts | 10 +- pages/music-landing/main.ts | 100 ++++++------- pages/music/edit.ts | 8 +- pages/music/main.ts | 14 +- pages/music/newDrop.ts | 184 +++++++++++------------- pages/music/share.ts | 72 +++++----- serve.ts | 2 +- 13 files changed, 393 insertions(+), 430 deletions(-) diff --git a/pages/admin/dialog.ts b/pages/admin/dialog.ts index 806eb07..c563ef9 100644 --- a/pages/admin/dialog.ts +++ b/pages/admin/dialog.ts @@ -1,6 +1,6 @@ -import { API, LoadingSpinner } from "shared/mod.ts"; -import { asState, Box, Button, ButtonStyle, CenterV, Checkbox, createElement, css, Custom, Empty, getErrorMessage, Horizontal, Label, SheetDialog, Spacer, Validate, Vertical } from "webgen/mod.ts"; -import { zod } from "webgen/zod.ts"; +import { API } from "shared/mod.ts"; +import { asRefRecord, Box, Checkbox, css, Empty, Grid, Label, PrimaryButton, SecondaryButton, SheetHeader, Spinner, TextAreaInput } from "webgen/mod.ts"; +import z from "zod/index.ts"; import reviewTexts from "../../data/reviewTexts.json" with { type: "json" }; import { Drop, ReviewResponse } from "../../spec/music.ts"; import { sheetStack } from "../shared/helper.ts"; @@ -31,42 +31,29 @@ const reviewResponse = [ ]; const rejectReasons = [ReviewResponse.DeclineCopyright]; -export const dialogState = asState({ +export const dialogState = asRefRecord({ drop: undefined, - responseText: "", - validationState: undefined, + responseText: reviewTexts.APPROVED.content.join("\n"), + validationState: undefined, }); -export const ApproveDialog = SheetDialog( - sheetStack, - "Approve Drop", - dialogState.$drop.map((drop) => +export const ApproveDialog = Grid( + SheetHeader("Approve Drop", sheetStack), + Box(dialogState.drop.map((drop) => Box( drop - ? Vertical( + ? Grid( Box( Label("Email Response"), - Custom((() => { - const ele = createElement("textarea"); - ele.rows = 10; - dialogState.responseText = reviewTexts.APPROVED.content.join("\n"); - ele.value = dialogState.responseText; - ele.style.resize = "vertical"; - ele.oninput = () => { - dialogState.responseText = ele.value; - }; - return ele; - })()), + TextAreaInput(dialogState.responseText), ) .addClass("winput", "grayscaled", "has-value", "textarea") .setMargin("0 0 .5rem"), Label("Preview") .setMargin("0 0 0.5rem"), - dialogState.$responseText - .map(() => clientRender(dropPatternMatching(dialogState.responseText, drop))) - .asRefComponent(), - Horizontal( + Box(dialogState.responseText.map(() => clientRender(dropPatternMatching(dialogState.responseText, drop)))), + Grid( Box( - dialogState.$validationState.map((error) => + dialogState.validationState.map((error) => error ? CenterV( Label(getErrorMessage(error)) @@ -74,11 +61,10 @@ export const ApproveDialog = SheetDialog( .setMargin("0 0.5rem 0 0"), ) : Empty() - ).asRefComponent(), + ), ), - Spacer(), - Button("Cancel").setStyle(ButtonStyle.Secondary).onClick(() => ApproveDialog.close()), - Button("Submit").onPromiseClick(async () => { + SecondaryButton("Cancel").onClick(() => sheetStack.removeOne()), + PrimaryButton("Submit").onPromiseClick(async () => { const { data, error, validate } = Validate( dialogState, zod.object({ @@ -99,52 +85,49 @@ export const ApproveDialog = SheetDialog( denyEdits: false, }); - ApproveDialog.close(); + sheetStack.removeOne(); }), ).setGap(), ) - : LoadingSpinner(), + : Spinner(), ) .setMargin("0 0 var(--gap)") - ).asRefComponent(), + )), ); -const rejectState = asState({ +const rejectState = asRefRecord({ page: 0, respones: [] as ReviewResponse[], denyEdits: false, responseText: "", }); -export const DeclineDialog = SheetDialog( - sheetStack, - "Decline Drop", - rejectState.$page.map((page) => { +export const DeclineDialog = Grid( + SheetHeader("Decline Drop", sheetStack), + Box(rejectState.page.map((page) => { if (page == 0) { - return Vertical( + return Grid( Label("Choose Rejection Reasons"), ...rejectReasons .map((rsp) => - Horizontal( + Grid( Checkbox(rejectState.respones.includes(rsp)).onClick(() => rejectState.respones.includes(rsp) ? rejectState.respones.splice(rejectState.respones.indexOf(rsp), 1) : rejectState.respones.push(rsp)), Label(reviewResponse[rejectReasons.indexOf(rsp)]), - Spacer(), ) - .setMargin("0.5rem 0") .setGap("0.5rem") + .setMargin("0.5rem 0") .setAlignItems("center") ), Label("Choose Rejection Method"), - Horizontal( + Grid( Checkbox(rejectState.denyEdits).onClick(() => rejectState.denyEdits = !rejectState.denyEdits), Label("Reject (Deny Edits)"), - Spacer(), ) - .setMargin("0.5rem 0") .setGap("0.5rem") + .setMargin("0.5rem 0") .setAlignItems("center"), - Horizontal( + Grid( Box( - dialogState.$validationState.map((error) => + dialogState.validationState.map((error) => error ? CenterV( Label(getErrorMessage(error)) @@ -152,16 +135,15 @@ export const DeclineDialog = SheetDialog( .setMargin("0 0.5rem 0 0"), ) : Empty() - ).asRefComponent(), + ), ), - Spacer(), - Button("Cancel").setStyle(ButtonStyle.Secondary).onClick(() => DeclineDialog.close()), - Button("Next").onClick(() => { + SecondaryButton("Cancel").onClick(() => sheetStack.removeOne()), + PrimaryButton("Next").onClick(() => { const { error, validate } = Validate( rejectState, - zod.object({ - respones: zod.string().array().min(1), - denyEdits: zod.boolean(), + z.object({ + respones: z.string().array().min(1), + denyEdits: z.boolean(), }), ); @@ -182,46 +164,34 @@ export const DeclineDialog = SheetDialog( ).setGap(), ); } else if (page == 1) { - return Vertical( + return Grid( Box( Label("Email Response"), - Custom((() => { - const ele = createElement("textarea"); - ele.rows = 10; - ele.value = rejectState.responseText; - ele.style.resize = "vertical"; - ele.oninput = () => { - rejectState.responseText = ele.value; - }; - return ele; - })()), + TextAreaInput(rejectState.responseText), ) .addClass("winput", "grayscaled", "has-value", "textarea") .setMargin("0 0 .5rem"), Label("Preview") .setMargin("0 0 0.5rem"), - rejectState.$responseText - .map(() => clientRender(dropPatternMatching(rejectState.responseText, dialogState.drop!))) - .asRefComponent(), - Horizontal( + Box(rejectState.responseText.map((x) => clientRender(dropPatternMatching(x, dialogState.drop!)))), + Grid( Box( - dialogState.$validationState.map((error) => + dialogState.validationState.map((error) => error - ? CenterV( + ? Grid( Label(getErrorMessage(error)) .addClass("error-message") .setMargin("0 0.5rem 0 0"), ) : Empty() - ).asRefComponent(), + ), ), - Spacer(), - Button("Cancel").setStyle(ButtonStyle.Secondary).onClick(() => DeclineDialog.close()), - Button("Submit").onPromiseClick(async () => { + SecondaryButton("Cancel").onClick(() => sheetStack.removeOne()), + PrimaryButton("Submit").onPromiseClick(async () => { const { error, validate } = Validate( rejectState, - zod.object({ - responseText: zod.string().refine((x) => render(dropPatternMatching(x, dialogState.drop!)).errors.length == 0, { message: "Invalid MJML" }), + z.object({ + responseText: z.string().refine((x) => render(dropPatternMatching(x, dialogState.drop!)).errors.length == 0, { message: "Invalid MJML" }), }), ); @@ -245,6 +215,6 @@ export const DeclineDialog = SheetDialog( ).setGap(), ); } - return Box(); - }).asRefComponent(), + return Empty(); + })), ); diff --git a/pages/admin/email.ts b/pages/admin/email.ts index 955d83d..41be934 100644 --- a/pages/admin/email.ts +++ b/pages/admin/email.ts @@ -1,6 +1,6 @@ // @deno-types="https://cdn.jsdelivr.net/npm/@types/mjml-core@4.7.1/index.d.ts" import mjml from "https://cdn.jsdelivr.net/npm/mjml-browser@4.15.3/+esm"; -import { Box, createElement, Custom, Label, Vertical } from "webgen/mod.ts"; +import { Box, Grid, Label } from "webgen/mod.ts"; import { Drop } from "../../spec/music.ts"; import "./email.css"; @@ -34,7 +34,7 @@ export function clientRender(data: string) { shell.srcdoc = mjmlrsp.html; return Box( Custom(shell).addClass("emailPreview").setMargin("0 0 calc(var(--gap) / 2)"), - Vertical( + Grid( Array.from(new Set(mjmlrsp.errors.map((x) => `${x.tagName}: ${x.message}`))).map((x) => Label(`⚠️ ${x}`)), ), ); diff --git a/pages/admin/loading.ts b/pages/admin/loading.ts index 3822b7b..e1a1ca5 100644 --- a/pages/admin/loading.ts +++ b/pages/admin/loading.ts @@ -1,6 +1,6 @@ import { delay } from "@std/async"; import { API, StreamingUploadHandler } from "shared/mod.ts"; -import { UploadFilesDialog } from "webgen/mod.ts"; +import { createFilePicker } from "webgen/mod.ts"; import { DropType } from "../../spec/music.ts"; import { state } from "./state.ts"; @@ -22,14 +22,14 @@ const urls = { export function upload(type: keyof typeof urls): Promise { const [url, extension] = urls[type]; return new Promise((resolve) => { - UploadFilesDialog((list) => { + createFilePicker(extension).then((file) => { StreamingUploadHandler(url, { failure: () => alert("Your Upload has failed. Please try a different file or try again later"), uploadDone: () => console.log("Upload done"), credentials: () => API.getToken(), backendResponse: (id) => resolve(id), onUploadTick: async () => await delay(2), - }, list[0].file); - }, extension); + }, file); + }); }); } diff --git a/pages/admin/review.ts b/pages/admin/review.ts index 57d48fc..f1c5905 100644 --- a/pages/admin/review.ts +++ b/pages/admin/review.ts @@ -1,4 +1,6 @@ import { permCheck, RegisterAuthRefresh, renewAccessTokenIfNeeded, saveBlob, showPreviewImage, showProfilePicture } from "shared/helper.ts"; +import { API, stupidErrorAlert } from "shared/restSpec.ts"; +import { appendBody, Color, Content, Empty, Entry, Grid, isMobile, Label, PrimaryButton, Spinner, WebGenTheme } from "webgen/mod.ts"; import "../../assets/css/main.css"; import "../../assets/css/music.css"; import { DynaNavigation } from "../../components/nav.ts"; @@ -27,147 +29,148 @@ if (!data.id) { location.href = "/admin"; } -sheetStack.setDefault(Vertical( - DynaNavigation("Admin"), - Grid( - Vertical( - Label("User Details", "h1").setTextAlign("center"), - reviewState.$drop.map((drop) => - drop - ? Vertical( - showProfilePicture(drop.user), - Label(`Username: ${drop.user.profile.username}`), - Label(`Email: ${drop.user.profile.email}`), - Label(`ID: ${drop.user._id}`), - ).setGap() - : LoadingSpinner() - ).asRefComponent(), - Label("User's Drops", "h1").setTextAlign("center"), - reviewState.$drops.map((drops) => - drops - ? Vertical( - ...drops.map((drop) => Entry({ title: drop.title, subtitle: drop.type }).addClass("small")), - ).setGap() - : LoadingSpinner() - ).asRefComponent(), - ) - .setMaxHeight("calc(100vh - 53px)") - .setCssStyle("overflow", "auto") - .setCssStyle("border", "solid") - .setGap() - .setBorderRadius("tiny"), - reviewState.$drop.map((drop) => - drop - ? Navigation({ - title: drop.title, - children: [ - Label(DropTypeToText(drop.type)).setTextSize("2xl"), - { - id: "edit-drop", - title: "Drop", - subtitle: "Change Title, Release Date, ...", - children: [ - ChangeDrop(drop, drop.artistList), - ], - }, - { - id: "edit-songs", - title: "Songs", - subtitle: "Move Songs, Remove Songs, Add Songs, ...", +appendBody( + WebGenTheme( + Content( + DynaNavigation("Admin"), + Grid( + Grid( + Label("User Details", "h1").setTextAlign("center"), + reviewState.$drop.map((drop) => + drop + ? Grid( + showProfilePicture(drop.user), + Label(`Username: ${drop.user.profile.username}`), + Label(`Email: ${drop.user.profile.email}`), + Label(`ID: ${drop.user._id}`), + ).setGap() + : Spinner() + ).asRefComponent(), + Label("User's Drops", "h1").setTextAlign("center"), + reviewState.$drops.map((drops) => + drops + ? Grid( + drops.map((drop) => Entry({ title: drop.title, subtitle: drop.type }).addClass("small")), + ).setGap() + : Spinner() + ).asRefComponent(), + ) + .setMaxHeight("calc(100vh - 53px)") + .setCssStyle("overflow", "auto") + .setCssStyle("border", "solid") + .setGap() + .setBorderRadius("tiny"), + reviewState.$drop.map((drop) => + drop + ? Navigation({ + title: drop.title, children: [ - ChangeSongs(drop, drop.artistList), + Label(DropTypeToText(drop.type)).setTextSize("2xl"), + { + id: "edit-drop", + title: "Drop", + subtitle: "Change Title, Release Date, ...", + children: [ + ChangeDrop(drop, drop.artistList), + ], + }, + { + id: "edit-songs", + title: "Songs", + subtitle: "Move Songs, Remove Songs, Add Songs, ...", + children: [ + ChangeSongs(drop, drop.artistList), + ], + }, + { + id: "export", + title: "Export", + subtitle: "Download your complete Drop with every Song", + clickHandler: async () => { + const blob = await API.music.id(drop._id).download().then(stupidErrorAlert); + saveBlob(blob, `${drop.title}.tar`); + }, + }, ], - }, - { - id: "export", - title: "Export", - subtitle: "Download your complete Drop with every Song", - clickHandler: async () => { - const blob = await API.music.id(drop._id).download().then(stupidErrorAlert); - saveBlob(blob, `${drop.title}.tar`); - }, - }, - ], - }) - .addClass( - isMobile.map((mobile) => mobile ? "mobile-navigation" : "navigation"), - "limited-width", - ) - .setHeader((menu) => - isMobile.map((mobile) => { - const list = Vertical( - menu.path.map((x) => x == "-/" ? Grid(showPreviewImage(drop).addClass("image-preview")).setEvenColumns(1, "10rem") : Empty()).asRefComponent(), - createBreadcrumb(menu), - createTagList(menu), - ).setGap(); - if (!mobile) { - return Grid( - list, - createActionList(menu), - ).setRawColumns("auto max-content").setGap().setAlignItems("center"); - } - return list; - }).asRefComponent() - ) - : LoadingSpinner() - ).asRefComponent(), - Vertical( - Label("Drop History", "h1").setTextAlign("center"), - reviewState.$drop.map((drop) => - drop - ? Vertical( - ...drop.events.map((entry) => - Vertical( - Label(entry.meta.action), - Label(entry.userId), + }) + .addClass( + isMobile.map((mobile) => mobile ? "mobile-navigation" : "navigation"), + "limited-width", + ) + .setHeader((menu) => + isMobile.map((mobile) => { + const list = Grid( + menu.path.map((x) => x == "-/" ? Grid(showPreviewImage(drop).addClass("image-preview")).setEvenColumns(1, "10rem") : Empty()).asRefComponent(), + createBreadcrumb(menu), + createTagList(menu), + ).setGap(); + if (!mobile) { + return Grid( + list, + createActionList(menu), + ).setRawColumns("auto max-content").setGap().setAlignItems("center"); + } + return list; + }) + ) + : Spinner() + ).asRefComponent(), + Grid( + Label("Drop History", "h1").setTextAlign("center"), + reviewState.$drop.map((drop) => + drop + ? Grid( + ...drop.events.map((entry) => + Grid( + Label(entry.meta.action), + Label(entry.userId), + ).setGap() + ), ).setGap() - ), - ).setGap() - : LoadingSpinner() - ).asRefComponent(), - Spacer(), - Button("Change Drop Type") - .setStyle(ButtonStyle.Inline) - .setColor(Color.Colored) - .addClass("tag") - .setMargin("var(--gap)") - .onClick(() => { - changeTypeDialog.open(); - changeState.drop = reviewState.drop; - changeState.type = reviewState.drop!.type; - changeTypeDialog.setOnClose(() => refreshReviewState()); - }), - Horizontal( - Button("Decline") - .setStyle(ButtonStyle.Inline) - .setColor(Color.Colored) - .addClass("tag") - .onClick(() => { - DeclineDialog.open(); - dialogState.drop = reviewState.drop!; - DeclineDialog.setOnClose(() => refreshReviewState()); - }), - Button("Approve") - .setStyle(ButtonStyle.Normal) - .setColor(Color.Colored) - .addClass("tag") - .onClick(() => { - ApproveDialog.open(); - dialogState.drop = reviewState.drop!; - ApproveDialog.setOnClose(() => refreshReviewState()); - }), - ).setGap(), - ) - .setMaxHeight("calc(100vh - 53px)") - .setCssStyle("overflow", "auto") - .setCssStyle("border", "solid") - .setBorderRadius("tiny"), - ) - .setGap() - .setRawColumns("1fr 3fr 1fr"), -)); - -Body(sheetStack); + : Spinner() + ).asRefComponent(), + PrimaryButton("Change Drop Type") + .setStyle(ButtonStyle.Inline) + .setColor(Color.Colored) + .addClass("tag") + .setMargin("var(--gap)") + .onClick(() => { + changeTypeDialog.open(); + changeState.drop = reviewState.drop; + changeState.type = reviewState.drop!.type; + changeTypeDialog.setOnClose(() => refreshReviewState()); + }), + Grid( + PrimaryButton("Decline") + .setStyle(ButtonStyle.Inline) + .setColor(Color.Colored) + .addClass("tag") + .onClick(() => { + DeclineDialog.open(); + dialogState.drop = reviewState.drop!; + DeclineDialog.setOnClose(() => refreshReviewState()); + }), + PrimaryButton("Approve") + .setStyle(ButtonStyle.Normal) + .setColor(Color.Colored) + .addClass("tag") + .onClick(() => { + ApproveDialog.open(); + dialogState.drop = reviewState.drop!; + ApproveDialog.setOnClose(() => refreshReviewState()); + }), + ).setGap(), + ) + .setMaxHeight("calc(100vh - 53px)") + .setCssStyle("overflow", "auto") + .setCssStyle("border", "solid") + .setBorderRadius("tiny"), + ) + .setGap() + .setRawColumns("1fr 3fr 1fr"), + ), + ), +); renewAccessTokenIfNeeded() .then(() => refreshReviewState()); diff --git a/pages/admin/state.ts b/pages/admin/state.ts index 7b4fdda..b31aa3c 100644 --- a/pages/admin/state.ts +++ b/pages/admin/state.ts @@ -1,9 +1,9 @@ import { ProfileData } from "shared/helper.ts"; import { External } from "shared/mod.ts"; -import { asState } from "webgen/mod.ts"; +import { asRefRecord } from "webgen/mod.ts"; import { Artist, Drop, File, Group, OAuthApp, Payout, Server, Transcript, Wallet } from "../../spec/music.ts"; -export const state = asState({ +export const state = asRefRecord({ drops: { reviews: | "loading"> "loading", publishing: | "loading"> "loading", @@ -18,7 +18,7 @@ export const state = asState({ export type SearchResult = { _index: "transcripts"; _source: Transcript } | { _index: "drops"; _source: Drop } | { _index: "servers"; _source: Server } | { _index: "users"; _source: ProfileData } | { _index: "files"; _source: File } | { _index: "user-events"; _source: object } | { _index: "none" } | { _index: "empty" }; -export const reviewState = asState({ +export const reviewState = asRefRecord({ // deno-lint-ignore no-explicit-any drop: undefined, drops: undefined, diff --git a/pages/holding/imprint.ts b/pages/holding/imprint.ts index 3346c71..f1790e7 100644 --- a/pages/holding/imprint.ts +++ b/pages/holding/imprint.ts @@ -9,7 +9,7 @@ await RegisterAuthRefresh(); appendBody(Box( DynaNavigation("Home"), Box( - Label("Imprint", "h2"), + Label("Imprint").setTextSize("2xl"), Grid( Label("Phone:"), Label("+49 176 16818623"), @@ -29,8 +29,8 @@ appendBody(Box( Label("Maximilian Arzberger\nGregor Bigalke"), Label("Responsible for content:"), Label("Maximilian Arzberger, Gregor Bigalke\nRose-Luxemburg-Str. 37\n14482 Potsdam\nGermany"), - ).setEvenColumns(2).setGap().setCssStyle("white-space", "pre-wrap"), - Label(`Alternative dispute resolution`, "h3"), + ).setEvenColumns(2).setGap().setCssStyle("whiteSpace", "pre-wrap"), + Label(`Alternative dispute resolution`).setTextSize("xl"), Label( `The European Commission provides a platform for the out-of-court resolution of disputes (ODR platform), which can be viewed under ec.europa.eu/odr`, ).addClass("block"), diff --git a/pages/holding/index.ts b/pages/holding/index.ts index 7270cdc..1172a3c 100644 --- a/pages/holding/index.ts +++ b/pages/holding/index.ts @@ -1,7 +1,7 @@ -import { appendBody, Box, Grid, Label } from "webgen/mod.ts"; +import { RegisterAuthRefresh } from "shared/helper.ts"; +import { appendBody, Box, Empty, Grid, Image, Label } from "webgen/mod.ts"; import "../../assets/css/main.css"; import { DynaNavigation } from "../../components/nav.ts"; -import { RegisterAuthRefresh } from "../shared/helper.ts"; import "./landing.css"; import { data, streamingPool } from "./loading.ts"; // Main @@ -24,9 +24,9 @@ await RegisterAuthRefresh(); appendBody(Box( DynaNavigation("Home"), - Vertical( + Grid( Box( - Box().addClass("background-image"), + Empty().addClass("background-image"), Label("Your Journey,  our Mission.") .setFontWeight("bold"), ) @@ -35,7 +35,7 @@ appendBody(Box( Label("BBN One", "h2"), Label("Your all in one solution. Everything in “One” place.", "h3"), ).addClass("section"), - Box(Box()).addClass("glowbs", "orange"), + Box(Empty()).addClass("glowbs", "orange"), Grid( Box( Image(bbnMusic, "An orange logo of BBN Music"), diff --git a/pages/music-landing/main.ts b/pages/music-landing/main.ts index 27ef105..169ed9e 100644 --- a/pages/music-landing/main.ts +++ b/pages/music-landing/main.ts @@ -1,46 +1,47 @@ import { Footer } from "shared/footer.ts"; import { RegisterAuthRefresh } from "shared/helper.ts"; -import { MaterialIcon, mediaQueryRef, PrimaryButton, SheetHeader, Sheets, WebGenTheme } from "webgen/components/mod.ts"; +import { Image, MaterialIcon, mediaQueryRef, PrimaryButton, SheetHeader, Sheets, WebGenTheme } from "webgen/components/mod.ts"; import { Box, Content, Empty, FullWidthSection, Grid, Label } from "webgen/core/mod.ts"; import { appendBody } from "webgen/mod.ts"; import { DynaNavigation } from "../../components/nav.ts"; import "./main.css"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import apple from "./assets/apple.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import deezer from "./assets/deezer.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import facebook from "./assets/facebook.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import instagram from "./assets/instagram.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import pandora from "./assets/pandora.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import spotify from "./assets/spotify.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import tidal from "./assets/tidal.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import tiktok from "./assets/tiktok.svg"; -// // @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" -// import youtube from "./assets/youtube.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import apple from "./assets/apple.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import deezer from "./assets/deezer.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import facebook from "./assets/facebook.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import instagram from "./assets/instagram.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import pandora from "./assets/pandora.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import spotify from "./assets/spotify.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import tidal from "./assets/tidal.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import tiktok from "./assets/tiktok.svg"; +// @deno-types="https://raw.githubusercontent.com/lucsoft-DevTeam/lucsoft.de/master/custom.d.ts" +import youtube from "./assets/youtube.svg"; -// +import criticz from "./assets/criticz.jpg"; +import redz from "./assets/redz.jpg"; await RegisterAuthRefresh(); -// const images = () => -// Array.from({ length: 4 }, () => [ -// Image(apple, "Apple Music"), -// Image(deezer, "Deezer"), -// Image(facebook, "Facebook"), -// Image(instagram, "Instagram"), -// Image(pandora, "Pandora"), -// Image(spotify, "Spotify"), -// Image(tidal, "Tidal"), -// Image(tiktok, "TikTok"), -// Image(youtube, "Youtube"), -// ]).flat(); +const images = () => + Array.from({ length: 4 }, () => [ + Image(apple, "Apple Music"), + Image(deezer, "Deezer"), + Image(facebook, "Facebook"), + Image(instagram, "Instagram"), + Image(pandora, "Pandora"), + Image(spotify, "Spotify"), + Image(tidal, "Tidal"), + Image(tiktok, "TikTok"), + Image(youtube, "Youtube"), + ]).flat(); export const isMobileKeyFeatures = mediaQueryRef("(max-width: 820px)"); @@ -213,15 +214,16 @@ appendBody( .addClass("opacity-60"), ) .setMargin("10px 0 40px"), - Grid(Empty() // Grid(...images()) - // .addClass("icon-carousel") - // .setGap("38px") - // .setDirection("column"), - // Grid(...images().reverse()) - // .addClass("icon-carousel") - // .addClass("icon-carousel-reversed") - // .setGap("38px") - // .setDirection("column"), + Grid( + Grid(images()) + .setGap("38px") + .addClass("icon-carousel") + .setDirection("column"), + Grid(...images().reverse()) + .setGap("38px") + .addClass("icon-carousel") + .addClass("icon-carousel-reversed") + .setDirection("column"), ) .setGap("35px") .addClass("icon-carousel-container"), @@ -329,10 +331,10 @@ appendBody( .addClass("italic-text") .setFontWeight("bold"), Grid( - // Image(redz, "Avatar of Redz") - // .setBorderRadius("complete") - // .setAspectRatio("1/1") - // .resizeToBox(), + Image(redz, "Avatar of Redz") + // .setBorderRadius("complete") + .setAspectRatio("1/1") + .resizeToBox(), Label("Redz") .setFontWeight("bold") .setTextSize("xl"), @@ -350,10 +352,10 @@ appendBody( .addClass("italic-text") .setFontWeight("bold"), Grid( - // Image(criticz, "Avatar of Criticz") - // .setBorderRadius("complete") - // .setAspectRatio("1/1") - // .resizeToBox(), + Image(criticz, "Avatar of Criticz") + // .setBorderRadius("complete") + .setAspectRatio("1/1") + .resizeToBox(), Label("Criticz") .setFontWeight("bold") .setTextSize("xl"), diff --git a/pages/music/edit.ts b/pages/music/edit.ts index 09db0fa..b3adc38 100644 --- a/pages/music/edit.ts +++ b/pages/music/edit.ts @@ -1,5 +1,5 @@ -import { API, createActionList, createBreadcrumb, createTagList, LoadingSpinner, Navigation, stupidErrorAlert } from "shared/mod.ts"; -import { asRef, Body, Button, ButtonStyle, Color, Empty, Grid, Horizontal, isMobile, Label, LinkButton, SheetDialog, Vertical } from "webgen/mod.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"; @@ -22,7 +22,7 @@ const drop = asRef( undefined); const services = asRef | undefined>(undefined); const share = asRef( undefined); -sheetStack.setDefault(Vertical( +appendBody(Vertical( DynaNavigation("Music"), drop.map((drop) => drop @@ -143,8 +143,6 @@ sheetStack.setDefault(Vertical( ).asRefComponent(), )); -Body(sheetStack); - const Permissions = { canTakedown: (type: DropType) => type == "PUBLISHED", canSubmit: (type: DropType) => ( ["UNSUBMITTED", "PRIVATE"]).includes(type), diff --git a/pages/music/main.ts b/pages/music/main.ts index 90c87e4..9135dad 100644 --- a/pages/music/main.ts +++ b/pages/music/main.ts @@ -1,6 +1,6 @@ import { RegisterAuthRefresh, renewAccessTokenIfNeeded, sheetStack } from "shared/helper.ts"; import { API, stupidErrorAlert } from "shared/restSpec.ts"; -import { Body, Vertical } from "webgen/mod.ts"; +import { appendBody, Content, DialogContainer, WebGenTheme } from "webgen/mod.ts"; import "../../assets/css/main.css"; import "../../assets/css/music.css"; import { DynaNavigation } from "../../components/nav.ts"; @@ -9,9 +9,15 @@ import { menuState, musicMenu } from "./views/menu.ts"; await RegisterAuthRefresh(); -sheetStack.setDefault(Vertical(DynaNavigation("Music"), musicMenu)); - -Body(sheetStack); +appendBody( + WebGenTheme( + DialogContainer(sheetStack.visible(), sheetStack), + Content( + DynaNavigation("Music"), + musicMenu, + ), + ), +); renewAccessTokenIfNeeded() .then(async () => { diff --git a/pages/music/newDrop.ts b/pages/music/newDrop.ts index ec4ad1d..809a7d7 100644 --- a/pages/music/newDrop.ts +++ b/pages/music/newDrop.ts @@ -1,12 +1,11 @@ -import { API, LoadingSpinner, stupidErrorAlert } from "shared/mod.ts"; -import { AdvancedImage, asRef, asState, Body, Box, Button, ButtonStyle, Center, CenterV, Color, createFilePicker, Custom, DropAreaInput, DropDownInput, Empty, getErrorMessage, Grid, Horizontal, Image, Label, MediaQuery, Reference, SheetDialog, Spacer, TextInput, Validate, Vertical } from "webgen/mod.ts"; -import { zod } from "webgen/zod.ts"; +import { allowedAudioFormats, allowedImageFormats, CenterAndRight, ExistingSongDialog, getSecondary, RegisterAuthRefresh, sheetStack } from "shared/helper.ts"; +import { API, stupidErrorAlert } from "shared/mod.ts"; +import { appendBody, asRef, asRefRecord, Box, Content, createFilePicker, DialogContainer, DropDown, Empty, Grid, Image, Label, PrimaryButton, SecondaryButton, SheetHeader, Spinner, TextInput, WebGenTheme } from "webgen/mod.ts"; import "../../assets/css/main.css"; import { DynaNavigation } from "../../components/nav.ts"; import genres from "../../data/genres.json" with { type: "json" }; import language from "../../data/language.json" with { type: "json" }; import { ArtistRef, ArtistTypes, DropType, pages, Song } from "../../spec/music.ts"; -import { allowedAudioFormats, allowedImageFormats, CenterAndRight, ExistingSongDialog, getSecondary, RegisterAuthRefresh, sheetStack } from "../shared/helper.ts"; import { uploadArtwork, uploadSongToDrop } from "./data.ts"; import { EditArtistsDialog, ManageSongs } from "./views/table.ts"; @@ -26,7 +25,7 @@ if (!params.has("id")) { } const dropId = params.get("id")!; -export const creationState = asState({ +export const creationState = asRefRecord({ loaded: false, _id: undefined, gtin: undefined, @@ -54,41 +53,43 @@ API.music.id(dropId).get().then(stupidErrorAlert) creationState.title = drop.title; creationState.release = drop.release; creationState.language = drop.language; - creationState.artists = asState(drop.artists ?? [{ type: ArtistTypes.Primary, _id: null! }]); + creationState.artists = drop.artists ?? [{ type: ArtistTypes.Primary, _id: null! }]; creationState.primaryGenre = drop.primaryGenre; creationState.secondaryGenre = drop.secondaryGenre; creationState.compositionCopyright = drop.compositionCopyright ?? "BBN Music (via bbn.one)"; creationState.soundRecordingCopyright = drop.soundRecordingCopyright ?? "BBN Music (via bbn.one)"; creationState.artwork = drop.artwork; creationState.artworkClientData = (drop.artwork ? { type: "direct", source: () => API.music.id(dropId).artwork().then(stupidErrorAlert) } : undefined); - creationState.songs = asState(drop.songs ?? []); + creationState.songs = drop.songs ?? []; creationState.comments = drop.comments; }) .then(() => creationState.loaded = true); -const additionalDropInformation = SheetDialog( - sheetStack, - "Additional Information", - Vertical( +const additionalDropInformation = Grid( + SheetHeader("Additional Information", sheetStack), + Grid( Grid( - TextInput("text", "UPC/EAN").ref(creationState.$gtin), - TextInput("text", "Composition Copyright").ref(creationState.$compositionCopyright), - TextInput("text", "Sound Recording Copyright").ref(creationState.$soundRecordingCopyright), + TextInput(creationState.gtin, "UPC/EAN"), + TextInput(creationState.compositionCopyright, "Composition Copyright"), + TextInput(creationState.soundRecordingCopyright, "Sound Recording Copyright"), ) + .setGap() .setEvenColumns(1) - .addClass("grid-area") - .setGap(), - Horizontal(Spacer(), Button("Save").onClick(() => additionalDropInformation.close())), + .addClass("grid-area"), + PrimaryButton("Save").onClick(() => sheetStack.removeOne()), ).setGap(), ); -sheetStack.setDefault(Vertical( - DynaNavigation("Music"), - creationState.$loaded.map((loaded) => loaded ? wizard : LoadingSpinner()).asRefComponent(), -)); +appendBody( + WebGenTheme( + DialogContainer(sheetStack.visible(), sheetStack), + Content( + DynaNavigation("Music"), + Box(creationState.loaded.map((loaded) => loaded ? wizard : Spinner())), + ), + ).addClass("fullscreen"), +); -Body(sheetStack) - .addClass("fullscreen"); Custom(document.body).setAttribute("data-theme", undefined); const validator = (page: number) => async () => { @@ -102,11 +103,10 @@ const validator = (page: number) => async () => { }; const footer = (page: number) => - Horizontal( - page == 0 ? Button("Cancel").setJustifyContent("center").setStyle(ButtonStyle.Secondary).onClick(() => location.href = "/c/music") : Button("Back").setJustifyContent("center").setStyle(ButtonStyle.Secondary).onClick(() => creationState.page--), - Spacer(), + Grid( + page == 0 ? SecondaryButton("Cancel").setJustifyContent("center").onClick(() => location.href = "/c/music") : SecondaryButton("Back").setJustifyContent("center").onClick(() => creationState.page--), Box( - creationState.$validationState.map((error) => + creationState.validationState.map((error) => error ? CenterV( Label(getErrorMessage(error)) @@ -114,131 +114,111 @@ const footer = (page: number) => .setMargin("0 0.5rem 0 0"), ) : Empty() - ).asRefComponent(), + ), ), - Button("Next").setJustifyContent("center").onClick(validator(page)), + PrimaryButton("Next").setJustifyContent("center").onClick(validator(page)), ).addClass("footer"); -const wizard = creationState.$page.map((page) => { +const wizard = creationState.page.map((page) => { if (page == 0) { - return Vertical( - Spacer(), + return Grid( MediaQuery("(max-width: 450px)", (small) => Grid( - Center(Label("Enter your Album details.").addClass("title")), - TextInput("text", "Title").ref(creationState.$title), + Label("Enter your Album details.").addClass("title"), + TextInput(creationState.title, "Title"), Grid( - TextInput("date", "Release Date").ref(creationState.$release), - DropDownInput("Language", Object.keys(language)) - .setRender((key) => language[ key]) - .ref(creationState.$language), + TextInput(creationState.release, "Release Date"), + DropDown(Object.keys(language), creationState.language, "Language") + .setValueRender((key) => language[ key]), ) .setEvenColumns(small ? 1 : 2) .setGap(), - Button("Artists") - .onClick(() => EditArtistsDialog(creationState.$artists as unknown as Reference).open()), - Center(Label("Set your target Audience").addClass("title")), + PrimaryButton("Artists") + .onClick(() => EditArtistsDialog(creationState.artists).open()), + Label("Set your target Audience").addClass("title"), Grid( - DropDownInput("Primary Genre", Object.keys(genres)) - .ref(creationState.$primaryGenre) - .onChange(() => creationState.$secondaryGenre.setValue(undefined)), - creationState.$primaryGenre.map((primaryGenre) => - DropDownInput("Secondary Genre", getSecondary(genres, primaryGenre) ?? []) - .ref(creationState.$secondaryGenre) + DropDown(Object.keys(genres), creationState.primaryGenre, "Primary Genre"), + // .onChange(() => creationState.secondaryGenre.setValue(undefined)), //move to listen + Box(creationState.primaryGenre.map((primaryGenre) => + DropDown(getSecondary(genres, primaryGenre) ?? [], creationState.secondaryGenre, "Secondary Genre") .setColor(getSecondary(genres, primaryGenre) ? Color.Grayscaled : Color.Disabled) - ).asRefComponent(), + )), ) .setGap() .setEvenColumns(small ? 1 : 2), - Button("Additional Information") - .onClick(() => additionalDropInformation.open()), + PrimaryButton("Additional Information") + .onClick(() => sheetStack.addSheet(additionalDropInformation)), ) + .setGap() .setEvenColumns(1) - .addClass("grid-area") - .setGap()), - Spacer(), + .addClass("grid-area")), footer(page), ).addClass("wwizard"); } else if (page == 1) { - return Vertical( - Spacer(), - Center( - creationState.$artworkClientData.map((data) => - Vertical( - CenterAndRight( - Label("Upload your Cover").addClass("title"), - Button("Manual Upload") - .onClick(() => createFilePicker(allowedImageFormats.join(",")).then((file) => uploadArtwork(dropId, file, creationState.$artworkClientData, creationState.$artwork))), - ), - DropAreaInput( - CenterV(data ? Image(data, "A Music Album Artwork.") : Label("Drop your Artwork here.").setTextSize("xl").setFontWeight("semibold")), - allowedImageFormats, - ([{ file }]) => uploadArtwork(dropId, file, creationState.$artworkClientData, creationState.$artwork), - ).addClass("drop-area"), - ).setGap() - ).asRefComponent(), + return Grid( + creationState.artworkClientData.map((data) => + Grid( + CenterAndRight( + Label("Upload your Cover").addClass("title"), + PrimaryButton("Manual Upload") + .onClick(() => createFilePicker(allowedImageFormats.join(",")).then((file) => uploadArtwork(dropId, file, creationState.artworkClientData, creationState.artwork))), + ), + DropAreaInput( + CenterV(data ? Image(data, "A Music Album Artwork.") : Label("Drop your Artwork here.").setTextSize("xl").setFontWeight("semibold")), + allowedImageFormats, + ([{ file }]) => uploadArtwork(dropId, file, creationState.artworkClientData, creationState.artwork), + ).addClass("drop-area"), + ).setGap() ), - Spacer(), footer(page), ).addClass("wwizard"); } else if (page == 2) { - creationState.$songs.listen((songs, oldVal) => { + creationState.songs.listen((songs, oldVal) => { if (oldVal != undefined) { - creationState.$songs.setValue(songs); + creationState.songs.setValue(songs); } }); const songs = asRef( undefined); const existingSongDialog = ExistingSongDialog(creationState.songs, songs); - return Vertical( - Spacer(), - Horizontal( - Spacer(), - Vertical( + return Grid( + Grid( + Grid( CenterAndRight( Label("Manage your Music").addClass("title"), Box( - Button("Manual Upload") - .onClick(() => createFilePicker(allowedAudioFormats.join(",")).then((file) => uploadSongToDrop(creationState.$songs, creationState.artists, creationState.language, creationState.primaryGenre, creationState.secondaryGenre, creationState.$uploadingSongs, file))).setMargin("0 1rem 0 0"), - Button("Add an existing Song") + PrimaryButton("Manual Upload") + .onClick(() => createFilePicker(allowedAudioFormats.join(",")).then((file) => uploadSongToDrop(creationState.songs, creationState.artists, creationState.language, creationState.primaryGenre, creationState.secondaryGenre, creationState.uploadingSongs, file))).setMargin("0 1rem 0 0"), + PrimaryButton("Add an existing Song") .onPromiseClick(async () => { - songs.setValue((await API.music.songs.list().then(stupidErrorAlert)).filter((song) => creationState.songs.some((dropsong) => dropsong._id !== song._id))); + songs.setValue((await API.music.songs.list().then(stupidErrorAlert)).filter((song) => creationState.songs.value.some((dropsong) => dropsong._id !== song._id))); existingSongDialog.open(); }), ), ), - ManageSongs(creationState.$songs as unknown as Reference, creationState.$uploadingSongs, creationState.primaryGenre!), + ManageSongs(creationState.songs, creationState.uploadingSongs, creationState.primaryGenre!), ).setGap(), - Spacer(), ), - Spacer(), footer(page), ).addClass("wwizard"); } else if (page == 3) { - return Vertical( - Spacer(), - Horizontal( - Spacer(), + return Grid( + Grid( Label("Thanks! That's everything we need.").setBalanced().addClass("ending-title"), - Spacer(), ), - Horizontal( - Spacer(), - TextInput("text", "Comments for Review Team").ref(creationState.$comments), - Spacer(), + Grid( + TextInput(creationState.comments, "Comments for Review Team"), ), - Spacer(), - Horizontal( - Button("Back").setJustifyContent("center").setStyle(ButtonStyle.Secondary).onClick(() => creationState.page--), - Spacer(), - Button("Submit").setJustifyContent("center").onPromiseClick(async () => { + Grid( + SecondaryButton("Back").setJustifyContent("center").onClick(() => creationState.page--), + PrimaryButton("Submit").onPromiseClick(async () => { creationState.loaded = false; await API.music.id(dropId).update(creationState); await API.music.id(dropId).type.post(DropType.UnderReview); location.href = "/c/music"; - }), + }).setJustifyContent("center"), ).addClass("footer"), ).addClass("wwizard"); } - return LoadingSpinner(); -}).asRefComponent(); + return Spinner(); +}); diff --git a/pages/music/share.ts b/pages/music/share.ts index cf84314..dc049e2 100644 --- a/pages/music/share.ts +++ b/pages/music/share.ts @@ -1,6 +1,6 @@ +import { streamingImages } from "shared/helper.ts"; import { API, stupidErrorAlert } from "shared/restSpec.ts"; -import { asRef, Body, Empty, Horizontal, Image, Label, LinkButton, Vertical } from "webgen/mod.ts"; -import { sheetStack, streamingImages } from "../shared/helper.ts"; +import { appendBody, asRef, Content, Empty, Image, Label, WebGenTheme } from "webgen/mod.ts"; import "./share.css"; const params = new URLSearchParams(location.search); @@ -28,35 +28,39 @@ if (reqShare.status === "rejected") { share.setValue(stupidErrorAlert(reqShare)); -sheetStack.setDefault(Vertical( - Image({ type: "direct", source: () => API.music.share(data.s).artwork().then(stupidErrorAlert) }, "Background").addClass("bgImg"), - share.map((shareVal) => - shareVal - ? Horizontal( - Vertical( - Image({ type: "direct", source: () => API.music.share(data.s).artwork().then(stupidErrorAlert) }, "A Song Artwork") - .setMinHeight("250px").setMinWidth("250px").setBorderRadius("mid"), - Label(shareVal.title).setTextAlign("center").setTextSize("2xl").setMargin("0 10px 0 0"), - Label(shareVal.artistNames.join(", ")).setTextAlign("center"), - Vertical( - ...Object.entries(shareVal.services).map(([key, val]) => - LinkButton( - Horizontal( - streamingImages[key] - .setHeight("1.5rem") - .setWidth("1.5rem").setMargin("0 10px 0 0"), - Label(key[0].toUpperCase() + key.slice(1)).setTextSize("xl"), - ), - val, - "_blank", - ) - ), - ).setGap("0.5rem").setMargin("10px 0 0 0"), - Label("Powered by BBN Music").setTextAlign("center").setMargin("10px 0 0 0"), - ).addClass("share").setPadding("1rem").setBorderRadius("mid"), - ) - : Empty() - ).asRefComponent(), -)); - -Body(sheetStack); +appendBody( + WebGenTheme( + Content( + Grid( + Image({ type: "direct", source: () => API.music.share(data.s).artwork().then(stupidErrorAlert) }, "Background").addClass("bgImg"), + share.map((shareVal) => + shareVal + ? Grid( + Grid( + Image({ type: "direct", source: () => API.music.share(data.s).artwork().then(stupidErrorAlert) }, "A Song Artwork") + .setMinHeight("250px").setMinWidth("250px").setBorderRadius("mid"), + Label(shareVal.title).setTextAlign("center").setTextSize("2xl").setMargin("0 10px 0 0"), + Label(shareVal.artistNames.join(", ")).setTextAlign("center"), + Grid( + ...Object.entries(shareVal.services).map(([key, val]) => + LinkButton( + Horizontal( + streamingImages[key] + .setHeight("1.5rem") + .setWidth("1.5rem").setMargin("0 10px 0 0"), + Label(key[0].toUpperCase() + key.slice(1)).setTextSize("xl"), + ), + val, + "_blank", + ) + ), + ).setGap("0.5rem").setMargin("10px 0 0 0"), + Label("Powered by BBN Music").setTextAlign("center").setMargin("10px 0 0 0"), + ).addClass("share").setPadding("1rem").setBorderRadius("mid"), + ) + : Empty() + ), + ), + ), + ), +); diff --git a/serve.ts b/serve.ts index 650bc2e..90e3dea 100644 --- a/serve.ts +++ b/serve.ts @@ -1,7 +1,7 @@ import { serve } from "https://deno.land/x/esbuild_serve@1.5.0/mod.ts"; // import { serve } from "../esbuild_serve/mod.ts"; -CI FAIL +// CI FAIL const title = new Map(Object.entries({ "index": "BBN Music",