Skip to content

Commit

Permalink
add new gallery modal
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloose committed Nov 28, 2024
1 parent 66e937e commit 93483af
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 80 deletions.
21 changes: 15 additions & 6 deletions app/src/components/NewGalleryButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
import { primaryIconProps } from "@/constants";
import { NewGalleryForm } from "@/pages/Dashboard/components/NewGalleryForm";
import { useMetagalleryStore } from "@/providers/MetagalleryProvider";
import { Button, Text } from "@mantine/core";
import { IconPrismPlus } from "@tabler/icons-react";
import { Button } from "@mantine/core";
import { IconSparkles } from "@tabler/icons-react";

export const NewGalleryButton = () => {
return (
<Button
variant="primary"
onClick={() => {
useMetagalleryStore.getState().openModal(
<NewGalleryForm />
);
useMetagalleryStore.getState().openModal({
id: 'new-gallery-modal',
centered: true,
withCloseButton: false,
overlayProps: {
backgroundOpacity: 0.55,
blur: 3,
},
child: (
<NewGalleryForm modalKey={'new-gallery-modal'} />
),
});
}}
leftSection={(
<IconPrismPlus {...primaryIconProps} />
<IconSparkles {...primaryIconProps} />
)}
>
Nueva galería
Expand Down
4 changes: 4 additions & 0 deletions app/src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

body {}

input:focus {
outline: none;
}

* {
margin: 0;
padding: 0;
Expand Down
2 changes: 1 addition & 1 deletion app/src/pages/Dashboard/GalleryDashboard.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

.header {
top: 0;
z-index: 6969;
z-index: 1;
position: sticky;
border-bottom: 1px solid #e5e5e5;
}
Expand Down
140 changes: 91 additions & 49 deletions app/src/pages/Dashboard/components/NewGalleryForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Button, FileButton, Group, ScrollArea, Text, TextInput } from "@mantine/core";
import { useMetagalleryStore } from "@/providers/MetagalleryProvider";
import { Button, Stack, Text, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form";
import { IconSearch, IconUpload } from "@tabler/icons-react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { useEffect } from "react";

type NewGalleryPayload = {
template: number;
Expand All @@ -11,15 +12,52 @@ type NewGalleryPayload = {
description: string;
};

export const NewGalleryForm = () => {
const [filterInput, setFilterInput] = useState('');
let __shitty_toggle = false;
let __shitty_dirty_slug = false;

const normalizeName = (name: string) => {
let normalized = name.toLowerCase().replace(/ /g, '-');
return normalized.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}

export const NewGalleryForm = ({ modalKey }: { modalKey: string }) => {
const queryClient = useQueryClient();

useEffect(() => {
__shitty_toggle = false;
__shitty_dirty_slug = false;
}, []);

const form = useForm({
onValuesChange(values, previous) {
if (__shitty_toggle) {
__shitty_toggle = false;
return;
}

if (values.slug != previous.slug) {
__shitty_dirty_slug = true;
__shitty_toggle = false;
}

if (values.title != previous.title && !__shitty_dirty_slug) {
__shitty_toggle = true;
form.setFieldValue('slug', normalizeName(values.title));
form.setDirty({ slug: false });
}
},
initialValues: {
title: 'Mi nueva galería',
slug: '',
slug: 'mi-nueva-galeria',
description: '',
templateId: 0,
},
validate: {
title: (value) => {
if (value.length < 3) {
return 'El título debe tener al menos 4 caracteres';
}
}
}
});

Expand Down Expand Up @@ -52,53 +90,57 @@ export const NewGalleryForm = () => {
description: values.description,
template: values.templateId,
});
useMetagalleryStore.getState().closeModal(modalKey);
});

return (
<form onSubmit={handleSubmit}>
<div className="stack gap-lg">
<div className="stack gap-sm">
<TextInput
label="Título"
placeholder="Título de la obra"
required
{...form.getInputProps('title')}
key={form.key('title')}
/>
<TextInput
label="Descripción"
required
placeholder="Descripción de la obra"
{...form.getInputProps('description')}
key={form.key('description')}
/>
<TextInput
label="URL"
placeholder="mi-galeria"
required
styles={{
section: {
width: 60,
color: 'gray',
},
input: {
paddingInlineStart: 187,
}
}}
{...form.getInputProps('slug')}
leftSection={<Text w={40}>metagallery.pages.dev/</Text>}
key={form.key('slug')}
/>
<Stack>
<Text size="xl" fw={700}>Crear nueva galería</Text>
<form onSubmit={handleSubmit}>
<div className="stack gap-lg">
<div className="stack gap-sm">
<TextInput
placeholder="Título de la obra"
variant="filled"
description="Título de tu galería"
required
{...form.getInputProps('title',)}
key={form.key('title')}
/>
<TextInput
placeholder="Descripción de la obra"
variant="filled"
description="Descripción"
required
{...form.getInputProps('description')}
key={form.key('description')}
/>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div>
<Text c={'dimmed'}>metagallery.pages.dev/</Text>
</div>
<div>
<input
key={form.key('slug')}
style={{
border: 'none',
}}
{...form.getInputProps('slug')}
/>
</div>
</div>
</div>
<Button
type="submit"
variant="primary"
// disabled={!form.isDirty()}
// disabled={!form.isDirty()}
bg={form.isDirty() ? 'black' : 'gray.7'}
>
Crear galería
</Button>
</div>
<Button
type="submit"
variant="primary"
disabled={!form.isDirty()}
bg={form.isDirty() ? 'black' : 'gray.7'}
>
Actualizar
</Button>
</div>
</form>
</form>
</Stack>
);
}
9 changes: 6 additions & 3 deletions app/src/pages/Editor/components/ContentSidebarElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ const ContentSidebarElement = ({ element }: { element: UserContentFileElement })
<Menu.Dropdown>
<Menu.Item
leftSection={<IconEdit style={{ width: rem(14) }} />}
onClick={() => useMetagalleryStore.getState().openModal(
<FileEditor element={element} />
)}
onClick={() => {
useMetagalleryStore.getState().openModal({
id: 'file-editor-modal',
child: <FileEditor element={element} />
})
}}
>
Editar
</Menu.Item>
Expand Down
7 changes: 4 additions & 3 deletions app/src/pages/Editor/components/blocks/PictureSlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,10 @@ export const PictureSlot = ({ idRef, v, res, props }: PictureSlotProps) => {
fill={dragging ? '#fcf3de' : (hovering ? '#e1e3e5' : '#f1f3f5')}
strokeWidth={FRAME_STROKE_WIDTH}
onClick={() => {
useMetagalleryStore.getState().openModal(
<Text>Hawk tuah!</Text>
);
useMetagalleryStore.getState().openModal({
id: 'picture-slot-modal',
child: <Text>Hawk tuah!</Text>
});
}}
onMouseUp={() => {
const dropped = hovering && dragging;
Expand Down
80 changes: 62 additions & 18 deletions app/src/providers/MetagalleryProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,58 @@
import { create } from 'zustand';
import { Modal, Portal } from '@mantine/core';
import { Modal, ModalProps, Portal } from '@mantine/core';
import { ReactNode, useEffect } from 'react';
import { MODAL_PORTAL_ID, TOKEN_LC_KEY } from '@/constants';
import { useLocalStorage } from '@/hooks/useLocalStorage';
import { useUser } from '@/stores/useUser';
import { useWindowSize } from 'react-use';
import ReactConfetti from 'react-confetti';

type ModalProps2 = Omit<ModalProps, 'opened' | 'onClose'> & {
id: string,
child: ReactNode,
opened?: boolean,
onClose?: () => void,
};

interface MetagalleryProviderStore {
activeModals: Set<ReactNode>,
activeModals: Map<string, { el: ReactNode, props?: ModalProps2 }>,
showingConfetti: boolean,
confetti: (ms?: number) => void,
openModal: (modal: ReactNode) => void,
openModal: (props: ModalProps2) => void,
closeModal: (id: string) => boolean,
}

export const useMetagalleryStore = create<MetagalleryProviderStore>()(
(set, get) => ({
activeModals: new Set(),
activeModals: new Map(),
showingConfetti: false,
confetti: (ms) => {
set({ showingConfetti: true });
setTimeout(() => set({ showingConfetti: false }), ms ?? 1000);
},
openModal: (modal) => {
const newModals = new Set(get().activeModals);
newModals.add(modal);
openModal: (props) => {
const newModals = new Map(get().activeModals);
console.log({ props })
newModals.set(props.id, {
el: props.child,
props: props,
});

set({
activeModals: newModals,
});
},
closeModal: (id) => {
const newModals = new Map(get().activeModals);

newModals.get(id)?.props?.onClose?.();
newModals.delete(id);

set({
activeModals: newModals,
});

return true;
},
}),
);
Expand All @@ -52,33 +76,53 @@ export const MetagalleryProvider = ({ children }: { children: ReactNode }) => {
return (
<>
<div id={MODAL_PORTAL_ID} style={{ position: 'absolute' }}></div>
<ReactConfetti
numberOfPieces={showingConfetti ? 200 : 0}
width={width}
height={height}
/>
<Portal target={`#${MODAL_PORTAL_ID}`}>
{
Array.from(modals.values()).map((modal, i) => {
Array.from(modals.entries()).map(([key, modal], i) => {
const { opened, onClose, ...props } = modal.props ?? {
opened: true,
onClose: () => { },
};

console.log({ opened, onClose, props })

return (
<Modal
key={i}
opened
style={{
zIndex: 69696969,
}}
opened={opened ?? true}
closeOnClickOutside={true}
onClose={() => {
const newModals = new Set(modals);
newModals.delete(modal);
console.log('🐢🐢🐢🐢🐢🐢', onClose)
const newModals = new Map(modals);
newModals.delete(key);

useMetagalleryStore.setState({
activeModals: newModals,
});
}}>
{modal}

onClose?.();
}}
{...props}
>
{modal.el}
</Modal>
);
})
}
</Portal>
{children}
<ReactConfetti
numberOfPieces={showingConfetti ? 200 : 0}
width={width}
height={height}
style={{
width: 0, height: 0,
overflow: 'hidden',
}}
/>
</>
);
};

0 comments on commit 93483af

Please sign in to comment.