Skip to content
54 changes: 49 additions & 5 deletions platforms/metagram/src/lib/dummyData.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { CommentType } from "./types";

export const dummyPosts = Array.from({ length: 100 }, (_, i) => ({
id: i + 1,
avatar: 'https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250',
Expand All @@ -9,10 +11,52 @@ export const dummyPosts = Array.from({ length: 100 }, (_, i) => ({
count: {
likes: Math.floor(Math.random() * 500),
comments: Math.floor(Math.random() * 200)
},
callback: {
like: () => alert(`Like clicked on post ${i + 1}`),
comment: () => alert(`Comment clicked on post ${i + 1}`),
menu: () => alert(`Menu clicked on post ${i + 1}`)
}
}));

export const comments: CommentType[] = Array.from({ length: 50 }, (_, i) => ({
userImgSrc: 'https://picsum.photos/800',
name: `user${i + 1}`,
commentId: `${i + 1}`,
comment: `this is the dummy comment which is commented by user${i + 1}`,
isLiked: false,
isDisliked: false,
likeCount: 0,
time: '2 minutes ago',
replies: [
{
userImgSrc: 'https://picsum.photos/800',
name: `user${i + 1}x`,
commentId: `${i + 1}x`,
comment: `this is the dummy reply which is replied by another${i}x`,
isLiked: false,
isDisliked: false,
likeCount: 0,
time: '1 minute ago',
replies: [
{
userImgSrc: 'https://picsum.photos/800',
name: `user${i + 1}a`,
commentId: `${i + 1}a`,
comment: `this is the dummy reply which is replied by another${i}a`,
isLiked: false,
isDisliked: false,
likeCount: 0,
time: '1 minute ago',
replies: []
}
]
},
{
userImgSrc: 'https://picsum.photos/800',
name: `user${i + 1}y`,
commentId: `${i + 1}y`,
comment: `this is the dummy reply which is replied by another${i}y`,
isLiked: false,
isDisliked: false,
likeCount: 0,
time: '1 minute ago',
replies: []
}
]
}));
19 changes: 19 additions & 0 deletions platforms/metagram/src/lib/fragments/Comment/Comment.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { ComponentProps } from 'svelte';
import { Comment } from '..';
import { comments } from '$lib/dummyData';

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

export const Main = {
args: {
comment: comments[0]
}
};
86 changes: 86 additions & 0 deletions platforms/metagram/src/lib/fragments/Comment/Comment.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<script lang="ts">
import { Like } from '$lib/icons';
import { Avatar } from '$lib/ui';
import { cn } from '$lib/utils';
import type { HTMLAttributes } from 'svelte/elements';
import CommentComponent from './Comment.svelte';
import type { CommentType } from '$lib/types';

interface ICommentProps extends HTMLAttributes<HTMLElement> {
comment: CommentType;
handleReply: () => void;
}

let visibleReplies = 2;

const showMoreReplies = () => {
visibleReplies = comment.replies.length;
};

let { comment, handleReply, ...restProps }: ICommentProps = $props();
</script>

<article {...restProps} class={cn([restProps.class].join(' '))}>
<div class="align-start flex gap-2">
<Avatar src={comment.userImgSrc} size="sm" />
<div>
<h3 class="font-semibold text-black">{comment.name}</h3>
<p class="text-black-600 mt-0.5">{comment.comment}</p>
</div>
</div>
<div class="ms-12 mt-2 flex items-center gap-2">
<button
onclick={() => {
if (!comment.isLiked) {
comment.likeCount++;
comment.isLiked = true;
comment.isDisliked = false;
}
}}
>
<Like
size="18px"
color={comment.isLiked
? 'var(--color-brand-burnt-orange)'
: 'var(--color-black-600)'}
fill={comment.isLiked
? 'var(--color-brand-burnt-orange)'
: 'var(--color-black-600)'}
/>
</button>
<p class="text-black-600 font-semibold">{comment.likeCount}</p>
<button
onclick={() => {
if (!comment.isDisliked) {
comment.likeCount--;
comment.isDisliked = true;
comment.isLiked = false;
}
}}
>
<Like
size="18px"
color={comment.isDisliked
? 'var(--color-brand-burnt-orange)'
: 'var(--color-black-600)'}
fill={comment.isDisliked
? 'var(--color-brand-burnt-orange)'
: 'var(--color-black-600)'}
class="rotate-180"
/>
</button>
<span class="bg-black-600 inline-block h-1 w-1 rounded-full"></span>
<button onclick={handleReply} class="text-black-600 font-semibold">Reply</button>
<span class="bg-black-600 inline-block h-1 w-1 rounded-full"></span>
<p class="text-black-600">{comment.time}</p>
</div>
{#if comment?.replies?.length}
<ul class="ms-12 mt-4 space-y-2">
{#each comment.replies as reply}
<li>
<CommentComponent comment={reply} {handleReply} />
</li>
{/each}
</ul>
{/if}
</article>
20 changes: 2 additions & 18 deletions platforms/metagram/src/lib/fragments/Drawer/Drawer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,21 @@
import type { SwipeCustomEvent } from 'svelte-gestures';

interface IDrawerProps extends HTMLAttributes<HTMLDivElement> {
isPaneOpen?: boolean;
drawer?: CupertinoPane;
children?: Snippet;
handleSwipe?: (isOpen: boolean | undefined) => void;
}

let {
isPaneOpen = $bindable(),
children = undefined,
handleSwipe,
...restProps
}: IDrawerProps = $props();
let { drawer = $bindable(), children = undefined, ...restProps }: IDrawerProps = $props();

let drawerElement: HTMLElement;
let drawer: CupertinoPane;

function dismiss() {
if (drawer) drawer.destroy({ animate: true });
}

const handleDrawerSwipe = (event: SwipeCustomEvent) => {
if (event.detail.direction === ('down' as string)) {
handleSwipe?.(false);
drawer?.destroy({ animate: true });
isPaneOpen = false;
}
};

Expand All @@ -51,13 +42,6 @@
onBackdropTap: () => dismiss()
}
});
if (isPaneOpen) {
drawer.present({ animate: true });
} else {
drawer.destroy({ animate: true });
}

drawer.present();
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

interface IMessageInputProps extends HTMLAttributes<HTMLElement> {
variant: 'comment' | 'dm';
input?: HTMLInputElement;
src: string;
value: string;
placeholder?: string;
Expand All @@ -18,7 +19,8 @@
let {
variant = 'comment',
src = 'https://www.gravatar.com/avatar/2c7d99fe281ecd3bcd65ab915bac6dd5?s=250',
value,
value = $bindable(),
input = $bindable(),
placeholder,
files = $bindable(),
handleAdd,
Expand Down Expand Up @@ -46,7 +48,7 @@
<HugeiconsIcon size="24px" icon={PlusSignIcon} color="var(--color-black-400)" />
</button>
{/if}
<Input type="text" bind:value {placeholder} />
<Input type="text" bind:input bind:value {placeholder} />
{#if value || variant === 'dm'}
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
Expand Down
4 changes: 2 additions & 2 deletions platforms/metagram/src/lib/fragments/Post/Post.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@
</button>
</div>
<div class="flex items-center justify-between gap-3 text-lg text-black/40">
<p>{count.likes} likes</p>
<p class="subtext text-black-400">{count.likes} likes</p>
<HugeiconsIcon
icon={RecordIcon}
size={5}
strokeWidth={30}
color="var(--color-black-400)"
className="rounded-full"
/>
<p>{count.comments} comments</p>
<p class="subtext text-black-400">{count.comments} comments</p>
</div>
</div>
</article>
1 change: 1 addition & 0 deletions platforms/metagram/src/lib/fragments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ 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 Post } from './Post/Post.svelte';
export { default as Comment } from './Comment/Comment.svelte';
4 changes: 2 additions & 2 deletions platforms/metagram/src/lib/icons/Like.svelte
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script lang="ts">
import type { ISvgProps } from './../types';

let { size = '20px', color = '#A5A5A5', ...restProps }: ISvgProps = $props();
let { size = '20px', color = '#A5A5A5', fill, ...restProps }: ISvgProps = $props();
</script>

<svg
width={size}
height={size}
viewBox="0 0 20 20"
fill="none"
{fill}
xmlns="http://www.w3.org/2000/svg"
{...restProps}
>
Expand Down
12 changes: 12 additions & 0 deletions platforms/metagram/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,15 @@ export interface ISvgProps extends SVGAttributes<SVGElement> {
size?: number | string;
color?: string;
}

export type CommentType = {
commentId: string;
name: string;
userImgSrc: string;
comment: string;
isLiked: boolean;
isDisliked: boolean;
likeCount: number;
time: string;
replies: CommentType[];
};
5 changes: 5 additions & 0 deletions platforms/metagram/src/lib/ui/Input/Input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@

interface IInputProps extends HTMLInputAttributes {
type: HTMLInputTypeAttribute;
input?: HTMLInputElement;
value: string | number | any;
placeholder?: string;
}

let {
type = 'text',
input = $bindable(),
value = $bindable(),
placeholder = '',
...restProps
Expand All @@ -23,6 +27,7 @@
{type}
{placeholder}
bind:value
bind:this={input}
class={cn([cbase, restProps.class].join(' '))}
tabindex="0"
/>
Loading
Loading