Skip to content

Commit

Permalink
Merge pull request #30 from SpaceTurtle-Dao/feature/feed
Browse files Browse the repository at this point in the history
Implemented Feed Page
  • Loading branch information
coolestnick authored Sep 2, 2024
2 parents dbaeefe + d380dcb commit 2147b10
Show file tree
Hide file tree
Showing 6 changed files with 306 additions and 120 deletions.
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@tailwindcss/typography": "^0.5.14",
"@tsconfig/svelte": "^5.0.4",
"@types/node": "^22.5.2",
"autoprefixer": "^10.4.20",
"svelte": "^4.2.18",
"svelte-check": "^3.8.5",
Expand All @@ -37,6 +38,7 @@
"svelte-sonner": "^0.3.27",
"tailwind-merge": "^2.5.2",
"tailwind-variants": "^0.2.1",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
}
}
41 changes: 40 additions & 1 deletion src/app.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind utilities;

@layer base {
:root {
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 45%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 72% 51%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
}

@layer base {
* {
@apply border-border;
}

body {
@apply bg-background text-foreground font-body;
}

h1, h2, h3, h4, h5, h6 {
@apply font-heading;
}
}
134 changes: 73 additions & 61 deletions src/lib/Feed.svelte
Original file line number Diff line number Diff line change
@@ -1,63 +1,75 @@
<!-- Feed.svelte -->
<script>
import { onMount } from "svelte";
import Tweet from "./Post.svelte";
let tweets = [
{
id: "1",
username: "johnDoe",
text: "Just learned Svelte! #SvelteLearning",
likes: 10,
retweets: 5,
},
{
id: "2",
username: "janeSmith",
text: "I'm loving this Svelte tutorial! #SvelteTutorials",
likes: 20,
retweets: 10,
},
{
id: "3",
username: "janeSmith",
text: "I'm loving this Svelte tutorial! #SvelteTutorials",
likes: 20,
retweets: 10,
},
];
onMount(() => {
// fetch tweets from API or database here
// for demonstration purposes, we'll just use the pre-defined array
console.log("tweets:", tweets);
<script lang="ts">
//@ts-nocheck
import { onMount } from 'svelte';
import Tweet from './Tweet.svelte';
import { fetchMemes, fetchMemesByIds } from './ao/mememaker';
let tweets = [];
onMount(async () => {
try {
const fetchedMemes = await fetchMemes("1", "100");
tweets = fetchedMemes.map(meme => ({
id: meme.Pool,
avatarSrc: meme.Profile?.Image ? `https://arweave.net/${meme.Profile.Image}` : '/default-avatar.png',
username: meme.Profile?.Name || 'Anonymous',
handle: `@${meme.Creator.slice(0, 12)}`,
time: formatTime(meme.createdAt),
content: meme.Post.Content,
likes: meme.Pumps,
retweets: meme.Replies,
price: meme.Analytics.Price,
marketCap: meme.Analytics.MarketCap
}));
} catch (error) {
console.error('Error fetching memes:', error);
}
});
// function handleTweetLike(tweetId) {
// const tweet = tweets.find((t) => t.id === tweetId);
// if (tweet) {
// tweet.likes++;
// }
// }
// function handleTweetRetweet(tweetId) {
// const tweet = tweets.find((t) => t.id === tweetId);
// if (tweet) {
// tweet.retweets++;
// }
// }
</script>

<div>
{#each tweets as tweet}
<Tweet
id={tweet.id}
username={tweet.username}
text={tweet.text}
likes={tweet.likes}
retweets={tweet.retweets}
onLike={() => {}}
onRetweet={() => {}}
/>
function formatTime(timestamp) {
const now = Date.now();
const diff = now - timestamp;
const minutes = Math.floor(diff / 60000);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}d`;
if (hours > 0) return `${hours}h`;
if (minutes > 0) return `${minutes}m`;
return 'Just now';
}
function handleTweetLike(tweetId) {
const tweet = tweets.find((t) => t.id === tweetId);
if (tweet) {
tweet.likes++;
}
}
function handleTweetRetweet(tweetId) {
const tweet = tweets.find((t) => t.id === tweetId);
if (tweet) {
tweet.retweets++;
}
}
</script>

<div class="flex flex-col items-center max-w-2xl mx-auto px-4 py-8 space-y-6">
{#each tweets as tweet (tweet.id)}
<div class="w-full bg-white rounded-lg shadow-md hover:shadow-lg transition-shadow duration-300 ease-in-out">
<Tweet
avatarSrc={tweet.avatarSrc}
username={tweet.username}
handle={tweet.handle}
time={tweet.time}
content={tweet.content}
likes={tweet.likes}
retweets={tweet.retweets}
onLike={() => handleTweetLike(tweet.id)}
onRetweet={() => handleTweetRetweet(tweet.id)}
price={tweet.price}
marketCap={tweet.marketCap}
/>
</div>
{/each}
</div>
</div>
84 changes: 84 additions & 0 deletions src/lib/Tweet.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<script>
import { MessageCircleIcon, RepeatIcon, HeartIcon, ShareIcon, DollarSignIcon, TrendingUpIcon } from 'lucide-svelte';
import Card from '$lib/components/ui/ui/card/card.svelte';
import Avatar from '$lib/components/ui/ui/avatar/avatar.svelte';
import Button from './components/ui/ui/button/button.svelte';
export let avatarSrc = '/placeholder-user.jpg';
export let username = 'User';
export let handle = '@user';
export let time = '1h';
export let content = 'Tweet content here';
export let imageSrc = '';
export let showImage = false;
export let likes = 0;
export let retweets = 0;
export let price = 0;
export let marketCap = 0;
export let onLike = () => {};
export let onRetweet = () => {};
$: formattedPrice = price.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
$: formattedMarketCap = marketCap.toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
</script>

<Card class="max-w-full md:max-w-lg">
<div class="p-4">
<div class="flex items-start gap-4">
<a href="/" class="flex-shrink-0">
<Avatar class="h-10 w-10 rounded-full">
<img src={avatarSrc} alt={`Avatar of ${username}`} />
<span>{username.charAt(0)}</span>
</Avatar>
</a>
<div class="flex-1 space-y-2">
<div class="flex items-center gap-2">
<a href="/" class="font-medium">{username}</a>
<span class="text-sm text-muted-foreground">{handle} · {time}</span>
</div>
<p class="text-sm">
{content}
</p>
{#if showImage}
<!-- svelte-ignore a11y-img-redundant-alt -->
<img
src={imageSrc}
alt="Tweet image"
class="rounded-md object-cover w-full"
style="aspect-ratio: 600/400; object-fit: cover;"
/>
{/if}
<div class="flex items-center gap-4 text-sm text-muted-foreground">
<div class="flex items-center gap-1">
<DollarSignIcon class="h-4 w-4" />
<span>Price: {formattedPrice}</span>
</div>
<div class="flex items-center gap-1">
<TrendingUpIcon class="h-4 w-4" />
<span>Market Cap: {formattedMarketCap}</span>
</div>
</div>
<div class="flex items-center gap-4">
<Button variant="ghost" size="icon" on:click={onLike}>
<HeartIcon class="h-5 w-5" />
<span class="sr-only">Like</span>
<span>{likes}</span>
</Button>
<Button variant="ghost" size="icon" on:click={onRetweet}>
<RepeatIcon class="h-5 w-5" />
<span class="sr-only">Retweet</span>
<span>{retweets}</span>
</Button>
<Button variant="ghost" size="icon">
<MessageCircleIcon class="h-5 w-5" />
<span class="sr-only"> Comment</span>
</Button>
<Button variant="ghost" size="icon">
<ShareIcon class="h-5 w-5" />
<span class="sr-only">Share</span>
</Button>
</div>
</div>
</div>
</div>
</Card>
Loading

0 comments on commit 2147b10

Please sign in to comment.