chore: remove all Twitter branding, rename route /twitter -> /feed
- Renamed apps/web/src/app/twitter/ -> feed/ - Renamed TwitterComposer -> FeedComposer, TwitterSidebar -> FeedSidebar - TwitterPage -> FeedPage, TwitterComposerProps -> FeedComposerProps - Shell nav: 'Twitter' -> 'Feed', route /twitter -> /feed - BottomNav: 'Twitter' -> 'Feed' - Root page: redirect / -> /feed (was /twitter) - All 'Twitter' product references purged from codebase
This commit is contained in:
parent
5b394f6c92
commit
29b4d51b3c
13 changed files with 36 additions and 36 deletions
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
|
|
@ -112,4 +112,4 @@ jobs:
|
|||
run: |
|
||||
echo "::error::Deploy failed for ${{ github.ref }} — see run logs"
|
||||
# Add Slack/Discord/PagerDuty webhook here when ready.
|
||||
exit 1
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -151,4 +151,4 @@ wrangler rollback --env production
|
|||
```
|
||||
|
||||
Or via the Cloudflare dashboard: `Workers & Pages → degenfeed-api →
|
||||
Deployments → Rollback`.
|
||||
Deployments → Rollback`.
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ Rebuild DegenFeed Web into a usable web3-first social aggregator (TODO.md #1–1
|
|||
4. Newsletter cron + email delivery (#15).
|
||||
|
||||
## Blocked
|
||||
None.
|
||||
None.
|
||||
|
|
|
|||
28
TODO.md
28
TODO.md
|
|
@ -15,49 +15,49 @@
|
|||
|
||||
### 15 Next Moves (ranked by impact)
|
||||
|
||||
1. **Make `/home` per-protocol sections actually work**
|
||||
1. **Make `/home` per-protocol sections actually work**
|
||||
Ensure `/home/nostr`, `/home/farcaster`, `/home/bluesky`, `/home/lens`, `/home/mastodon`, `/home/threads`, and `/home/reddit` each call the correct provider endpoint and render a real feed with loading, error, and empty states. Fix `/home/mastodon` to use `/api/feed/home?protocols=mastodon` (or keep `/api/feed/activitypub` but wire it to the deployed GotoSocial instance).
|
||||
|
||||
2. **Rebuild the landing experience**
|
||||
2. **Rebuild the landing experience**
|
||||
The current app looks like a generic dashboard. Design a web3-first `/twitter` timeline with: compact PostCards, hover actions, quote/repost counts, protocol badges, embedded link previews, and image lightbox. Copy the best parts of Warpcast / Bluesky / X, not a Bootstrap card layout.
|
||||
|
||||
3. **Fix the empty-state problem everywhere**
|
||||
3. **Fix the empty-state problem everywhere**
|
||||
Every feed currently shows an empty card with no personality. Add protocol-specific empty states: "No Nostr notes found — try a different relay", "Mastodon timeline is quiet — create the first post @social.degenfeed.xyz", etc., with one-click fixes (switch relay, create account, sign in).
|
||||
|
||||
4. **Add real-time / polling updates**
|
||||
4. **Add real-time / polling updates**
|
||||
The news page polls every 60s for new stories but other timelines do not. Add a global `useFeedPoller` hook that shows a "New posts" banner and lets users pull-to-refresh on mobile and click-to-refresh on desktop.
|
||||
|
||||
5. **Replace the RMI hard dependency with a resilient pipeline**
|
||||
5. **Replace the RMI hard dependency with a resilient pipeline**
|
||||
RMI is unreachable from Cloudflare edge. The feed should always fall back to public sources without the user noticing. Remove all user-facing "RMI DataBus" copy until the backend is actually deployed and reachable from the edge.
|
||||
|
||||
6. **Harden the Mastodon/GotoSocial integration**
|
||||
6. **Harden the Mastodon/GotoSocial integration**
|
||||
Our own instance is the most important protocol. Add a dedicated GotoSocial provider path that reads the public timeline from `https://social.degenfeed.xyz/api/v1/timelines/public`, supports hashtag timelines, and lets signed-in users see their home timeline.
|
||||
|
||||
7. **Add protocol-aware composer**
|
||||
7. **Add protocol-aware composer**
|
||||
The composer now shows all protocols. Signed-in protocols are selectable; unsigned protocols show a lock icon and open sign-in when clicked. Added live publish preview (`ComposePreview`) and per-protocol character-limit warnings that disable the Post button when exceeded. Updated both the inline `TwitterComposer` and the `ComposeModal`.
|
||||
|
||||
8. **Implement wallet-first authentication**
|
||||
8. **Implement wallet-first authentication**
|
||||
Wallet sign-in is now the primary path in the `SignInModal` (Ethereum + Solana buttons at the top). Added `/api/auth/signout` to clear the `__Host-dfid` cookie, added `signOut` to `AuthProvider`, and exposed it in the `/twitter` header and sidebar. `/api/bridge/rss-to-nostr` now requires the session cookie too.
|
||||
|
||||
9. **Add a unified notifications stream**
|
||||
9. **Add a unified notifications stream**
|
||||
Added `useNotifications` hook that builds auth from all linked identities, polls `POST /api/notifications` every 60s, and persists read state in localStorage. Extended the backend to aggregate notifications from Nostr, Mastodon, and Bluesky. Added the `NotificationBell` to the `/twitter` header and kept it in `/home/[section]`.
|
||||
|
||||
10. **Fix ranking and deduplication**
|
||||
10. **Fix ranking and deduplication**
|
||||
Backend now computes and attaches a per-post score breakdown (recency, engagement, relevance, quality, diversity, source, velocity, reasons). `PostCard` shows a `★` badge with hover tooltip exposing each component. Added a "hide low-quality" toggle in `/twitter` (persisted in localStorage) that filters posts with `score.total < 1.0`. The toggle respects the session-bound `hideLowQuality` preference so it can later be moved to a profile page.
|
||||
|
||||
11. **Add cross-posting to the bridge**
|
||||
Wire `/api/bridge/rss-to-nostr` and a general `/api/publish` to cross-post from Mastodon to Nostr, Farcaster to Bluesky, etc. Start with one working pair (Mastodon → Nostr) and expose it in the composer.
|
||||
|
||||
12. **Build a mobile-first responsive layout**
|
||||
12. **Build a mobile-first responsive layout**
|
||||
The current layout is desktop-only with a hidden right sidebar. Implement a bottom nav (Home, Search, Notifications, Profile) for mobile, collapsible sidebars, and proper safe-area handling.
|
||||
|
||||
13. **Add protocol health dashboard**
|
||||
13. **Add protocol health dashboard**
|
||||
`/api/feed/health` exists but is not exposed in the UI. Add a `/status` page (or admin panel) showing each protocol's latency, success rate, and last fetched time so users know when a feed is degraded.
|
||||
|
||||
14. **Add search that actually searches**
|
||||
14. **Add search that actually searches**
|
||||
`/api/search` and `/api/search/identity` are wired. Add a global search bar in the shell that searches posts, identities, and niches across protocols, with filters for protocol and time range.
|
||||
|
||||
15. **Ship the newsletter as a real product**
|
||||
15. **Ship the newsletter as a real product**
|
||||
After the digest works, add an actual email-sending path (Postmark / SES) and a cron trigger that builds the daily digest from live data and sends it to subscribers. Add a `/newsletter/manage` page with preferences and unsubscribe.
|
||||
|
||||
## Active
|
||||
|
|
|
|||
2
apps/web/next-env.d.ts
vendored
2
apps/web/next-env.d.ts
vendored
|
|
@ -1,6 +1,6 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import './.next/types/routes.d.ts';
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import { FeedList, NotificationBell } from '@degenfeed/ui';
|
|||
import Image from 'next/image';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useAuth } from '../../components/AuthProvider';
|
||||
import { FeedComposer } from '../../components/FeedComposer';
|
||||
import { FeedSidebar } from '../../components/FeedSidebar';
|
||||
import { TipModal } from '../../components/TipModal';
|
||||
import { TwitterComposer } from '../../components/TwitterComposer';
|
||||
import { TwitterSidebar } from '../../components/TwitterSidebar';
|
||||
import { useNotifications } from '../../hooks/useNotifications';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
|
@ -43,7 +43,7 @@ const PROTOCOL_META: Record<string, { label: string; color: string; emoji: strin
|
|||
rss: { label: 'News', color: '#ffa500', emoji: '📰' },
|
||||
};
|
||||
|
||||
export default function TwitterPage() {
|
||||
export default function FeedPage() {
|
||||
const { signedInProtocols, engage, openSignIn, publish, ready, signOut, nostrPublicId } =
|
||||
useAuth();
|
||||
|
||||
|
|
@ -472,7 +472,7 @@ export default function TwitterPage() {
|
|||
|
||||
{/* Composer / sign-in CTA */}
|
||||
{hasSignedIn ? (
|
||||
<TwitterComposer
|
||||
<FeedComposer
|
||||
onPost={publish}
|
||||
signedInProtocols={signedInProtocols}
|
||||
nostrPublicId={nostrPublicId}
|
||||
|
|
@ -568,7 +568,7 @@ export default function TwitterPage() {
|
|||
{/* Right sidebar */}
|
||||
<aside className="hidden lg:col-span-4 lg:block xl:col-span-3">
|
||||
<div className="sticky top-20">
|
||||
<TwitterSidebar
|
||||
<FeedSidebar
|
||||
trending={feedMeta.trending ?? []}
|
||||
protocolSummaries={protocolSummaries}
|
||||
activeProtocolFilter={protocolFilter}
|
||||
|
|
@ -6,7 +6,7 @@ import { useEffect } from 'react';
|
|||
export default function RootPage() {
|
||||
const router = useRouter();
|
||||
useEffect(() => {
|
||||
router.replace('/twitter');
|
||||
router.replace('/feed');
|
||||
}, [router]);
|
||||
return (
|
||||
<div className="flex min-h-[60vh] items-center justify-center">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function Icon({ children }: { children: React.ReactNode }) {
|
|||
|
||||
const NAV: NavItem[] = [
|
||||
{ href: '/home', label: 'Feed', icon: <Icon>⌂</Icon> },
|
||||
{ href: '/twitter', label: 'Twitter', icon: <Icon>✦</Icon> },
|
||||
{ href: '/feed', label: 'Feed', icon: <Icon>✦</Icon> },
|
||||
{ href: '/news', label: 'News', icon: <Icon>◉</Icon> },
|
||||
{ href: '/newsletter', label: 'Daily', icon: <Icon>✉</Icon> },
|
||||
{ href: '/profile', label: 'Profile', icon: <Icon>◍</Icon> },
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const TARGETS = [
|
|||
{ id: 'mastodon', label: 'Mastodon', charLimit: 5000 },
|
||||
];
|
||||
|
||||
interface TwitterComposerProps {
|
||||
interface FeedComposerProps {
|
||||
signedInProtocols: Record<string, boolean>;
|
||||
nostrPublicId?: string;
|
||||
onPost: (
|
||||
|
|
@ -25,12 +25,12 @@ interface TwitterComposerProps {
|
|||
onRequestSignIn?: (protocol: string) => void;
|
||||
}
|
||||
|
||||
export function TwitterComposer({
|
||||
export function FeedComposer({
|
||||
signedInProtocols,
|
||||
nostrPublicId,
|
||||
onPost,
|
||||
onRequestSignIn,
|
||||
}: TwitterComposerProps) {
|
||||
}: FeedComposerProps) {
|
||||
const [text, setText] = useState('');
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [bridgeToNostr, setBridgeToNostr] = useState(false);
|
||||
|
|
@ -9,7 +9,7 @@ interface ProtocolSummary {
|
|||
count: number;
|
||||
}
|
||||
|
||||
interface TwitterSidebarProps {
|
||||
interface FeedSidebarProps {
|
||||
trending?: { topic: string; count: number; score: number }[];
|
||||
protocolSummaries?: ProtocolSummary[];
|
||||
activeProtocolFilter?: string | null;
|
||||
|
|
@ -27,12 +27,12 @@ const NETWORK_HINTS: Record<string, string> = {
|
|||
rss: '30+ news sources',
|
||||
};
|
||||
|
||||
export function TwitterSidebar({
|
||||
export function FeedSidebar({
|
||||
trending,
|
||||
protocolSummaries,
|
||||
activeProtocolFilter,
|
||||
onProtocolClick,
|
||||
}: TwitterSidebarProps) {
|
||||
}: FeedSidebarProps) {
|
||||
const { walletAddress, signOut, openSignIn } = useAuth();
|
||||
const items = trending ?? [];
|
||||
const protocols = protocolSummaries ?? [];
|
||||
|
|
@ -14,7 +14,7 @@ interface NavItem {
|
|||
|
||||
const NAV: NavItem[] = [
|
||||
{ href: '/home', label: 'Feed' },
|
||||
{ href: '/twitter', label: 'Twitter' },
|
||||
{ href: '/feed', label: 'Feed' },
|
||||
{ href: '/news', label: 'News' },
|
||||
{ href: '/newsletter', label: 'Daily' },
|
||||
{ href: '/premium', label: 'Premium' },
|
||||
|
|
@ -195,8 +195,8 @@ export function Shell({ children }: { children: React.ReactNode }) {
|
|||
<a href="/home" className="transition-colors hover:text-white">
|
||||
Feed
|
||||
</a>
|
||||
<a href="/twitter" className="transition-colors hover:text-white">
|
||||
Twitter
|
||||
<a href="/feed" className="transition-colors hover:text-white">
|
||||
Feed
|
||||
</a>
|
||||
<a href="/news" className="transition-colors hover:text-white">
|
||||
News
|
||||
|
|
|
|||
|
|
@ -203,4 +203,4 @@ echo " 3. Deploy the preview environment:"
|
|||
echo " cd workers/api && wrangler deploy --env preview"
|
||||
echo
|
||||
echo " 4. Cut a release tag and push to main — CI will deploy production."
|
||||
hr
|
||||
hr
|
||||
|
|
|
|||
|
|
@ -67,4 +67,4 @@ routes = [
|
|||
]
|
||||
[env.preview.vars]
|
||||
ALLOWED_ORIGINS = "https://preview.degenfeed.xyz,https://app.preview.degenfeed.xyz,http://localhost:3000"
|
||||
RATE_MAX_REQ = "600"
|
||||
RATE_MAX_REQ = "600"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue