Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<script lang="ts">
import { Button, InputRadio, Label, Textarea } from '$lib/ui';
import type { CupertinoPane } from 'cupertino-pane';
import { InputFile, Modal } from '..';
let {
files = $bindable(),
caption = $bindable(),
postVisibility = $bindable(),
paneModal = $bindable()
}: {
files: FileList | undefined;
caption: string;
postVisibility: string;
paneModal: CupertinoPane | undefined;
} = $props();
let isAddCaption = $state(false);
let imagePreviews: string[] = $state([]);
let postVisibilityOptions = ['Only followers', 'Close friends', 'Anyone'];
$effect(() => {
if (files) {
const readers = Array.from(files).map((file) => {
return new Promise<string>((resolve) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target?.result as string);
reader.readAsDataURL(file);
});
});
Promise.all(readers).then((previews) => {
imagePreviews = previews;
});
} else {
imagePreviews = [];
}
});
</script>

<Modal
bind:paneModal
initialBreak="middle"
handleDismiss={() => {
(files = undefined), (isAddCaption = false);
}}
>
<h1 class="mb-6 font-semibold text-black">Upload a Photo</h1>
{#if !isAddCaption}
{#if !files}
<InputFile class="mb-4 h-[40vh]" bind:files accept="images/*" multiple={true} />
{:else}
<div class="mb-4 grid grid-cols-3 gap-2">
{#each imagePreviews as src}
<div class="aspect-[4/5] overflow-hidden rounded-lg border">
<!-- svelte-ignore a11y_img_redundant_alt -->
<img {src} alt="Selected image" class="h-full w-full object-cover" />
</div>
{/each}
</div>
{/if}
{:else if isAddCaption}
<Label>Add a Caption</Label>
<Textarea class="mb-4" bind:value={caption} placeholder="enter caption" />
<div class="mb-4 flex items-center gap-2">
{#each imagePreviews as src}
<div class="h-[100px] w-[80px] overflow-hidden rounded-lg border">
<!-- svelte-ignore a11y_img_redundant_alt -->
<img {src} alt="Selected image" class="h-[100px] w-[80px] object-cover" />
</div>
{/each}
</div>
<h3 class="text-black-800 mt-20 mb-2">Who can see the post?</h3>
{#each postVisibilityOptions as option, i}
<div class="mb-2 flex w-[50%] items-center justify-between">
<Label for={option + i}>{option}</Label>
<InputRadio
name="post-visibility"
id={option + i}
value={option}
bind:selected={postVisibility}
/>
</div>
{/each}
{/if}
{#if files}
<div class="grid grid-cols-2 gap-2">
<Button
variant="secondary"
size="sm"
callback={async () => {
files = undefined;
isAddCaption = false;
paneModal?.destroy({ animate: true });
}}>Cancel</Button
>
<Button
variant="secondary"
size="sm"
callback={async () => {
isAddCaption = true;
}}>Next</Button
>
</div>
{/if}
</Modal>
33 changes: 23 additions & 10 deletions platforms/metagram/src/lib/fragments/InputFile/InputFile.svelte
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
<script lang="ts">
import { cn } from '$lib/utils';
import { Album01Icon } from '@hugeicons/core-free-icons';
import { HugeiconsIcon } from '@hugeicons/svelte';
import type { HTMLLabelAttributes } from 'svelte/elements';

interface IInputFileProps {
interface IInputFileProps extends HTMLLabelAttributes {
files: FileList | undefined;
accept: string;
label: string;
cancelLabel: string;
oncancel: () => void;
label?: string;
multiple?: boolean;
cancelLabel?: string;
oncancel?: () => void;
}

let {
files = $bindable(),
accept = 'image/*',
label = 'Click to upload a photo',
multiple = false,
cancelLabel = 'Delete upload',
oncancel
oncancel,
...restProps
}: IInputFileProps = $props();

const uniqueId = Math.random().toString().split('.')[1];
let inputFile: HTMLInputElement | undefined = $state();

let cBase =
'bg-grey text-black-400 font-geist flex min-h-[158px] w-full items-center justify-center rounded-4xl text-base font-normal';
</script>

<input id={uniqueId} type="file" bind:files class="hidden" {accept} bind:this={inputFile} />
<input
id={uniqueId}
type="file"
bind:files
class="hidden"
{multiple}
{accept}
bind:this={inputFile}
/>

<label
for={uniqueId}
class="bg-grey text-black-400 font-geist flex h-[158px] w-full items-center justify-center rounded-4xl text-base font-normal"
>
<label {...restProps} for={uniqueId} class={cn([cBase, restProps.class].join(' '))}>
{#if files}
<div class="flex flex-col items-center gap-2">
<HugeiconsIcon size="24px" icon={Album01Icon} color="var(--color-black-600)" />
Expand Down
34 changes: 18 additions & 16 deletions platforms/metagram/src/lib/fragments/Modal/Modal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@
interface IDrawerProps extends HTMLAttributes<HTMLDivElement> {
modalEl?: HTMLDivElement;
paneModal?: CupertinoPane;
initialBreak?: 'bottom' | 'top' | 'middle';
handleDismiss?: () => void;
children?: Snippet;
}

let {
modalEl = $bindable(),
paneModal = $bindable(),
children = undefined,
initialBreak,
handleDismiss,
...restProps
}: IDrawerProps = $props();

function present() {
if (paneModal) paneModal.present({ animate: true });
}

function dismiss() {
handleDismiss && handleDismiss();
if (paneModal) paneModal.destroy({ animate: true });
}

Expand All @@ -30,25 +31,25 @@
paneModal = new CupertinoPane(modalEl, {
modal: true,
backdrop: true,
backdropBlur: true,
backdropOpacity: 0.4,
animationType: 'ease',
animationDuration: 300,
fitHeight: true,
showDraggable: true,
bottomClose: false,
showDraggable: false,
buttonDestroy: false,
initialBreak: initialBreak,
breaks: {
bottom: { enabled: true, height: 250 }
top: { enabled: true, height: 600 },
middle: { enabled: true, height: 400 },
bottom: { enabled: true, height: 200 }
},
initialBreak: 'bottom',
cssClass: 'modal',
events: {
onBackdropTap: () => dismiss()
}
});

present();

return () => {
if (paneModal) paneModal.destroy({ animate: false });
};
});
</script>

Expand All @@ -60,17 +61,18 @@

<style>
:global(.modal .pane) {
width: 95% !important;
max-height: 300px !important;
width: 100% !important;
max-height: 600px !important;
min-height: 100px !important;
height: auto !important;
position: fixed !important;
bottom: 30px !important;
left: 50% !important;
left: 40% !important;
transform: translateX(-50%) !important;
border-radius: 32px !important;
padding: 20px !important;
background-color: var(--color-white) !important;
cursor: default !important;
overflow: scroll !important;
scrollbar-width: none !important;
-ms-overflow-style: none !important;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import type { ComponentProps } from "svelte";
import SettingsTile from "./SettingsTile.svelte";
import type { ComponentProps } from 'svelte';
import SettingsTile from './SettingsTile.svelte';

export default {
title: "UI/SettingsTile",
component: SettingsTile,
tags: ["autodocs"],
render: (args: {
Component: SettingsTile;
props: ComponentProps<typeof SettingsTile>;
}) => ({
Component: SettingsTile,
props: args,
}),
title: 'UI/SettingsTile',
component: SettingsTile,
tags: ['autodocs'],
render: (args: { Component: SettingsTile; props: ComponentProps<typeof SettingsTile> }) => ({
Component: SettingsTile,
props: args
})
};

export const Primary = {
args: {
title: "Who can see your posts?",
currentStatus: "Only followers",
onclick: () => alert("clicked"),
},
args: {
title: 'Who can see your posts?',
currentStatus: 'Only followers',
onclick: () => alert('clicked')
}
};
41 changes: 21 additions & 20 deletions platforms/metagram/src/lib/fragments/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
export { default as Profile } from "./Profile/Profile.svelte";
export { default as Header } from "./Header/Header.svelte";
export { default as BottomNav } from "./BottomNav/BottomNav.svelte";
export { default as SettingsNavigationButton } from "./SettingsNavigationButton/SettingsNavigationButton.svelte";
export { default as MessageInput } from "./MessageInput/MessageInput.svelte";
export { default as InputFile } from "./InputFile/InputFile.svelte";
export { default as Drawer } from "./Drawer/Drawer.svelte";
export { default as Message } from "./Message/Message.svelte";
export { default as ActionMenu } from "./ActionMenu/ActionMenu.svelte";
export { default as Modal } from "./Modal/Modal.svelte";
export { default as SideBar } from "./SideBar/SideBar.svelte";
export { default as RightAside } from "./RightAside/RightAside.svelte";
export { default as SettingsToggleButton } from "./SettingsToggleButton/SettingsToggleButton.svelte";
export { default as Post } from "./Post/Post.svelte";
export { default as ChatMessage } from "./ChatMessage/ChatMessage.svelte";
export { default as Comment } from "./Comment/Comment.svelte";
export { default as SettingsDeleteButton } from "./SettingsDeleteButton/SettingsDeleteButton.svelte";
export { default as SettingsTile } from "./SettingsTile/SettingsTile.svelte";
export { default as UserRequest } from "./UserRequest/UserRequest.svelte";
export { default as UploadedPostView } from "./UploadedPostView/UploadedPostView.svelte";
export { default as Profile } from './Profile/Profile.svelte';
export { default as Header } from './Header/Header.svelte';
export { default as BottomNav } from './BottomNav/BottomNav.svelte';
export { default as SettingsNavigationButton } from './SettingsNavigationButton/SettingsNavigationButton.svelte';
export { default as MessageInput } from './MessageInput/MessageInput.svelte';
export { default as InputFile } from './InputFile/InputFile.svelte';
export { default as Drawer } from './Drawer/Drawer.svelte';
export { default as Message } from './Message/Message.svelte';
export { default as ActionMenu } from './ActionMenu/ActionMenu.svelte';
export { default as Modal } from './Modal/Modal.svelte';
export { default as SideBar } from './SideBar/SideBar.svelte';
export { default as RightAside } from './RightAside/RightAside.svelte';
export { default as SettingsToggleButton } from './SettingsToggleButton/SettingsToggleButton.svelte';
export { default as Post } from './Post/Post.svelte';
export { default as ChatMessage } from './ChatMessage/ChatMessage.svelte';
export { default as Comment } from './Comment/Comment.svelte';
export { default as SettingsDeleteButton } from './SettingsDeleteButton/SettingsDeleteButton.svelte';
export { default as SettingsTile } from './SettingsTile/SettingsTile.svelte';
export { default as UserRequest } from './UserRequest/UserRequest.svelte';
export { default as UploadedPostView } from './UploadedPostView/UploadedPostView.svelte';
export { default as AddPostModal } from './AddPostModal/AddPostModal.svelte';
Loading
Loading