your personal website on atproto - mirror blento.app

add popfeed reviews

Florian b901933e e4d39faa

+134 -2
+12
docs/Autofill.md
···
··· 1 + # autofilling a profile 2 + 3 + - find all links in bluesky profile 4 + - check for lexicons: 5 + - place.stream.livestream 6 + - social.popfeed.challenge.participation 7 + - social.popfeed.feed.review 8 + - site.standard.document 9 + - com.germnetwork.declaration 10 + - pub.leaflet.document 11 + - blue.flashes.actor.portfolio 12 + - add bluesky profile card
+46
src/lib/cards/PopfeedReviews/PopfeedReviewsCard.svelte
···
··· 1 + <script lang="ts"> 2 + import type { Item } from '$lib/types'; 3 + import { onMount } from 'svelte'; 4 + import { BlueskyPost } from '../../components/bluesky-post'; 5 + import { getAdditionalUserData, getDidContext, getHandleContext } from '$lib/website/context'; 6 + import { CardDefinitionsByType } from '..'; 7 + import Rating from './Rating.svelte'; 8 + 9 + let { item }: { item: Item } = $props(); 10 + 11 + const data = getAdditionalUserData(); 12 + // svelte-ignore state_referenced_locally 13 + let feed = $state(data[item.cardType] as any); 14 + 15 + let did = getDidContext(); 16 + let handle = getHandleContext(); 17 + 18 + onMount(async () => { 19 + console.log(feed); 20 + if (!feed) { 21 + feed = (await CardDefinitionsByType[item.cardType]?.loadData?.([], { 22 + did, 23 + handle 24 + })) as any; 25 + 26 + console.log(feed); 27 + 28 + data[item.cardType] = feed; 29 + } 30 + }); 31 + </script> 32 + 33 + <div class="z-10 flex h-full gap-4 overflow-x-scroll p-4"> 34 + {#each feed ?? [] as review} 35 + <a target="_blank" class="flex" href="https://popfeed.social/review/{review.uri}"> 36 + <div 37 + class="relative flex aspect-[2/3] h-full flex-col items-center justify-end overflow-hidden p-1 rounded-xl" 38 + > 39 + <img src={review.value.posterUrl} alt="" class="absolute inset-0 -z-10" /> 40 + <div class="from-base-900/80 absolute bottom-0 left-0 right-0 h-1/3 bg-gradient-to-t via-transparent"></div> 41 + 42 + <Rating class="z-10 text-lg" rating={review.value.rating} /> 43 + </div> 44 + </a> 45 + {/each} 46 + </div>
+51
src/lib/cards/PopfeedReviews/Rating.svelte
···
··· 1 + <script lang="ts"> 2 + import { cn } from '@foxui/core'; 3 + 4 + let { rating, class: className }: { rating: number; class?: string } = $props(); 5 + 6 + // Convert 0-10 rating to 0-5 stars 7 + const starRating = $derived(Math.max(0, Math.min(10, rating ?? 0)) / 2); 8 + const fullStars = $derived(Math.floor(starRating)); 9 + const hasHalfStar = $derived(rating % 2 === 1); 10 + const emptyStars = $derived(Math.max(0, 5 - fullStars - (hasHalfStar ? 1 : 0))); 11 + </script> 12 + 13 + {#snippet star(className: string)} 14 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 {className}"> 15 + <path 16 + fill="currentColor" 17 + fill-rule="evenodd" 18 + d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" 19 + clip-rule="evenodd" 20 + /> 21 + </svg> 22 + {/snippet} 23 + 24 + {#snippet halfStar()} 25 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="size-5 fill-accent-500"> 26 + <defs> 27 + <linearGradient id="half-filled" x1="0%" y1="0%" x2="100%" y2="0%"> 28 + <stop offset="50%" stop-color="currentColor" /> 29 + <stop offset="50%" stop-color="var(--color-base-400)" /> 30 + </linearGradient> 31 + </defs> 32 + <path 33 + fill="url(#half-filled)" 34 + fill-rule="evenodd" 35 + d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" 36 + clip-rule="evenodd" 37 + /> 38 + </svg> 39 + {/snippet} 40 + 41 + <div class={cn('text-accent-500 flex', className)}> 42 + {#each Array(fullStars) as _} 43 + {@render star("text-accent-500")} 44 + {/each} 45 + {#if hasHalfStar} 46 + {@render halfStar()} 47 + {/if} 48 + {#each Array(emptyStars) as _} 49 + {@render star("text-base-400")} 50 + {/each} 51 + </div>
+21
src/lib/cards/PopfeedReviews/index.ts
···
··· 1 + import type { CardDefinition } from '../types'; 2 + import { listRecords } from '$lib/oauth/atproto'; 3 + import PopfeedReviewsCard from './PopfeedReviewsCard.svelte'; 4 + 5 + export const PopfeedReviewsCardDefinition = { 6 + type: 'recentPopfeedReviews', 7 + contentComponent: PopfeedReviewsCard, 8 + createNew: (card) => { 9 + card.w = 8; 10 + card.mobileW = 8; 11 + card.h = 3; 12 + card.mobileH = 6; 13 + }, 14 + loadData: async (items, { did }) => { 15 + const data = await listRecords({ did, collection: 'social.popfeed.feed.review' }); 16 + 17 + return data; 18 + }, 19 + minH: 3, 20 + sidebarButtonText: 'Popfeed Reviews' 21 + } as CardDefinition & { type: 'recentPopfeedReviews' };
+3 -1
src/lib/cards/index.ts
··· 18 import { YoutubeCardDefinition } from './YoutubeVideoCard'; 19 import { BlueskyProfileCardDefinition } from './BlueskyProfileCard'; 20 import { GithubProfileCardDefitition } from './GitHubProfileCard'; 21 22 export const AllCardDefinitions = [ 23 ImageCardDefinition, ··· 38 DinoGameCardDefinition, 39 BlueskyProfileCardDefinition, 40 GithubProfileCardDefitition, 41 - TetrisCardDefinition 42 ] as const; 43 44 export const CardDefinitionsByType = AllCardDefinitions.reduce(
··· 18 import { YoutubeCardDefinition } from './YoutubeVideoCard'; 19 import { BlueskyProfileCardDefinition } from './BlueskyProfileCard'; 20 import { GithubProfileCardDefitition } from './GitHubProfileCard'; 21 + import { PopfeedReviewsCardDefinition } from './PopfeedReviews'; 22 23 export const AllCardDefinitions = [ 24 ImageCardDefinition, ··· 39 DinoGameCardDefinition, 40 BlueskyProfileCardDefinition, 41 GithubProfileCardDefitition, 42 + TetrisCardDefinition, 43 + PopfeedReviewsCardDefinition 44 ] as const; 45 46 export const CardDefinitionsByType = AllCardDefinitions.reduce(
+1 -1
src/lib/website/Settings.svelte
··· 50 (value) => { 51 data.publication ??= {}; 52 data.publication.preferences ??= {}; 53 - data.publication.preferences.hideProfile = value; 54 55 data = { ...data }; 56 }
··· 50 (value) => { 51 data.publication ??= {}; 52 data.publication.preferences ??= {}; 53 + data.publication.preferences.hideProfileSection = value; 54 55 data = { ...data }; 56 }