From 4670e765311b7f55ec2608198f71caf4f81be627 Mon Sep 17 00:00:00 2001 From: Zak Nesler Date: Sat, 1 Jun 2024 13:13:49 -0400 Subject: [PATCH] add refreshing animation --- package.json | 1 + pnpm-lock.yaml | 24 +++++++++++++++ tailwind.config.ts | 8 ++--- ui/src/components/feed/feed-item.tsx | 39 +++++++++++++++++++----- ui/src/contexts/notifications-context.ts | 12 ++------ 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index dd47dbb1..1132aca6 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "partysocket": "^1.0.1", "solid-icons": "^1.1.0", "solid-js": "^1.8.17", + "solid-transition-group": "^0.2.3", "wretch": "^2.8.1" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 271d000f..bda20718 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: solid-js: specifier: ^1.8.17 version: 1.8.17 + solid-transition-group: + specifier: ^0.2.3 + version: 0.2.3(solid-js@1.8.17) wretch: specifier: ^2.8.1 version: 2.8.1 @@ -844,6 +847,11 @@ packages: peerDependencies: solid-js: ^1.6.12 + '@solid-primitives/transition-group@1.0.5': + resolution: {integrity: sha1-8TdsRkjXjLaiKijUCUyUq02QI0Y=} + peerDependencies: + solid-js: ^1.6.12 + '@solid-primitives/trigger@1.0.11': resolution: {integrity: sha1-dlEt4Gs7zHjNLb3S4XJriJ8P5gQ=} peerDependencies: @@ -2030,6 +2038,12 @@ packages: peerDependencies: solid-js: ^1.3 + solid-transition-group@0.2.3: + resolution: {integrity: sha1-70QdnkYgzdxNKc28lYsJ+U21FcQ=} + engines: {node: '>=18.0.0', pnpm: '>=8.6.0'} + peerDependencies: + solid-js: ^1.6.12 + source-map-js@1.2.0: resolution: {integrity: sha1-FrgJwWJRe1uMPn3NMVoqXCYSsq8=} engines: {node: '>=0.10.0'} @@ -3064,6 +3078,10 @@ snapshots: '@solid-primitives/utils': 6.2.3(solid-js@1.8.17) solid-js: 1.8.17 + '@solid-primitives/transition-group@1.0.5(solid-js@1.8.17)': + dependencies: + solid-js: 1.8.17 + '@solid-primitives/trigger@1.0.11(solid-js@1.8.17)': dependencies: '@solid-primitives/utils': 6.2.3(solid-js@1.8.17) @@ -4384,6 +4402,12 @@ snapshots: '@babel/types': 7.24.6 solid-js: 1.8.17 + solid-transition-group@0.2.3(solid-js@1.8.17): + dependencies: + '@solid-primitives/refs': 1.0.8(solid-js@1.8.17) + '@solid-primitives/transition-group': 1.0.5(solid-js@1.8.17) + solid-js: 1.8.17 + source-map-js@1.2.0: {} source-map-support@0.5.13: diff --git a/tailwind.config.ts b/tailwind.config.ts index d90e2737..246ab7f7 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,10 +1,10 @@ -import defaultTheme from 'tailwindcss/defaultTheme'; +import kobaltePlugin from '@kobalte/tailwindcss'; +import formsPlugin from '@tailwindcss/forms'; +import typographyPlugin from '@tailwindcss/typography'; import type { Config } from 'tailwindcss'; import colors from 'tailwindcss/colors'; +import defaultTheme from 'tailwindcss/defaultTheme'; import plugin from 'tailwindcss/plugin'; -import formsPlugin from '@tailwindcss/forms'; -import kobaltePlugin from '@kobalte/tailwindcss'; -import typographyPlugin from '@tailwindcss/typography'; import { screens } from './ui/src/constants/screens'; export default { diff --git a/ui/src/components/feed/feed-item.tsx b/ui/src/components/feed/feed-item.tsx index eca46343..57dda80c 100644 --- a/ui/src/components/feed/feed-item.tsx +++ b/ui/src/components/feed/feed-item.tsx @@ -4,21 +4,25 @@ import { cx } from 'class-variance-authority'; import { HiSolidRss } from 'solid-icons/hi'; import { type Component, type JSX, Match, type Setter, Show, Switch, createMemo, createSignal } from 'solid-js'; import { Dynamic } from 'solid-js/web'; +import { Transition } from 'solid-transition-group'; +import { useNotifications } from '~/contexts/notifications-context'; import { useQueryState } from '~/contexts/query-state-context'; import { useFeedsStats } from '~/hooks/queries/use-feeds-stats'; import type { Feed } from '~/types/bindings'; +import { Spinner } from '../ui/spinner'; type FeedItemProps = { feed: Feed; }; export const FeedItem: Component = props => { - const location = useLocation(); const state = useQueryState(); - - const [open, setOpen] = createSignal(false); + const location = useLocation(); const { stats } = useFeedsStats(); + const notifications = useNotifications(); + + const [open, setOpen] = createSignal(false); const getPath = createMemo(() => `/feeds/${props.feed.uuid}`); const isActive = createMemo(() => location.pathname.startsWith(getPath())); @@ -26,13 +30,16 @@ export const FeedItem: Component = props => { const getFaviconSrc = () => props.feed.favicon_b64 || props.feed.favicon_url; + const isLoading = createMemo(() => notifications.feedsRefreshing().includes(props.feed.uuid)); + return ( @@ -41,11 +48,12 @@ export const FeedItem: Component = props => { type BaseFeedItemProps = { href: string; - unread_count?: number; - title?: string; - active: boolean; open: boolean; setOpen: Setter; + active: boolean; + title?: string; + loading?: boolean; + unread_count?: number; favicon_src?: string; icon?: () => JSX.Element; }; @@ -63,7 +71,7 @@ export const BaseFeedItem: Component = props => ( : 'border-transparent dark:hover:bg-gray-800 hover:bg-gray-200 dark:hover:text-white hover:text-gray-900', )} > -
+
}> @@ -76,6 +84,21 @@ export const BaseFeedItem: Component = props => ( + + + +
+
+ +
+
+
+
{props.title} diff --git a/ui/src/contexts/notifications-context.ts b/ui/src/contexts/notifications-context.ts index ef9f909d..2ce3d0c6 100644 --- a/ui/src/contexts/notifications-context.ts +++ b/ui/src/contexts/notifications-context.ts @@ -1,5 +1,5 @@ import { WebSocket } from 'partysocket'; -import { createContext, createEffect, createSignal, useContext } from 'solid-js'; +import { createContext, createSignal, useContext } from 'solid-js'; import type { Notification } from '~/types/bindings'; import { wsUrl } from '~/utils/url'; import { useInvalidateFeed } from '../hooks/queries/use-invalidate-feed'; @@ -15,19 +15,13 @@ export const useNotifications = () => { }; export const makeNotificationsContext = () => { - const [feedsRefreshing, setFeedsRefreshing] = createSignal([]); const invalidateFeed = useInvalidateFeed(); - createEffect(() => { - const refreshing = feedsRefreshing(); - if (!refreshing.length) return; - - console.log(`refreshing ${refreshing.length} feeds`); - }); + const [feedsRefreshing, setFeedsRefreshing] = createSignal([]); const socket = new WebSocket(wsUrl('/notifications'), undefined, { connectionTimeout: 1000, - maxRetries: 10, + maxRetries: 20, }); socket.addEventListener('open', () => console.info('[ws] connection established'));