Skip to content

Commit

Permalink
add guild banner setting
Browse files Browse the repository at this point in the history
  • Loading branch information
jay3332 committed Jul 5, 2024
1 parent d35c1ca commit c637053
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 23 deletions.
30 changes: 16 additions & 14 deletions src/components/settings/EditableAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,26 @@ export interface Props {
setImageData: Setter<string | null | undefined>
}

export function promptImageUpload(setData: (data: string) => any) {
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/png, image/jpeg, image/gif'
input.onchange = async () => {
const file = input.files![0]
if (!file) return

const reader = new FileReader()
reader.onload = () => setData(reader.result as string)
reader.readAsDataURL(file)
}
input.click()
}

export default function EditableAvatar(props: ParentProps<Props>) {
return (
<button
class="group relative rounded-[50%] hover:rounded-lg overflow-hidden transition-all duration-200"
onClick={() => {
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/png, image/jpeg, image/gif'
input.onchange = async () => {
const file = input.files![0]
if (!file) return

const reader = new FileReader()
reader.onload = () => props.setImageData(reader.result as string)
reader.readAsDataURL(file)
}
input.click()
}}
onClick={() => promptImageUpload(props.setImageData)}
>
<div
class="absolute inset-0 flex flex-col items-center justify-center bg-black/60 backdrop-blur rounded-lg
Expand Down
81 changes: 72 additions & 9 deletions src/pages/guilds/settings/Overview.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import Header from "../../../components/ui/Header";
import EditableAvatar from "../../../components/settings/EditableAvatar";
import EditableAvatar, {promptImageUpload} from "../../../components/settings/EditableAvatar";
import {createEffect, createMemo, createSignal, createUniqueId, on, Show} from "solid-js";
import {useParams} from "@solidjs/router";
import {getApi} from "../../../api/Api";
import {acronym} from "../../../utils";
import {AccountField, EditingState, SaveCancel} from "../../settings/Account";
import {useSaveTask} from "../../settings/SettingsLayout";
import Icon from "../../../components/icons/Icon";
import ArrowUpFromBracket from "../../../components/icons/svg/ArrowUpFromBracket";

export default function Overview() {
const api = getApi()!
Expand Down Expand Up @@ -34,13 +37,8 @@ export default function Overview() {
const [iconData, setIconData] = createSignal<string | null | undefined>(undefined)
const previewIcon = createMemo(() => iconData() === undefined ? guild().icon : iconData() as string)

const [bannerData, setBannerData] = createSignal<string | null | undefined>(undefined)
const previewBanner = createMemo(() => bannerData() === undefined ? guild().banner : bannerData() as string)

createEffect(on([iconData, bannerData], () => {
if (iconData() === undefined && bannerData() === undefined)
return

createEffect(on(iconData, (data) => {
if (data === undefined) return
setEditing(EditingState.Editing)
updateChanged()
}))
Expand All @@ -65,6 +63,24 @@ export default function Overview() {
setEditing(EditingState.NotEditing)
}

const [bannerData, setBannerData] = createSignal<string | null | undefined>(undefined)
const previewBanner = createMemo(() => bannerData() === undefined ? guild().banner : bannerData() as string)

const [setEdited] = useSaveTask(
async () => {
const json: Record<string, any> = {}
if (bannerData() !== undefined) json.banner = bannerData()

const response = await api.request('PATCH', `/guilds/${guildId()}`, { json })
if (!response.ok)
setError(response.errorJsonOrThrow().message)
},
() => {
setBannerData(undefined)
}
)
createEffect(() => setEdited(bannerData() !== undefined))

return (
<div class="px-2 py-4">
<Header>Overview</Header>
Expand Down Expand Up @@ -135,7 +151,54 @@ export default function Overview() {
<p class="p-3 text-sm bg-danger/20 text-danger w-full">{error()}</p>
</Show>
</div>
<h2 class="font-bold uppercase text-fg/60 text-sm mt-6 mb-2 mx-2">Banner</h2>

<div class="flex justify-between mt-6 ml-2 gap-x-4 mobile:flex-col mobile:gap-y-2">
<div class="flex flex-col items-start mobile:flex-row mobile:items-center mobile:justify-between gap-y-1">
<div class="flex flex-col gap-y-1">
<h3 class="font-light font-title text-lg">Banner</h3>
<p class="font-light text-sm text-fg/70">
This will be shown at the top of the channel sidebar.
</p>
</div>
<div class="flex mt-2 mobile:flex-col">
<button class="btn btn-primary" onClick={() => promptImageUpload(setBannerData)}>
<Icon icon={ArrowUpFromBracket} class="w-4 h-4 fill-current mr-1" />
Upload Banner
</button>
<Show when={previewBanner()}>
<button class="btn btn-ghost mobile:btn-sm" onClick={() => setBannerData(null)}>
Remove Banner
</button>
</Show>
</div>
</div>

<div
class="my-1 flex-shrink-0 rounded-xl w-1/3 mobile:w-full min-w-[150px] overflow-hidden cursor-pointer group"
onClick={() => promptImageUpload(setBannerData)}
>
<Show when={previewBanner()} fallback={
<div
class="flex flex-col gap-y-2 aspect-video border-2 border-dashed rounded-xl border-fg/50 items-center justify-center"
>
<Icon icon={ArrowUpFromBracket} class="w-5 h-5 fill-fg/50 group-hover:fill-fg/100 transition" />
<span class="text-sm font-medium text-fg text-opacity-50 group-hover:text-opacity-100 transition">
Upload
</span>
</div>
}>
<figure
class="aspect-video"
style={{
"background-image": `url(${previewBanner()})`,
"background-size": "cover",
"background-position": "center",
}}
/>
</Show>
</div>
</div>


</div>
)
Expand Down

0 comments on commit c637053

Please sign in to comment.