Skip to content

Commit

Permalink
still highly wip: webgen changes
Browse files Browse the repository at this point in the history
  • Loading branch information
GregTCLTK committed Jan 13, 2024
1 parent bc218bd commit 6346e09
Show file tree
Hide file tree
Showing 13 changed files with 297 additions and 251 deletions.
3 changes: 1 addition & 2 deletions pages/_legacy/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,7 @@ export const EditArtistsDialog = (state: StateHandler<{ artists: Artist[]; }>) =
.setValue(artist[ 0 ])
.onChange(data => artist[ 0 ] = data ?? "")
)
//how to handle without index?
.addColumn("", () => IconButton(MIcon("delete"), "Delete").onClick(() => "remove")),
.addColumn("", (data) => IconButton(MIcon("delete"), "Delete").onClick(() => state.artists = state.artists.filter((_, i) => i != state.artists.indexOf(data)) as typeof state.artists)),
Horizontal(
Spacer(),
Button("Add Artist")
Expand Down
165 changes: 86 additions & 79 deletions pages/_legacy/music/changeDrop.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,98 @@
import { API, stupidErrorAlert } from "shared/mod.ts";
import { AdvancedImage, Box, Button, DropAreaInput, DropDownInput, Grid, IconButton, Image, MIcon, Spacer, TextInput, createFilePicker } from "webgen/mod.ts";
import * as zod from "https://deno.land/x/zod@v3.22.4/mod.ts";
import { ZodError } from "https://deno.land/x/zod@v3.22.4/mod.ts";
import { API } from "shared/mod.ts";
import { AdvancedImage, Box, Button, CenterV, DropAreaInput, DropDownInput, Empty, Grid, Horizontal, IconButton, Image, Label, MIcon, Spacer, StateHandler, TextInput, Validate, createFilePicker, getErrorMessage } from "webgen/mod.ts";
import artwork from "../../../assets/img/template-artwork.png";
import genres from "../../../data/genres.json" with { type: "json" };
import language from "../../../data/language.json" with { type: "json" };
import { ArtistTypes, Drop } from "../../../spec/music.ts";
import { Artist, DATE_PATTERN, artist, song, userString } from "../../../spec/music.ts";
import { EditArtistsDialog, allowedImageFormats, getSecondary } from "../helper.ts";
import { uploadArtwork } from "./data.ts";

export function ChangeDrop(drop: Drop) {
return Wizard({
submitAction: async (data) => {
let obj = structuredClone(drop);
data.map(x => x.data.data).forEach(x => obj = { ...obj, ...x });
await API.music.id(drop._id).update(obj);
location.reload(); // Handle this Smarter => Make it a Reload Event.
},
buttonArrangement: "flex-end",
buttonAlignment: "top",
}, () => [
Page({
title: drop.title,
release: drop.release,
language: drop.language,
artists: drop.artists,
primaryGenre: drop.primaryGenre,
secondaryGenre: drop.secondaryGenre,
compositionCopyright: drop.compositionCopyright,
soundRecordingCopyright: drop.soundRecordingCopyright,

loading: false,
artwork: drop.artwork,
artworkClientData: <AdvancedImage | string | undefined>(drop.artwork ? <AdvancedImage>{ type: "direct", source: () => API.music.id(drop._id).artwork().then(stupidErrorAlert) } : undefined),
export function ChangeDrop(state: StateHandler<{ _id: string | undefined, title: string | undefined, release: string | undefined, language: string | undefined, artists: Artist[], artwork: string | undefined, artworkClientData: AdvancedImage | string | undefined; compositionCopyright: string | undefined, soundRecordingCopyright: string | undefined, primaryGenre: string | undefined, secondaryGenre: string | undefined, loading: boolean; validationState: ZodError | undefined; }>) {
const { data, error, validate } = Validate(
state,
zod.object({
title: userString,
artists: artist.array().refine(x => x.some(([ , , type ]) => type == "PRIMARY"), { message: "At least one primary artist is required" }),
release: zod.string().regex(DATE_PATTERN, { message: "Not a date" }),
language: zod.string(),
primaryGenre: zod.string(),
secondaryGenre: zod.string(),
compositionCopyright: userString,
soundRecordingCopyright: userString,
artwork: zod.string(),
loading: zod.literal(false, { errorMap: () => ({ message: "Artwork is still uploading" }) }).transform(() => undefined),
songs: song.array().min(1, { message: "At least one song is required" }),
})
);

uploadingSongs: [],
songs: drop.songs
}, data => [
return Grid(
[
{ width: 2 },
Horizontal(
Box(data.$validationState.map(error => error ? CenterV(
Label(getErrorMessage(error))
.addClass("error-message")
.setMargin("0 0.5rem 0 0")
)
: Empty()).asRefComponent()),
Spacer(),
Button("Save")
.onClick(async () => {
const validation = validate();
if (error.getValue()) return data.validationState = error.getValue();
if (validation) await API.music.id(state._id!).update(validation);
location.reload(); // Handle this Smarter => Make it a Reload Event.
})
),
],
Grid(
data.$artworkClientData.map(artworkData => DropAreaInput(
Box(artworkData ? Image(artworkData, "A Music Album Artwork.") : Image(artwork, "A Default Alubm Artwork."), IconButton(MIcon("edit"), "edit icon"))
.addClass("upload-image"),
allowedImageFormats,
([ { file } ]) => uploadArtwork(data, file)
).onClick(() => createFilePicker(allowedImageFormats.join(",")).then(file => uploadArtwork(data, file)))).asRefComponent(),
).setDynamicColumns(2, "12rem"),
[
{ width: 2 },
TextInput("text", "Title").sync(data, "title")
],
TextInput("date", "Release Date").sync(data, "release"),
DropDownInput("Language", Object.keys(language))
.setRender((key) => language[ <keyof typeof language>key ])
.sync(data, "language"),
[
{ width: 2 },
Button("Artists")
.onClick(() => {
EditArtistsDialog(data).open();
}),
],
[ { width: 2, height: 2 }, Spacer() ],
[
{ width: 2 },
Grid(
Grid(
data.$artworkClientData.map(() => DropAreaInput(
Box(data.artworkClientData ? Image(data.artworkClientData, "A Music Album Artwork.") : Image(artwork, "A Default Alubm Artwork."), IconButton(MIcon("edit"), "edit icon"))
.addClass("upload-image"),
allowedImageFormats,
([ { file } ]) => uploadArtwork(data, file)
).onClick(() => createFilePicker(allowedImageFormats.join(",")).then(file => uploadArtwork(data, file)))).asRefComponent(),
).setDynamicColumns(2, "12rem"),
[
{ width: 2 },
TextInput("text", "Title").sync(data, "title")
],
TextInput("date", "Release Date").sync(data, "release"),
DropDownInput("Language", Object.keys(language))
.setRender((key) => language[ <keyof typeof language>key ])
.sync(data, "language"),
[
{ width: 2 },
// TODO: Make this a nicer component
Button("Artists")
.onClick(() => {
EditArtistsDialog(data.artists ?? [ [ "", "", ArtistTypes.Primary ] ]).open();
}),
],
[ { width: 2, height: 2 }, Spacer() ],
[
{ width: 2 },
Grid(
DropDownInput("Primary Genre", Object.keys(genres))
.sync(data, "primaryGenre")
.onChange(() => {
data.secondaryGenre = undefined!;
}),
data.$primaryGenre.map(() => DropDownInput("Secondary Genre", getSecondary(genres, data.primaryGenre) ?? [])
.sync(data, "secondaryGenre")
.addClass("border-box")
.setWidth("100%")
).asRefComponent(),
)
.setEvenColumns(2, "minmax(2rem, 20rem)")
.setGap("15px")
],
TextInput("text", "Composition Copyright").sync(data, "compositionCopyright"),
TextInput("text", "Sound Recording Copyright").sync(data, "soundRecordingCopyright")
DropDownInput("Primary Genre", Object.keys(genres))
.sync(data, "primaryGenre")
.onChange(() => {
data.secondaryGenre = undefined!;
}),
data.$primaryGenre.map(primaryGenre => DropDownInput("Secondary Genre", getSecondary(genres, primaryGenre) ?? [])
.sync(data, "secondaryGenre")
.addClass("border-box")
.setWidth("100%")
).asRefComponent(),
)
.setEvenColumns(2, "minmax(2rem, 20rem)")
.addClass("settings-form")
.addClass("limited-width")
.setGap("15px")
]).setValidator(() => pureDrop)
]
);
],
TextInput("text", "Composition Copyright").sync(data, "compositionCopyright"),
TextInput("text", "Sound Recording Copyright").sync(data, "soundRecordingCopyright")
)
.setEvenColumns(2, "minmax(2rem, 20rem)")
.addClass("settings-form")
.addClass("limited-width")
.setGap("15px");
}
95 changes: 46 additions & 49 deletions pages/_legacy/music/changeSongs.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,62 @@
import * as zod from "https://deno.land/x/zod@v3.22.4/mod.ts";
import { API } from "shared/mod.ts";
import { Button, Grid, Horizontal, Spacer, State, Validate, createFilePicker } from "webgen/mod.ts";
import { Drop } from "../../../spec/music.ts";
import { AdvancedImage, Box, Button, CenterV, Empty, Grid, Horizontal, Label, Spacer, StateHandler, Validate, createFilePicker, getErrorMessage } from "webgen/mod.ts";
import { Artist, DATE_PATTERN, Song, artist, song, userString } from "../../../spec/music.ts";
import { allowedAudioFormats } from "../helper.ts";
import { uploadSongToDrop } from "./data.ts";
import { ManageSongs } from "./table.ts";

export function ChangeSongs(drop: Drop) {
export function ChangeSongs(state: StateHandler<{ _id: string | undefined, songs: Song[], title: string | undefined, release: string | undefined, language: string | undefined, artists: Artist[], artwork: string | undefined, artworkClientData: AdvancedImage | string | undefined; compositionCopyright: string | undefined, soundRecordingCopyright: string | undefined, primaryGenre: string | undefined, secondaryGenre: string | undefined, loading: boolean; validationState: zod.ZodError | undefined; }>) {
const { data, error, validate } = Validate(
State({
drop
}),
state,
zod.object({
drop: zod.any(),
title: userString,
artists: artist.array().refine(x => x.some(([ , , type ]) => type == "PRIMARY"), { message: "At least one primary artist is required" }),
release: zod.string().regex(DATE_PATTERN, { message: "Not a date" }),
language: zod.string(),
primaryGenre: zod.string(),
secondaryGenre: zod.string(),
compositionCopyright: userString,
soundRecordingCopyright: userString,
artwork: zod.string(),
loading: zod.literal(false, { errorMap: () => ({ message: "Artwork is still uploading" }) }).transform(() => undefined),
songs: song.array().min(1, { message: "At least one song is required" }),
})
);

return Grid(
ManageSongs(data),
Horizontal(
Spacer(),
Button("Add a new Song")
.onClick(() => createFilePicker(allowedAudioFormats.join(",")).then(file => uploadSongToDrop(data, file)))
),
Button("Save Changes").onPromiseClick(async () => {
validate();
if (error) return;
let obj = structuredClone(drop);
data.map(x => x.data.data).forEach(x => obj = { ...obj, ...x });
await API.music.id(drop._id).update(obj);
location.reload(); // Handle this Smarter => Make it a Reload Event.
})
[
{ width: 2 },
Horizontal(
Box(data.$validationState.map(error => error ? CenterV(
Label(getErrorMessage(error))
.addClass("error-message")
.setMargin("0 0.5rem 0 0")
)
: Empty()).asRefComponent()),
Spacer(),
Button("Save")
.onClick(async () => {
const validation = validate();
if (error.getValue()) return data.validationState = error.getValue();
if (validation) await API.music.id(state._id!).update(validation);
location.reload(); // Handle this Smarter => Make it a Reload Event.
})
),
],
[
{ width: 2 },
ManageSongs(data),
],
[
{ width: 2 },
Horizontal(
Spacer(),
Button("Add a new Song")
.onClick(() => createFilePicker(allowedAudioFormats.join(",")).then(file => uploadSongToDrop(data, file)))
)
],
)
.setGap("15px")
.setPadding("15px 0 0 0");

// return Wizard({
// submitAction: async (data) => {
// let obj = structuredClone(drop);
// data.map(x => x.data.data).forEach(x => obj = { ...obj, ...x });
// await API.music.id(drop._id).update(obj);
// location.reload(); // Handle this Smarter => Make it a Reload Event.
// },
// buttonArrangement: "flex-end",
// buttonAlignment: "top",
// }, ({ PageData }) => [
// Page({
// uploadingSongs: <string[]>[],
// songs: drop.songs
// }, data => [
// Grid(
// ManageSongs(data),
// Horizontal(
// Spacer(),
// Button("Add a new Song")
// .onClick(() => uploadFilesDialog((list) => uploadSongToDrop(data, getDropFromPages(PageData(), drop), list), allowedAudioFormats.join(",")))
// )
// )
// .setGap("15px")
// .setPadding("15px 0 0 0")
// ]).setValidator(() => pageFive)
// ]
// );
}
2 changes: 0 additions & 2 deletions pages/_legacy/music/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { delay } from "std/async/delay.ts";
import { AdvancedImage, State, StateHandler } from "webgen/mod.ts";
import { Artist, Song } from "../../../spec/music.ts";

// TODO: Remove all theses spread operator, update values directly,

export function uploadSongToDrop(state: StateHandler<{ uploadingSongs: string[]; songs: Song[]; artists: Artist[], language: string | undefined, primaryGenre: string | undefined, secondaryGenre: string | undefined, _id: string; }>, file: File) {
const uploadId = crypto.randomUUID();
state.uploadingSongs.push(uploadId);
Expand Down

0 comments on commit 6346e09

Please sign in to comment.