diff --git a/app/expert-finder/lib/generatedEmailStatus.ts b/app/expert-finder/lib/generatedEmailStatus.ts
index 97551beef..2e8b6c0f4 100644
--- a/app/expert-finder/lib/generatedEmailStatus.ts
+++ b/app/expert-finder/lib/generatedEmailStatus.ts
@@ -14,10 +14,6 @@ export function isGeneratedEmailBounced(status: string): boolean {
return status === 'bounced';
}
-export function isGeneratedEmailFailed(status: string): boolean {
- return status === 'failed' || status === 'send_failed';
-}
-
export type GeneratedEmailStatusBadgeVariant =
| 'default'
| 'primary'
diff --git a/app/expert-finder/library/new/schema.ts b/app/expert-finder/library/new/schema.ts
index 921bb4f52..e934f202b 100644
--- a/app/expert-finder/library/new/schema.ts
+++ b/app/expert-finder/library/new/schema.ts
@@ -9,7 +9,6 @@ import {
const INPUT_TYPES: InputType[] = ['abstract', 'pdf', 'full_content'];
export const EXPERT_COUNT_OPTIONS = [5, 10, 25, 50, 100] as const;
-export type ExpertCountOption = (typeof EXPERT_COUNT_OPTIONS)[number];
export const DEFAULT_STATE = 'All States';
diff --git a/app/layouts/MobileBottomNav.tsx b/app/layouts/MobileBottomNav.tsx
index fe812540d..8b9758be1 100644
--- a/app/layouts/MobileBottomNav.tsx
+++ b/app/layouts/MobileBottomNav.tsx
@@ -188,5 +188,3 @@ export const MobileBottomNav: React.FC = () => {
);
};
-
-export default MobileBottomNav;
diff --git a/app/leaderboard/components/LeaderboardContent.tsx b/app/leaderboard/components/LeaderboardContent.tsx
index 2a87aa685..59a897416 100644
--- a/app/leaderboard/components/LeaderboardContent.tsx
+++ b/app/leaderboard/components/LeaderboardContent.tsx
@@ -12,8 +12,6 @@ import { useCurrentUserLeaderboard } from '@/hooks/useLeaderboard';
import { TopPeerReviewers } from './TopPeerReviewers';
import { TopFunders } from './TopFunders';
-export type { LeaderboardPeriod } from '@/services/leaderboard.service';
-
const PERIOD_OPTIONS: { value: LeaderboardPeriod; label: string }[] = [
{ value: '7_days', label: 'Last 7 Days' },
{ value: '30_days', label: 'Last 30 Days' },
diff --git a/app/pool/doublezero/link.ts b/app/pool/doublezero/link.ts
index 1b9a0940f..c15b27483 100644
--- a/app/pool/doublezero/link.ts
+++ b/app/pool/doublezero/link.ts
@@ -49,12 +49,6 @@ export const SURFACE_KM = EARTH_RADIUS_KM * CENTRAL_ANGLE;
/** Straight-line distance between the endpoints, through the planet. */
export const CHORD_KM = 2 * EARTH_RADIUS_KM * Math.sin(CENTRAL_ANGLE / 2);
-/** How far below the surface that chord dips at its midpoint. */
-export const CHORD_DEPTH_KM = EARTH_RADIUS_KM * (1 - Math.cos(CENTRAL_ANGLE / 2));
-
-/** Closest the chord comes to the Earth's centre. Under 80 km, so: inner core. */
-export const CHORD_CENTRE_MISS_KM = EARTH_RADIUS_KM * Math.cos(CENTRAL_ANGLE / 2);
-
/**
* A neutrino crosses the chord at c. It has mass, so strictly it is a hair
* slower — but at the TeV energies this RFP contemplates the deficit is
@@ -66,8 +60,6 @@ export const CHORD_MS = (CHORD_KM / C_KM_S) * 1000;
/** Fiber pays twice — the longer path and the slower medium. */
export const SURFACE_MS = ((SURFACE_KM * FIBER_INDEX) / C_KM_S) * 1000;
-export const SAVED_MS = SURFACE_MS - CHORD_MS;
-
/**
* Shell boundaries by depth, as fractions of the radius, for the cross-section.
* Upper/lower mantle at 660 km, the core-mantle boundary at 2,890 km, and the
diff --git a/components/Activity/index.ts b/components/Activity/index.ts
index 06b6c38fd..b334a7640 100644
--- a/components/Activity/index.ts
+++ b/components/Activity/index.ts
@@ -1,10 +1,6 @@
// Cards
export { ActivityCard } from './cards/ActivityCard';
-export { ActivityCardCompact } from './cards/ActivityCardCompact';
-export { ActivityCardHeader } from './cards/ActivityCardHeader';
export { ActivityCardSkeleton } from './cards/ActivityCardSkeleton';
-export { ActivityCommentGroupCard } from './cards/ActivityCommentGroupCard';
-export { ActivityFundingGroupCard } from './cards/ActivityFundingGroupCard';
// Work card primitives, shared with the funding feeds
export { ActivityTimestamp } from './cards/ActivityTimestamp';
@@ -16,9 +12,7 @@ export { WorkPreviewCard } from './work/WorkPreviewCard';
export { ActivityFeedList } from './ActivityFeedList';
export { ActivityRow } from './ActivityRow';
export { ActivityPageContent } from './ActivityPageContent';
-export { ActivityCacheBypassControl } from './ActivityCacheBypassControl';
// Sidebar
-export { ActivitySidebar } from './sidebar/ActivitySidebar';
export { ActivitySidebarServer } from './sidebar/ActivitySidebarServer';
export { ActivitySidebarSkeleton } from './sidebar/ActivitySidebarSkeleton';
diff --git a/components/Auth/AuthContent.tsx b/components/Auth/AuthContent.tsx
index e2fcb3a0b..14a3812d6 100644
--- a/components/Auth/AuthContent.tsx
+++ b/components/Auth/AuthContent.tsx
@@ -7,8 +7,6 @@ import ForgotPassword from './screens/ForgotPassword';
import { AuthScreen, type AuthAppearance, type CatalystSurface } from './types';
import AnalyticsService, { LogEvent } from '@/services/analytics.service';
-export type { AuthAppearance, CatalystSurface } from './types';
-
interface AuthContentProps {
onClose?: () => void;
onSuccess?: () => void;
diff --git a/components/Bounty/lib/bountyUtil.ts b/components/Bounty/lib/bountyUtil.ts
index 7e4b6f399..b96866768 100644
--- a/components/Bounty/lib/bountyUtil.ts
+++ b/components/Bounty/lib/bountyUtil.ts
@@ -72,15 +72,6 @@ export const countClosedBounties = (bounties: Bounty[]): number => {
return getClosedBounties(bounties).length;
};
-/**
- * Calculates the total amount of all bounties in an array
- * @param bounties Array of bounties to sum
- * @returns Total amount as a number
- */
-export const calculateTotalBountyAmount = (bounties: Bounty[]): number => {
- return bounties.reduce((sum, bounty) => sum + parseFloat(bounty.amount), 0);
-};
-
/**
* Finds the first active (open) bounty in an array
* @param bounties Array of bounties to search
@@ -113,22 +104,6 @@ export const findClosedBounty = (bounties: Bounty[]): Bounty | undefined => {
return closedBounty;
};
-/**
- * Gets the bounty to display from an array of bounties
- * @param bounties Array of bounties
- * @returns The display bounty or undefined if none found
- */
-export const getDisplayBounty = (bounties: Bounty[]): Bounty | undefined => {
- if (!bounties || !Array.isArray(bounties) || bounties.length === 0) {
- return undefined;
- }
-
- const activeBounty = findActiveBounty(bounties);
- const closedBounty = findClosedBounty(bounties);
-
- return activeBounty || closedBounty;
-};
-
/**
* Checks if a bounty is expiring soon (within 3 days)
* @param expirationDate The expiration date string
@@ -151,22 +126,6 @@ export const isExpiringSoon = (expirationDate?: string, daysThreshold: number =
return diffDays > 0 && diffDays < daysThreshold;
};
-/**
- * Gets the appropriate title for a bounty based on its type and status
- * @param bounty The bounty object
- * @param isOpen Whether the bounty is open
- * @returns The appropriate title string
- */
-export const getBountyTitle = (bounty?: Bounty, isOpen?: boolean): string => {
- if (bounty?.bountyType === 'REVIEW') {
- return isOpen ? 'Bounty: Peer Review' : 'Awarded Bounty: Peer Review';
- }
- if (bounty?.bountyType === 'ANSWER') {
- return isOpen ? 'Bounty: Answer to Question' : 'Awarded Bounty: Answer to Question';
- }
- return isOpen ? 'Bounty' : 'Awarded Bounty';
-};
-
/**
* Calculates the total awarded amount for a bounty with solutions
* @param bounty The bounty object with solutions
@@ -194,157 +153,6 @@ export interface Contributor {
isCreator?: boolean;
}
-/**
- * Formats contributor names for display
- * @param contributors Array of contributors
- * @returns Formatted string of contributor names
- */
-export const formatContributorNames = (contributors: Contributor[]): string => {
- if (contributors.length === 0) return 'Unknown';
-
- // Find the creator first (the main bounty creator)
- const creator = contributors.find((c) => c.isCreator);
- const creatorName = creator?.profile.fullName || contributors[0]?.profile.fullName || 'Unknown';
-
- // Get all non-creator contributors
- const otherContributors = contributors.filter(
- (c) => c.profile.fullName !== creatorName && c.profile.fullName
- );
-
- if (contributors.length === 1) {
- // Case 1: Just one contributor
- return creatorName;
- } else if (contributors.length === 2) {
- // Case 2: Two contributors
- const otherContributor = otherContributors[0];
- return `${creatorName} and ${otherContributor?.profile.fullName || 'another contributor'}`;
- } else {
- // Case 3: More than two contributors
- if (otherContributors.length === 0) {
- return `${creatorName} and others`;
- } else if (otherContributors.length === 1) {
- return `${creatorName} and ${otherContributors[0].profile.fullName}`;
- } else {
- return `${creatorName}, ${otherContributors[0].profile.fullName} and ${
- otherContributors.length > 1 ? `${otherContributors.length - 1} others` : 'another'
- }`;
- }
- }
-};
-
-/**
- * Extracts all contributors from an array of bounties
- * @param bounties Array of bounties
- * @param displayBounty The main bounty being displayed
- * @returns Array of contributors with profile information
- */
-export const extractContributors = (bounties: Bounty[], displayBounty?: Bounty): Contributor[] => {
- return bounties
- .filter((bounty) => bounty.createdBy.authorProfile)
- .map((bounty) => {
- // A bounty is not a contribution if it doesn't have a parent bounty
- const isContribution = bounty.raw && !!bounty.raw.parent;
-
- return {
- profile: bounty.createdBy.authorProfile!,
- amount: Number(bounty.amount),
- isCreator: bounty.id === displayBounty?.id && !isContribution,
- };
- });
-};
-
-/**
- * Filters out the creator from the contributors list
- * @param contributors Array of contributors
- * @returns Array of contributors without the creator
- */
-export const filterOutCreator = (contributors: Contributor[]): Contributor[] => {
- return contributors.filter((contributor) => !contributor.isCreator);
-};
-
-/**
- * Extracts contributors for display in the UI based on the following rules:
- * 1. If there are no contributors (other than the creator), return an empty array
- * 2. If there are one or more contributors, return both the creator and the contributors
- *
- * @param bounty The bounty to extract contributors from
- * @returns Array of contributors for display
- */
-export const extractContributorsForDisplay = (bounty: Bounty): Contributor[] => {
- // If there are no contributions, return an empty array
- if (!bounty.contributions || bounty.contributions.length === 0) {
- return [];
- }
-
- // Process contributions directly from the bounty.contributions array
- const contributorsFromContributions = bounty.contributions.map((contribution) => {
- // Get the name from the contribution's createdBy
- let fullName = 'Unknown';
- let profileImage: string | undefined = undefined;
-
- // Try to get profile info from authorProfile if it exists
- if (contribution.createdBy.authorProfile) {
- fullName = contribution.createdBy.authorProfile.fullName || 'Unknown';
- profileImage = contribution.createdBy.authorProfile.profileImage;
- }
- // Fallback to raw data if available
- else if (contribution.raw?.created_by?.author_profile) {
- const rawProfile = contribution.raw.created_by.author_profile;
- fullName = `${rawProfile.first_name || ''} ${rawProfile.last_name || ''}`.trim() || 'Unknown';
- profileImage = rawProfile.profile_image;
- }
-
- return {
- profile: {
- fullName,
- profileImage,
- isClaimed: true,
- },
- amount: Number(contribution.amount),
- isCreator: false,
- };
- });
-
- // Add the creator as a contributor if not already included
- let creatorFullName = 'Unknown';
- let creatorProfileImage: string | undefined = undefined;
-
- // Try to get creator profile info from authorProfile if it exists
- if (bounty.createdBy.authorProfile) {
- creatorFullName = bounty.createdBy.authorProfile.fullName || 'Unknown';
- creatorProfileImage = bounty.createdBy.authorProfile.profileImage;
- }
- // Fallback to raw data if available
- else if (bounty.raw?.created_by?.author_profile) {
- const rawProfile = bounty.raw.created_by.author_profile;
- creatorFullName =
- `${rawProfile.first_name || ''} ${rawProfile.last_name || ''}`.trim() || 'Unknown';
- creatorProfileImage = rawProfile.profile_image;
- }
-
- const creator: Contributor = {
- profile: {
- fullName: creatorFullName,
- profileImage: creatorProfileImage,
- isClaimed: true,
- },
- amount: Number(bounty.amount),
- isCreator: true,
- };
-
- // Check if the creator is already in the contributors list
- const creatorAlreadyIncluded = contributorsFromContributions.some(
- (c) => c.profile.fullName === creator.profile.fullName
- );
-
- // Return all contributors including the creator (if not already included)
- const result = creatorAlreadyIncluded
- ? contributorsFromContributions
- : [...contributorsFromContributions, creator];
-
- return result;
-};
-
/**
* Checks if a comment has any bounties
* @param comment The comment object to check
@@ -362,77 +170,6 @@ export interface BountyAvatar {
authorId?: number;
}
-/**
- * Extracts avatar information from bounties for use in UI components
- * @param bounties Array of bounties to extract avatars from
- * @param openOnly Whether to only include open bounties (default: true)
- * @returns Array of avatar objects ready for display
- */
-export const extractBountyAvatars = (
- bounties: Bounty[],
- openOnly: boolean = true
-): BountyAvatar[] => {
- // Filter bounties if openOnly is true
- const filteredBounties = openOnly
- ? bounties.filter((bounty) => bounty.status === 'OPEN')
- : bounties;
-
- // Extract avatars from each bounty
- const avatars = filteredBounties.flatMap((bounty) => {
- const result = [];
-
- // Add creator avatar if available
- if (bounty.createdBy) {
- // Try to access profile information from raw data
- const creatorRaw = bounty.raw?.created_by || {};
- const authorProfile = bounty.createdBy.authorProfile || {};
-
- // Use explicit type casting to avoid TypeScript errors with optional fields
- const profileImage = (authorProfile as any).profileImage || (creatorRaw as any).profile_image;
- const fullName = (authorProfile as any).fullName || (creatorRaw as any).full_name;
- const id = (authorProfile as any).id || (creatorRaw as any).id;
-
- result.push({
- src: profileImage || '/images/default-avatar.png',
- alt: fullName || 'Creator',
- tooltip: fullName,
- authorId: id,
- });
- }
-
- // Add contributor avatars if available
- if (bounty.contributions && bounty.contributions.length > 0) {
- const contributorAvatars = bounty.contributions.map((contribution) => {
- const contributorRaw = contribution.raw?.user?.author_profile || {};
- const authorProfile = contribution.createdBy?.authorProfile || {};
-
- // Use explicit type casting to avoid TypeScript errors with optional fields
- const profileImage =
- (authorProfile as any).profileImage || (contributorRaw as any).profile_image;
- const fullName = (authorProfile as any).fullName || (contributorRaw as any).full_name;
- const id = (authorProfile as any).id || (contributorRaw as any).id;
-
- return {
- src: profileImage || '/images/default-avatar.png',
- alt: fullName || 'Contributor',
- tooltip: fullName,
- authorId: id,
- };
- });
-
- result.push(...contributorAvatars);
- }
-
- return result;
- });
-
- // Remove duplicates by authorId
- return avatars.filter(
- (avatar, index, self) =>
- avatar.authorId && index === self.findIndex((a) => a.authorId === avatar.authorId)
- );
-};
-
/**
* Hacky shim to ensure we are rendering $150 USD for Foundation bounties.
* Extracts the user ID of the bounty creator from various possible data structures.
@@ -549,15 +286,6 @@ export const calculateBountyDisplayAmountUSD = (bounty: Bounty, exchangeRate: nu
return Math.round(rscAmount * exchangeRate);
};
-export const calculateTotalBountyDisplayAmountUSD = (
- bounties: Bounty[],
- exchangeRate: number
-): number => {
- return bounties.reduce((total, bounty) => {
- return total + calculateBountyDisplayAmountUSD(bounty, exchangeRate);
- }, 0);
-};
-
/**
* Calculates the display amount for a bounty, returning either USD or RSC based on preference.
* For Foundation bounties displayed in USD, returns a flat $150.
diff --git a/components/Comment/components/AuthorPosts.tsx b/components/Comment/components/AuthorPosts.tsx
index c84e039f2..cf29a0d4f 100644
--- a/components/Comment/components/AuthorPosts.tsx
+++ b/components/Comment/components/AuthorPosts.tsx
@@ -11,10 +11,6 @@ import { AuthorPostsCarousel } from './AuthorPostsCarousel';
import { PostComposerModal } from './PostComposerModal';
import { useAuthorPostComposer } from './useAuthorPostComposer';
-export { useAuthorPostComposer } from './useAuthorPostComposer';
-export { PostComposerModal } from './PostComposerModal';
-export type { AuthorPostComposer } from './useAuthorPostComposer';
-
const AuthorPostsEmptyShell: FC<{ children: ReactNode }> = ({ children }) => (
{children}
@@ -33,8 +29,6 @@ const ViewerEmptyState: FC = () => (
);
-export const ViewerPostsEmptyState = ViewerEmptyState;
-
interface AuthorPostsProps {
posts: Comment[];
documentId: number;
diff --git a/components/Comment/lib/types.ts b/components/Comment/lib/types.ts
index bb84036c1..7de888ba9 100644
--- a/components/Comment/lib/types.ts
+++ b/components/Comment/lib/types.ts
@@ -1,5 +1,3 @@
-import { Comment } from '@/types/comment';
-
export interface MentionItem {
id: string | null;
entityType: 'user' | 'author' | 'paper' | 'post';
@@ -78,21 +76,3 @@ export type CommentContent =
| { content: Array
}
| { type: string; content: any[] }
| string;
-
-/**
- * Options for comment editor
- */
-export interface CommentEditorOptions {
- placeholder?: string;
- isReadOnly?: boolean;
- debug?: boolean;
-}
-
-/**
- * Result of a comment operation
- */
-export interface CommentOperationResult {
- success: boolean;
- comment?: Comment;
- error?: string;
-}
diff --git a/components/Earn/BountyHubSelector.tsx b/components/Earn/BountyHubSelector.tsx
deleted file mode 100644
index 3ef3e1cbf..000000000
--- a/components/Earn/BountyHubSelector.tsx
+++ /dev/null
@@ -1,230 +0,0 @@
-'use client';
-
-import { useEffect, useState, useCallback, useRef } from 'react';
-import {
- MultiSelectOption,
- SearchableMultiSelect,
-} from '@/components/ui/form/SearchableMultiSelect';
-import { Badge } from '@/components/ui/Badge';
-import { Button } from '@/components/ui/Button';
-import { X, ChevronDown, Filter } from 'lucide-react';
-import { BaseMenu } from '@/components/ui/form/BaseMenu';
-import { BountyService } from '@/services/bounty.service';
-import { Topic } from '@/types/topic';
-
-export interface Hub {
- id: string | number;
- name: string;
- description?: string;
- color?: string;
-}
-
-interface BountyHubSelectorProps {
- selectedHubs: Hub[];
- onChange: (hubs: Hub[]) => void;
- error?: string | null;
- displayCountOnly?: boolean;
- hideSelectedItems?: boolean;
-}
-
-export function BountyHubSelector({
- selectedHubs,
- onChange,
- error,
- displayCountOnly = false,
- hideSelectedItems = false,
-}: BountyHubSelectorProps) {
- const [allHubs, setAllHubs] = useState([]);
- const [menuOpen, setMenuOpen] = useState(false);
- const menuContentRef = useRef(null);
-
- // Auto-focus input when menu opens
- useEffect(() => {
- if (menuOpen) {
- // Longer delay to ensure input is rendered and accessible
- setTimeout(() => {
- // Try to find the input in the document - this works even with portals
- const input = document.querySelector('.SearchableMultiSelect-input');
- if (input instanceof HTMLInputElement) {
- input.focus();
- } else {
- // Fallback to searching entire document for any input in our component
- const inputs = document.querySelectorAll('input');
- inputs.forEach((input) => {
- // Find inputs that are descendants of elements with our component classes
- if (input.closest('.overflow-visible.shadow-lg')) {
- input.focus();
- }
- });
- }
- }, 150);
- }
- }, [menuOpen]);
-
- // fetch all hubs at mount
- useEffect(() => {
- (async () => {
- const hubs = await BountyService.getBountyHubs();
- setAllHubs(hubs);
- })();
- }, []);
-
- // Populate missing names in selectedHubs when hubs are fetched
- // This is needed when we restore topics from URL params (only IDs are stored)
- useEffect(() => {
- if (allHubs.length === 0) return;
-
- const hasMissingNames = selectedHubs.some((hub) => !hub.name || hub.name === '');
- if (hasMissingNames) {
- const populatedHubs = selectedHubs.map((hub) => {
- // If hub already has a name, keep it
- if (hub.name && hub.name !== '') {
- return hub;
- }
- // Otherwise, find matching hub from fetched hubs and populate name/description
- const matchedHub = allHubs.find((h) => h.id === hub.id);
- if (matchedHub) {
- return {
- ...hub,
- name: matchedHub.name,
- description: matchedHub.description,
- };
- }
- // If no match found, return as-is
- return hub;
- });
-
- const anyChanged = populatedHubs.some((hub, index) => hub.name !== selectedHubs[index]?.name);
- if (anyChanged) {
- onChange(populatedHubs);
- }
- }
- }, [allHubs, selectedHubs, onChange]);
-
- // utility conversions
- const hubsToOptions = (hubs: Hub[]): MultiSelectOption[] =>
- hubs.map((hub) => ({ value: String(hub.id), label: hub.name }));
-
- const topicsToHubs = (topics: Topic[]): Hub[] =>
- topics.map((topic) => ({
- id: topic.id,
- name: topic.name,
- description: topic.description,
- }));
-
- const optionsToHubs = (options: MultiSelectOption[]): Hub[] =>
- options.map(
- (opt) =>
- selectedHubs.find((h) => String(h.id) === opt.value) || {
- id: opt.value,
- name: opt.label,
- }
- );
-
- const allHubOptions = hubsToOptions(topicsToHubs(allHubs));
-
- // Local search within allHubs
- const filterHubs = useCallback(
- async (query: string): Promise => {
- if (!query) {
- return hubsToOptions(topicsToHubs(allHubs));
- }
- const lowered = query.toLowerCase();
- const filtered = allHubs.filter((hub) => hub.name.toLowerCase().includes(lowered));
- return hubsToOptions(topicsToHubs(filtered));
- },
- [allHubs, selectedHubs]
- );
-
- const handleChange = (options: MultiSelectOption[]) => {
- onChange(optionsToHubs(options));
- if (displayCountOnly) {
- setMenuOpen(false);
- }
- };
-
- const CustomSelectedItems = () => (
-
- {selectedHubs.map((hub) => (
-
{
- e.preventDefault();
- e.stopPropagation();
- onChange(selectedHubs.filter((h) => h.id !== hub.id));
- if (displayCountOnly) {
- setMenuOpen(false);
- }
- }}
- >
- {hub.color && (
-
- )}
- {hub.name}
-
- ))}
-
- );
-
- if (displayCountOnly) {
- const trigger = (
-
- );
-
- return (
-
-
-
-
-
- );
- }
-
- return (
-
-
-
- {selectedHubs.length > 0 && !hideSelectedItems && }
-
-
- );
-}
diff --git a/components/Editor/components/menus/LinkMenu/LinkMenu.tsx b/components/Editor/components/menus/LinkMenu/LinkMenu.tsx
index 025a72e68..4b771588a 100644
--- a/components/Editor/components/menus/LinkMenu/LinkMenu.tsx
+++ b/components/Editor/components/menus/LinkMenu/LinkMenu.tsx
@@ -78,5 +78,3 @@ export const LinkMenu = ({ editor, appendTo }: MenuProps): React.JSX.Element =>
);
};
-
-export default LinkMenu;
diff --git a/components/Editor/extensions/BlockquoteFigure/BlockquoteFigure.ts b/components/Editor/extensions/BlockquoteFigure/BlockquoteFigure.ts
index 44baaafce..0472d80b1 100644
--- a/components/Editor/extensions/BlockquoteFigure/BlockquoteFigure.ts
+++ b/components/Editor/extensions/BlockquoteFigure/BlockquoteFigure.ts
@@ -76,5 +76,3 @@ export const BlockquoteFigure = Figure.extend({
};
},
});
-
-export default BlockquoteFigure;
diff --git a/components/Editor/extensions/BlockquoteFigure/Quote/Quote.ts b/components/Editor/extensions/BlockquoteFigure/Quote/Quote.ts
index 80888bbb8..9a9c0e8f5 100644
--- a/components/Editor/extensions/BlockquoteFigure/Quote/Quote.ts
+++ b/components/Editor/extensions/BlockquoteFigure/Quote/Quote.ts
@@ -27,5 +27,3 @@ export const Quote = Node.create({
};
},
});
-
-export default Quote;
diff --git a/components/Editor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts b/components/Editor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts
index c4e51c06a..9b08e16a3 100644
--- a/components/Editor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts
+++ b/components/Editor/extensions/BlockquoteFigure/QuoteCaption/QuoteCaption.ts
@@ -50,5 +50,3 @@ export const QuoteCaption = Node.create({
};
},
});
-
-export default QuoteCaption;
diff --git a/components/Editor/extensions/Document/Document.ts b/components/Editor/extensions/Document/Document.ts
index 58d8edcbb..86096cd40 100644
--- a/components/Editor/extensions/Document/Document.ts
+++ b/components/Editor/extensions/Document/Document.ts
@@ -3,5 +3,3 @@ import { Document as TiptapDocument } from '@tiptap/extension-document';
export const Document = TiptapDocument.extend({
content: '(block|columns)+',
});
-
-export default Document;
diff --git a/components/Editor/extensions/EmojiSuggestion/suggestion.ts b/components/Editor/extensions/EmojiSuggestion/suggestion.ts
index 45db9388c..648934e1c 100644
--- a/components/Editor/extensions/EmojiSuggestion/suggestion.ts
+++ b/components/Editor/extensions/EmojiSuggestion/suggestion.ts
@@ -78,5 +78,3 @@ export const emojiSuggestion = {
};
},
};
-
-export default emojiSuggestion;
diff --git a/components/Editor/extensions/Figcaption/Figcaption.ts b/components/Editor/extensions/Figcaption/Figcaption.ts
index f909023d7..53cf3f208 100644
--- a/components/Editor/extensions/Figcaption/Figcaption.ts
+++ b/components/Editor/extensions/Figcaption/Figcaption.ts
@@ -86,5 +86,3 @@ export const Figcaption = Node.create({
return ['figcaption', mergeAttributes(HTMLAttributes), 0];
},
});
-
-export default Figcaption;
diff --git a/components/Editor/extensions/Figure/Figure.ts b/components/Editor/extensions/Figure/Figure.ts
index ddeeeed67..f5c7e8e24 100644
--- a/components/Editor/extensions/Figure/Figure.ts
+++ b/components/Editor/extensions/Figure/Figure.ts
@@ -58,5 +58,3 @@ export const Figure = Node.create({
];
},
});
-
-export default Figure;
diff --git a/components/Editor/extensions/FontSize/FontSize.ts b/components/Editor/extensions/FontSize/FontSize.ts
index 20d6e8882..0c2746ed3 100644
--- a/components/Editor/extensions/FontSize/FontSize.ts
+++ b/components/Editor/extensions/FontSize/FontSize.ts
@@ -60,5 +60,3 @@ export const FontSize = Extension.create({
};
},
});
-
-export default FontSize;
diff --git a/components/Editor/extensions/Heading/Heading.ts b/components/Editor/extensions/Heading/Heading.ts
index 844910fca..cad80692f 100644
--- a/components/Editor/extensions/Heading/Heading.ts
+++ b/components/Editor/extensions/Heading/Heading.ts
@@ -11,5 +11,3 @@ export const Heading = TiptapHeading.extend({
return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
},
});
-
-export default Heading;
diff --git a/components/Editor/extensions/HorizontalRule/HorizontalRule.ts b/components/Editor/extensions/HorizontalRule/HorizontalRule.ts
index 2ca7b56d4..31ff3188e 100644
--- a/components/Editor/extensions/HorizontalRule/HorizontalRule.ts
+++ b/components/Editor/extensions/HorizontalRule/HorizontalRule.ts
@@ -10,5 +10,3 @@ export const HorizontalRule = TiptapHorizontalRule.extend({
];
},
});
-
-export default HorizontalRule;
diff --git a/components/Editor/extensions/Image/Image.ts b/components/Editor/extensions/Image/Image.ts
index 18177fe5c..2924fea6d 100644
--- a/components/Editor/extensions/Image/Image.ts
+++ b/components/Editor/extensions/Image/Image.ts
@@ -3,5 +3,3 @@ import { Image as BaseImage } from '@tiptap/extension-image';
export const Image = BaseImage.extend({
group: 'block',
});
-
-export default Image;
diff --git a/components/Editor/extensions/ImageBlock/ImageBlock.ts b/components/Editor/extensions/ImageBlock/ImageBlock.ts
index c1207681d..d55aed42e 100644
--- a/components/Editor/extensions/ImageBlock/ImageBlock.ts
+++ b/components/Editor/extensions/ImageBlock/ImageBlock.ts
@@ -104,5 +104,3 @@ export const ImageBlock = Image.extend({
return ReactNodeViewRenderer(ImageBlockView);
},
});
-
-export default ImageBlock;
diff --git a/components/Editor/extensions/ImageBlock/components/ImageBlockView.tsx b/components/Editor/extensions/ImageBlock/components/ImageBlockView.tsx
index f9d508407..f12e05557 100644
--- a/components/Editor/extensions/ImageBlock/components/ImageBlockView.tsx
+++ b/components/Editor/extensions/ImageBlock/components/ImageBlockView.tsx
@@ -43,5 +43,3 @@ export const ImageBlockView = (props: ImageBlockViewProps) => {
);
};
-
-export default ImageBlockView;
diff --git a/components/Editor/extensions/ImageUpload/ImageUpload.ts b/components/Editor/extensions/ImageUpload/ImageUpload.ts
index ce2ac647d..dfe7a053e 100644
--- a/components/Editor/extensions/ImageUpload/ImageUpload.ts
+++ b/components/Editor/extensions/ImageUpload/ImageUpload.ts
@@ -50,5 +50,3 @@ export const ImageUpload = Node.create({
return ReactNodeViewRenderer(ImageUploadComponent);
},
});
-
-export default ImageUpload;
diff --git a/components/Editor/extensions/ImageUpload/view/ImageUpload.tsx b/components/Editor/extensions/ImageUpload/view/ImageUpload.tsx
index b475feb65..bc5770d90 100644
--- a/components/Editor/extensions/ImageUpload/view/ImageUpload.tsx
+++ b/components/Editor/extensions/ImageUpload/view/ImageUpload.tsx
@@ -33,5 +33,3 @@ export const ImageUpload = ({
);
};
-
-export default ImageUpload;
diff --git a/components/Editor/extensions/ImageUpload/view/ImageUploader.tsx b/components/Editor/extensions/ImageUpload/view/ImageUploader.tsx
index e7adf2753..cf931bb5c 100644
--- a/components/Editor/extensions/ImageUpload/view/ImageUploader.tsx
+++ b/components/Editor/extensions/ImageUpload/view/ImageUploader.tsx
@@ -63,5 +63,3 @@ export const ImageUploader = ({ onUpload }: { onUpload: (url: string) => void })
);
};
-
-export default ImageUploader;
diff --git a/components/Editor/extensions/Link/Link.ts b/components/Editor/extensions/Link/Link.ts
index 230d10ed5..90ae2d717 100644
--- a/components/Editor/extensions/Link/Link.ts
+++ b/components/Editor/extensions/Link/Link.ts
@@ -88,5 +88,3 @@ export const Link = TiptapLink.extend({
];
},
});
-
-export default Link;
diff --git a/components/Editor/extensions/MultiColumn/Column.ts b/components/Editor/extensions/MultiColumn/Column.ts
index 592caf7a4..c6f42d813 100644
--- a/components/Editor/extensions/MultiColumn/Column.ts
+++ b/components/Editor/extensions/MultiColumn/Column.ts
@@ -29,5 +29,3 @@ export const Column = Node.create({
];
},
});
-
-export default Column;
diff --git a/components/Editor/extensions/MultiColumn/Columns.ts b/components/Editor/extensions/MultiColumn/Columns.ts
index 35699bff2..f1fa1363e 100644
--- a/components/Editor/extensions/MultiColumn/Columns.ts
+++ b/components/Editor/extensions/MultiColumn/Columns.ts
@@ -61,5 +61,3 @@ export const Columns = Node.create({
];
},
});
-
-export default Columns;
diff --git a/components/Editor/extensions/Selection/Selection.ts b/components/Editor/extensions/Selection/Selection.ts
index 38d84e720..8bcba060c 100644
--- a/components/Editor/extensions/Selection/Selection.ts
+++ b/components/Editor/extensions/Selection/Selection.ts
@@ -32,5 +32,3 @@ export const Selection = Extension.create({
];
},
});
-
-export default Selection;
diff --git a/components/Editor/extensions/SlashCommand/MenuList.tsx b/components/Editor/extensions/SlashCommand/MenuList.tsx
index 317101def..fe5432e9b 100644
--- a/components/Editor/extensions/SlashCommand/MenuList.tsx
+++ b/components/Editor/extensions/SlashCommand/MenuList.tsx
@@ -153,5 +153,3 @@ export const MenuList = React.forwardRef((props: MenuListProps, ref) => {
});
MenuList.displayName = 'MenuList';
-
-export default MenuList;
diff --git a/components/Editor/extensions/SlashCommand/SlashCommand.ts b/components/Editor/extensions/SlashCommand/SlashCommand.ts
index b098aebab..0a2e71752 100644
--- a/components/Editor/extensions/SlashCommand/SlashCommand.ts
+++ b/components/Editor/extensions/SlashCommand/SlashCommand.ts
@@ -354,5 +354,3 @@ export const SlashCommand = Extension.create({
};
},
});
-
-export default SlashCommand;
diff --git a/components/Editor/extensions/Table/Header.ts b/components/Editor/extensions/Table/Header.ts
index cc1610d37..9fdc66bda 100644
--- a/components/Editor/extensions/Table/Header.ts
+++ b/components/Editor/extensions/Table/Header.ts
@@ -85,5 +85,3 @@ export const TableHeader = TiptapTableHeader.extend({
];
},
});
-
-export default TableHeader;
diff --git a/components/Editor/extensions/Table/Row.ts b/components/Editor/extensions/Table/Row.ts
index 4b00633c6..49ab93b98 100644
--- a/components/Editor/extensions/Table/Row.ts
+++ b/components/Editor/extensions/Table/Row.ts
@@ -4,5 +4,3 @@ export const TableRow = TiptapTableRow.extend({
allowGapCursor: false,
content: 'tableCell*',
});
-
-export default TableRow;
diff --git a/components/Editor/extensions/Table/Table.ts b/components/Editor/extensions/Table/Table.ts
index 1ad9f9214..1bc15f525 100644
--- a/components/Editor/extensions/Table/Table.ts
+++ b/components/Editor/extensions/Table/Table.ts
@@ -1,5 +1,3 @@
import { Table as TiptapTable } from '@tiptap/extension-table';
export const Table = TiptapTable.configure({ resizable: true, lastColumnResizable: false });
-
-export default Table;
diff --git a/components/Editor/extensions/Table/menus/TableColumn/utils.ts b/components/Editor/extensions/Table/menus/TableColumn/utils.ts
index a74bbf64c..4f9e3af3e 100644
--- a/components/Editor/extensions/Table/menus/TableColumn/utils.ts
+++ b/components/Editor/extensions/Table/menus/TableColumn/utils.ts
@@ -35,5 +35,3 @@ export const isColumnGripSelected = ({
return !!gripColumn;
};
-
-export default isColumnGripSelected;
diff --git a/components/Editor/extensions/Table/menus/TableRow/utils.ts b/components/Editor/extensions/Table/menus/TableRow/utils.ts
index 33d12b8a4..266dc1429 100644
--- a/components/Editor/extensions/Table/menus/TableRow/utils.ts
+++ b/components/Editor/extensions/Table/menus/TableRow/utils.ts
@@ -35,5 +35,3 @@ export const isRowGripSelected = ({
return !!gripRow;
};
-
-export default isRowGripSelected;
diff --git a/components/Editor/extensions/Table/utils.ts b/components/Editor/extensions/Table/utils.ts
index bc530d3e9..3dac6e7ba 100644
--- a/components/Editor/extensions/Table/utils.ts
+++ b/components/Editor/extensions/Table/utils.ts
@@ -142,29 +142,6 @@ export const getCellsInRow = (rowIndex: number | number[]) => (selection: Select
return null;
};
-export const getCellsInTable = (selection: Selection) => {
- const table = findTable(selection);
-
- if (table) {
- const map = TableMap.get(table.node);
- const cells = map.cellsInRect({
- left: 0,
- right: map.width,
- top: 0,
- bottom: map.height,
- });
-
- return cells.map((nodePos) => {
- const node = table.node.nodeAt(nodePos);
- const pos = nodePos + table.start;
-
- return { pos, start: pos + 1, node };
- });
- }
-
- return null;
-};
-
export const findParentNodeClosestToPos = (
$pos: ResolvedPos,
predicate: (node: Node) => boolean
@@ -185,13 +162,6 @@ export const findParentNodeClosestToPos = (
return null;
};
-export const findCellClosestToPos = ($pos: ResolvedPos) => {
- const predicate = (node: Node) =>
- node.type.spec.tableRole && /cell/i.test(node.type.spec.tableRole);
-
- return findParentNodeClosestToPos($pos, predicate);
-};
-
const select = (type: 'row' | 'column') => (index: number) => (tr: Transaction) => {
const table = findTable(tr.selection);
const isRowSelection = type === 'row';
@@ -237,22 +207,3 @@ const select = (type: 'row' | 'column') => (index: number) => (tr: Transaction)
export const selectColumn = select('column');
export const selectRow = select('row');
-
-export const selectTable = (tr: Transaction) => {
- const table = findTable(tr.selection);
-
- if (table) {
- const { map } = TableMap.get(table.node);
-
- if (map && map.length) {
- const head = table.start + map[0];
- const anchor = table.start + map[map.length - 1];
- const $head = tr.doc.resolve(head);
- const $anchor = tr.doc.resolve(anchor);
-
- return tr.setSelection(new CellSelection($anchor, $head));
- }
- }
-
- return tr;
-};
diff --git a/components/Editor/extensions/extension-kit.ts b/components/Editor/extensions/extension-kit.ts
index 6908fa634..c5daeb0c8 100644
--- a/components/Editor/extensions/extension-kit.ts
+++ b/components/Editor/extensions/extension-kit.ts
@@ -174,5 +174,3 @@ export const ExtensionKit = ({ customDocument, placeholderConfig }: ExtensionKit
Youtube,
ReadOnlyFigure,
];
-
-export default ExtensionKit;
diff --git a/components/Editor/extensions/index.ts b/components/Editor/extensions/index.ts
index c27a29db8..e05904b17 100644
--- a/components/Editor/extensions/index.ts
+++ b/components/Editor/extensions/index.ts
@@ -5,7 +5,7 @@ export { Highlight } from '@tiptap/extension-highlight';
export { CharacterCount } from '@tiptap/extension-character-count';
export { Underline } from '@tiptap/extension-underline';
export { Placeholder } from '@tiptap/extension-placeholder';
-export { Emoji, gitHubEmojis } from '@tiptap/extension-emoji';
+export { Emoji } from '@tiptap/extension-emoji';
export { TextAlign } from '@tiptap/extension-text-align';
export { TextStyle } from '@tiptap/extension-text-style';
export { FontFamily } from '@tiptap/extension-font-family';
@@ -16,14 +16,11 @@ export { Dropcursor } from '@tiptap/extension-dropcursor';
export { Subscript } from '@tiptap/extension-subscript';
export { TableOfContents } from '@tiptap/extension-table-of-contents';
export { Superscript } from '@tiptap/extension-superscript';
-export { Paragraph } from '@tiptap/extension-paragraph';
-export { BulletList } from '@tiptap/extension-bullet-list';
-export { OrderedList } from '@tiptap/extension-ordered-list';
export { TaskItem } from '@tiptap/extension-task-item';
export { TaskList } from '@tiptap/extension-task-list';
export { FileHandler } from '@tiptap/extension-file-handler';
export { Details, DetailsContent, DetailsSummary } from '@tiptap/extension-details';
-export { Mathematics, migrateMathStrings } from '@tiptap/extension-mathematics';
+export { Mathematics } from '@tiptap/extension-mathematics';
export { UniqueID } from '@tiptap/extension-unique-id';
export { Selection } from './Selection';
@@ -35,14 +32,10 @@ export { Document } from './Document';
export { TrailingNode } from './TrailingNode';
export { SlashCommand } from './SlashCommand';
export { FontSize } from './FontSize';
-export { Figure } from './Figure';
export { Figcaption } from './Figcaption';
export { BlockquoteFigure } from './BlockquoteFigure';
-export { Quote } from './BlockquoteFigure/Quote';
-export { QuoteCaption } from './BlockquoteFigure/QuoteCaption';
export { Link } from './Link';
export { ImageUpload } from './ImageUpload';
export { ImageBlock } from './ImageBlock';
export { Columns, Column } from './MultiColumn';
export { emojiSuggestion } from './EmojiSuggestion';
-export { Youtube } from './Youtube';
diff --git a/components/Editor/lib/api.ts b/components/Editor/lib/api.ts
index c8ec359dc..1dd4bc9f9 100644
--- a/components/Editor/lib/api.ts
+++ b/components/Editor/lib/api.ts
@@ -11,5 +11,3 @@ export class API {
}
};
}
-
-export default API;
diff --git a/components/Editor/lib/data/grantTemplate.tsx b/components/Editor/lib/data/grantTemplate.tsx
index 93bc86d18..a18427946 100644
--- a/components/Editor/lib/data/grantTemplate.tsx
+++ b/components/Editor/lib/data/grantTemplate.tsx
@@ -298,5 +298,4 @@ const grantTemplate: Template = {
],
};
-export type GrantTemplate = typeof grantTemplate;
export default grantTemplate;
diff --git a/components/Editor/lib/data/initialContent.tsx b/components/Editor/lib/data/initialContent.tsx
index e110f21a5..d0ba9ef32 100644
--- a/components/Editor/lib/data/initialContent.tsx
+++ b/components/Editor/lib/data/initialContent.tsx
@@ -165,183 +165,4 @@ const researchTemplate: Template = {
],
};
-const grantTemplate: Template = {
- type: 'doc',
- content: [
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 1,
- },
- content: [
- {
- type: 'text',
- text: 'Request for Proposal Title',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Executive Summary',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'Brief overview of your proposal...',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Project Description',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'Detailed description of your proposed project...',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Goals and Objectives',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'List your project goals and objectives...',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Methodology',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'Describe your approach and methods...',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Budget',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'Detailed budget breakdown...',
- },
- ],
- },
- {
- type: 'heading',
- attrs: {
- textAlign: 'left',
- level: 2,
- },
- content: [
- {
- type: 'text',
- text: 'Timeline',
- },
- ],
- },
- {
- type: 'paragraph',
- attrs: {
- class: null,
- textAlign: 'left',
- },
- content: [
- {
- type: 'text',
- text: 'Project timeline and milestones...',
- },
- ],
- },
- ],
-};
-
-export const getInitialContent = (type: 'research' | 'grant' = 'research'): Template => {
- return type === 'research' ? researchTemplate : grantTemplate;
-};
-
export const initialContent = researchTemplate; // Default export for backward compatibility
diff --git a/components/Editor/lib/data/proposalTemplate.tsx b/components/Editor/lib/data/proposalTemplate.tsx
index 31105afb8..833c434ce 100644
--- a/components/Editor/lib/data/proposalTemplate.tsx
+++ b/components/Editor/lib/data/proposalTemplate.tsx
@@ -308,5 +308,4 @@ const proposalTemplate: Template = {
],
};
-export type ProposalTemplate = typeof proposalTemplate;
export default proposalTemplate;
diff --git a/components/Editor/lib/utils/cssVar.ts b/components/Editor/lib/utils/cssVar.ts
index 02ce5eed8..0bd1d98a1 100644
--- a/components/Editor/lib/utils/cssVar.ts
+++ b/components/Editor/lib/utils/cssVar.ts
@@ -10,5 +10,3 @@ export const cssVar = (name: string, value?: string) => {
return getComputedStyle(document.body).getPropertyValue(currentName);
};
-
-export default cssVar;
diff --git a/components/Editor/lib/utils/getRenderContainer.ts b/components/Editor/lib/utils/getRenderContainer.ts
index 6fab7613e..05e19a6cf 100644
--- a/components/Editor/lib/utils/getRenderContainer.ts
+++ b/components/Editor/lib/utils/getRenderContainer.ts
@@ -39,5 +39,3 @@ export const getRenderContainer = (editor: Editor, nodeType: string) => {
return container;
};
-
-export default getRenderContainer;
diff --git a/components/Editor/lib/utils/index.ts b/components/Editor/lib/utils/index.ts
index 1623ee7fa..2781b8712 100644
--- a/components/Editor/lib/utils/index.ts
+++ b/components/Editor/lib/utils/index.ts
@@ -5,8 +5,4 @@ export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
-export function randomElement(array: Array): T {
- return array[Math.floor(Math.random() * array.length)];
-}
-
export * from './cssVar';
diff --git a/components/Editor/lib/utils/isCustomNodeSelected.ts b/components/Editor/lib/utils/isCustomNodeSelected.ts
index 68876cf49..a1f696d4e 100644
--- a/components/Editor/lib/utils/isCustomNodeSelected.ts
+++ b/components/Editor/lib/utils/isCustomNodeSelected.ts
@@ -43,5 +43,3 @@ export const isCustomNodeSelected = (editor: Editor, node: HTMLElement) => {
return customNodes.some((type) => editor.isActive(type)) || isTableGripSelected(node);
};
-
-export default isCustomNodeSelected;
diff --git a/components/Editor/lib/utils/isTextSelected.ts b/components/Editor/lib/utils/isTextSelected.ts
index 265c51695..994700bbd 100644
--- a/components/Editor/lib/utils/isTextSelected.ts
+++ b/components/Editor/lib/utils/isTextSelected.ts
@@ -25,5 +25,3 @@ export const isTextSelected = ({ editor }: { editor: Editor }) => {
return true;
};
-
-export default isTextSelected;
diff --git a/components/Embed/index.ts b/components/Embed/index.ts
index 98b7e87ba..0044eca27 100644
--- a/components/Embed/index.ts
+++ b/components/Embed/index.ts
@@ -1,6 +1,3 @@
export { Embed } from './Embed';
export { EmbedCarousel } from './EmbedCarousel';
export { InlineRichLink } from './InlineRichLink';
-export { EmbedExpandedContent, XEmbedIframe, isEmbedExpandable } from './EmbedExpandedContent';
-export { useLinkPreview } from './hooks/useLinkPreview';
-export type { EmbedSize, PreviewData } from './types';
diff --git a/components/Feed/BaseFeedItem.tsx b/components/Feed/BaseFeedItem.tsx
index 67cfd3817..94c402d35 100644
--- a/components/Feed/BaseFeedItem.tsx
+++ b/components/Feed/BaseFeedItem.tsx
@@ -1,6 +1,6 @@
'use client';
-import { FC, ReactNode, useState } from 'react';
+import { FC, ReactNode } from 'react';
import {
FeedContentType,
FeedEntry,
@@ -11,11 +11,8 @@ import { FeedItemHeader } from '@/components/Feed/FeedItemHeader';
import { FeedItemActions } from '@/components/Feed/FeedItemActions';
import { CardWrapper } from './CardWrapper';
import { cn } from '@/utils/styles';
-import { stripHtml, truncateText } from '@/utils/stringUtils';
-import { TopicAndJournalBadge } from '@/components/ui/TopicAndJournalBadge';
+import { stripHtml } from '@/utils/stringUtils';
import { useNavigation } from '@/contexts/NavigationContext';
-import { Button } from '@/components/ui/Button';
-import { ChevronDown } from 'lucide-react';
import { BountyInfoSummary } from '@/components/Bounty/BountyInfoSummary';
import { useRouter } from 'next/navigation';
import Link from 'next/link';
@@ -95,44 +92,6 @@ export interface StatusSectionProps {
className?: string;
}
-// Subcomponents
-export const BadgeSection: FC = ({
- contentType,
- topics = [],
- className,
- onClick,
-}) => {
- return (
-
- {/* Content type badge would be rendered here */}
- {topics.map((topic) => (
-
{
- e.stopPropagation();
- onClick?.(e);
- }}
- onKeyDown={(e) => {
- if (e.key === 'Enter' || e.key === ' ') {
- e.preventDefault();
- e.stopPropagation();
- onClick?.(e as any);
- }
- }}
- role={onClick ? 'button' : undefined}
- tabIndex={onClick ? 0 : undefined}
- >
-
-
- ))}
-
- );
-};
-
export const TitleSection: FC = ({ title, className, href, onClick }) => {
const titleStyles = cn(
'text-md md:!text-lg font-semibold text-gray-900 mb-1 hover:underline',
@@ -152,55 +111,13 @@ export const TitleSection: FC = ({ title, className, href, on
return content;
};
-export const ContentSection: FC = ({
- content,
- className,
- maxLength = 200,
-}) => {
- const [isExpanded, setIsExpanded] = useState(false);
- const isTextTruncated = content && content.length > maxLength;
-
- const handleToggleExpand = (e: React.MouseEvent) => {
- e.stopPropagation();
- setIsExpanded(!isExpanded);
- };
-
- // Default: render truncated plain text
- return (
-
-
{isExpanded ? content : truncateText(content, maxLength)}
- {isTextTruncated && (
-
- )}
-
- );
-};
-
// Re-export ImageSection for backwards compatibility
-export { ImageSection, type ImageSectionProps } from './ImageSection';
+export { ImageSection } from './ImageSection';
export const MetadataSection: FC = ({ children, className }) => {
return {children}
;
};
-export const CTASection: FC = ({ children, className }) => {
- return {children}
;
-};
-
// Primary action component interface
export interface PrimaryActionSectionProps {
children: ReactNode;
@@ -223,35 +140,6 @@ export const PrimaryActionSection: FC = ({ children,
);
};
-// Re-export FeedItemAbstractSection for backwards compatibility
-export {
- FeedItemAbstractSection,
- type FeedItemAbstractSectionProps,
-} from './FeedItemAbstractSection';
-
-export const StatusSection: FC = ({ status, statusText, className }) => {
- if (!status) return null;
-
- const statusConfig = {
- open: { color: 'bg-emerald-500', textColor: 'text-emerald-700', text: 'Open' },
- closed: { color: 'bg-gray-400', textColor: 'text-gray-500', text: 'Closed' },
- expired: { color: 'bg-red-500', textColor: 'text-red-700', text: 'Expired' },
- active: { color: 'bg-blue-500', textColor: 'text-blue-700', text: 'Active' },
- inactive: { color: 'bg-gray-400', textColor: 'text-gray-500', text: 'Inactive' },
- };
-
- const config = statusConfig[status] ?? statusConfig.inactive;
-
- return (
-
-
-
- {statusText ?? config.text}
-
-
- );
-};
-
// Main BaseFeedItem component
export const BaseFeedItem: FC = ({
entry,
diff --git a/components/Feed/skeletons/shared.tsx b/components/Feed/skeletons/shared.tsx
index 400b33406..786e97589 100644
--- a/components/Feed/skeletons/shared.tsx
+++ b/components/Feed/skeletons/shared.tsx
@@ -1,8 +1,6 @@
import { FC, ReactNode } from 'react';
import { cn } from '@/utils/styles';
-export const skeletonPulse = 'bg-gray-200 animate-pulse rounded';
-
export const SkeletonCardShell: FC<{ children: ReactNode; className?: string }> = ({
children,
className,
diff --git a/components/Funding/dashboard/hooks/useMyFundingDocuments.ts b/components/Funding/dashboard/hooks/useMyFundingDocuments.ts
index a0a98a4e1..3fa940301 100644
--- a/components/Funding/dashboard/hooks/useMyFundingDocuments.ts
+++ b/components/Funding/dashboard/hooks/useMyFundingDocuments.ts
@@ -2,12 +2,11 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useFeed } from '@/hooks/useFeed';
-import { FUNDING_KIND_LABEL, type FundingKind } from '@/components/Funding/fundingKind';
+import type { FundingKind } from '@/components/Funding/fundingKind';
import type { FeedEntry, FeedGrantContent, FeedPostContent } from '@/types/feed';
import { formatTimeAgo } from '@/utils/date';
import { buildWorkUrl } from '@/utils/url';
-export { FUNDING_KIND_LABEL };
export type { FundingKind };
/** An amount in both currencies, shown in whichever the user prefers. */
diff --git a/components/Funding/fundingKind.ts b/components/Funding/fundingKind.ts
index 1fd2b2ceb..09bdf14c5 100644
--- a/components/Funding/fundingKind.ts
+++ b/components/Funding/fundingKind.ts
@@ -3,11 +3,6 @@ import { faBullhorn, faFileSignature } from '@fortawesome/pro-light-svg-icons';
export type FundingKind = 'rfp' | 'proposal';
-export const FUNDING_KIND_LABEL: Record = {
- rfp: 'RFP',
- proposal: 'Proposal',
-};
-
/** Shared document icons for publishing, thumbnails, and funding dashboards. */
export const FUNDING_KIND_ICON: Record = {
rfp: faBullhorn,
diff --git a/components/Globe/AnimatedGlobe/landDots.ts b/components/Globe/AnimatedGlobe/landDots.ts
index fe8ba988f..5121e96e0 100644
--- a/components/Globe/AnimatedGlobe/landDots.ts
+++ b/components/Globe/AnimatedGlobe/landDots.ts
@@ -1,6 +1,5 @@
// AUTO-GENERATED by tools land-dot generator. Do not edit by hand.
// 5776 land sample points (unit vectors) packed as signed int8 [x,y,z]
// triplets, base64-encoded. Decoded at runtime in AnimatedGlobe.
-export const LAND_DOTS_COUNT = 5776;
export const LAND_DOTS_B64 =
'94IM+YIP8IID9IIM8IIH9oIP7oIB8YIL+YIS7YMGFIP+84MP7IP/7oMK9oMS64MD8IMOBoMV84MS6YMA7YMN94MV74MR6oML84MV54MD7IQQ54T66IQIBoQZ8IQU6YQO54T29IQY5YQF7IQT5oQL6ITyG4T68IQX5IQC6YQR9YQb7IQW44T+5oUOHIX38YUa6YUU4oX6HoX77YUZ4YUA5oURHYX084UdG4UQIIX/6YUXIIX47oUb34UD5oUU9YUfIYb86oYaIIb18IYeHYYTI4YA5oYX4obuIob57IYdI4YF44YU8oYhJIb954Ya3Ib8HYbqI4b17YYfHoYV24YEJYYC44YXIIfu4YfrJYf66YcdI4fy74ciF4fhJof/5Icb2of6IIfrJYcMJof36ocg2YcDJ4cE4IcX2of1I4fvFYfeJ4f85oce2If9H4fnJ4cK24jwJojz7Ygj2IgGGYjhKIgB4YgbI4jrJogP3YjrKIj46IghHojkKYgHFIgk2YjyJojw74gm2IgKF4jeKoj+44geIojoEIjZ2ojtKYj16ogk1ogEHIjgKogD34ga14j1Jojs74jZ14gNFYjbK4j65Ygh1Yn+IYnkKokJE4kn2InwKYnx7Ikn1YkIGondLIkA4IkeBInUJYno7InZKYkPEonYK4n254kkH4nh44neLIkGConVFokn1onzKInt8YnWKIkV1YkMGIna3InlLYn84okhJInl6InaLIkMEInWEYkqK4ny6Ykn04kGHYnd4IngLYkC3YkdBonTGokl04n2KIrp7YrW1YoQFYrX2YrnLYr45IokIorh5IrbLYoIDIrTFYopK4rv8orUG4ra3YriL4r+34ohAorR0or6J4rl6YrXLYoOEorVEIos1orqLor05oonJYod0YoEIIre4IrdL4oF2oocCYrRGYoo0orzKorr7orUK4oV0ooOGIrX2YrkL4r64Yok/4rQIYoi0Ir9JYri5YrYL4oLD4rSFIosLYrwKIsaHova3YvfMIsB3IsgBYvQHYsn0Iv3KYvn6ovVLYsR04sSFYvUDosv1ovnMIv244soJYsgz4sBI4ve4YvaMIsHC4vQGIsr0YvwLYvs8IvRK4sY0IsMG4vX2YvhMYv93oskAYvPz4v7KIvj5ovW04sWEovSEosu04vqMIvyKIsdzosFIYva3YvcMosD2YsfCIvO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kccYD8dwccf7ScdXkMfx58dvbMciJsdrbsfj/8dxcccKPMdgk8fiZcfMZ8cxGMdvccfyUMdR8Mdxb8cZL8dnl8fUa8fakMcTCcdxcscBRMdbkMfrasgoIchtb8jpVshK+shyccgQOMhjlMjcaMjRZMg2Eshwcsj4TMhV68hwbsgfKshqbcjfA8hycsgHQMhfkcjlZMjJacguG8hvccjuU8hP9MhycMgWM8hmasjWYsg7DMlycsn9SMlZj8nv5clvbMklJclsb8nlWclI/clycskNO8liksngZ8nOZskzFslwcsn0T8lT7slxb8kcLslpbcncX8lAB8lyc8kDkMnpaskqH8luccnrVslM98lyccoTNsplasrTZMo4EMpyc8r6S8pX6MpwbsoiKMpsb8rhAcpzc8oJPsphkcrjZsrKGspwcsrwUspR8cpycMoYMcpobMrYCspzc8oARspbj8rsbMonI8tucMvnWMtK+8tzcssPOstkksvdacvPFMtyc8v2TstV7Mtyb8seLMtrbsveXstDBMtzc8sGQstfj8vmHctwcsvtVctP9ctzcssVNctna8vVj8sYDstzdMz8ScxZjczw5sxxbswkJsxtcMzj/8x0c8wMPcxikczhZ8zMF8xxc8zzUcxT78xzccwbL8xqbszaYcxACMx0dMwCjszqY8zDbMwqIcxvcszpV8xM+cx0c8wROM1mas3REs1zdM34Tc1X6c1ycM0hKs1scM3gXs1FAs10dM0IQM1hj83kG81xc83vVM1R8810cs0XM81pbc3WY809DM10dM3+jc3t481xbs0mJM1vcc7lWs5K/M51dM4OO85kac7OFc5zdM71UM5V7c5zcc4dLs5rb87cYM5CBs51dc4ERM5fjs7nZc7FH85xc87rV85P9s50c84UNs5nks7YbM7TEM50dc77S89Z589ycM8jKM9ucc/iXc9HAM91dc8KP89jj8/iGc9ydM/xU89T8M90cs8aMc9qbs/YY88/jM8UCs91dc8Bjc/r4c9xbs8pI89wc8/nWc9M+s91dM8QOs9mE9B0ddD3TtBX6tBzcdAgLNBtcNDeX9BFBNB1ddAHQtBhjtDlHdBydNDtVtBR9NB1dNAWNdBpbdDVZdA9jdAYDdB1jNDv5NBycNAlJtBvctDkXNFJ/tF2ddENPdFlF9F0ddHzUtFV7tF1c9Ec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KyBznyBLQyBniyAmGyB4sSBfXiCxliA+NCBvSyCepiBTSyBhjyAvJSB1XiFPVyGpmyFGPSFqiSEgrSFaYiG2kyE4LiFyoiFORiFljSEpHyF3WiFUWyGumCFBOCFtRyGcqCFWTiFfkCIzKSJ0niJJQCJoiyIjsCJdXyKzlSI7MiJwTCKgpCJRSSJijiItIyJ1XCJQWCKrmiJEOyJrqyNYYyO4kiM2LCNyoSNMQyNmjCMnHCN3syNfWCNVXCOwlyM/NSNuSSOepyNUTCNgkCMwJiN0VSOpnSRHPiRpryRbYCS1lCQ5MCRwoyRPRiRjjiQqICR1WiRSWSStmiRCOSRsRiScqiRWZCS6kiUzKiVyUiWmnyVKQSVnGiV3siVdViVWXSWylyU8MyVuSiWgpiVSSSVhkCUuJCV0VyWrnCVFPCVqrSZZYSa3lCY3LSZxoiZNRCZkjiYoHiZ2WCZTWyawmSY/NiZsRyaeqSZUZCa8kSYxJyZzVCaonidIPydnsCdbXie0lic6MSdvTCeipSdPRydijycrISd0WidQWCetmydCOSdqRCecrCdXBCeHYie5kyc0KydxUCimoShLQihlGyh1VihUXCiymCg9NChtSSigqChSZSi/kSgvJShzVSiqnihFPShoryhZXym3lSk4LilvTSmkpClNRSljjykpHyl0WClRWSmvmilANylrRSmeqylUYym8kykyKClxUimooClIQClmsipbVCpWXSq0lyo7MSptSiqipypQZirBkSosIipzViqtnSpDOippQiqcripXYCq5lSo1LCpvTyumoytLQytjHCt0VitTWiuxmis+NStrRyugqStSZCu+kiswJitxUyuqnytGPStmsStZXiy2lyw4LyxuTCykpixOZyzDkCwqICxzWSxQVyyvnCxBOCxpRCyerCxVYSy7lCwzKSxwUCyooixJQCxkVC1UWy2zmS08Mi1sSC2iqC1QZC3Aki0tIy1xVC2sni1EOy1nQC2cry1XXy24li02LS1uTS6mpS5LQy5iZy7GHi5zVy5RWC6xmy4/NS5qRS6gqy5TYi69lC4wJy5wUS6qoS5HPi5lai7LPS6bsi5ZUi5VXC62mS85MC9sSi+kpy9OZS/Dki8rIS9xVS+uni9BHC+NOS9oQi+eri9VXy+7li80Ki9uTi+opC9JQS9iaC/IVDBSWTCzmzA8MzBqRzCiqjBQYzDAlDAuJDBwUjCsoDBEPDBlajDOPjCcsTBXXTC4mDA3LTBsSzCmpjFMRDFgZTHFkjEoHzFxVzFPVjGxnTE/NjFoQzGgrTFTYDG9ljExKDFuTzGqozFHPjFjaDHKOzGbUjFTWjG1mjE6MTJqSDKkqTJOYzLClDIsIjJwUzKuoDJCOTJmajLQQDKeXjK6mDI0KzJsTDKopjJKQTJhZjLHVDNQVzOznTM9NDNoRTOirDNRYTO/ljMvJTNuUTOsojNFPDNkaDPNPTOdWzO4mjM3LjNrSTOmqDNMZDTElDQpIDRwVDSwnzRANzRmQTSgXjS9lzQyKTRsTTSqpTRHPzRhZjTKOTSbUjRRWDS1nDQ6MTRpRjWkqzVOYTXClTUsIzVuUjWuoTVCOjVkaTXPPjWfXDW6mjU1LDVrSjWopzVKZDXHlDUnNjWaHTVvVTaznjY9NDZmQzaiXza/lzYwJjZsTzaspDZFPTZiZzbMOzadWTa3nDY4LzZpRzamqjZMYjbElTcqITduUzewoTdANzdkPzehXDe8mTczKTdrTDeqpzdHZDfJNzecVje1njc7MjdnRDikXzjBlzgtJDhsUDiuozhDOjhiZzjPPDifWji6mzg2LThpSDioqThKYjjGlTgoNDibHjhuUzizoDk+NTllQTmjXTm/mTkwJzlrTTmspjlFPTlgZTnMOTmeVzm3njk4MDlnRTmmYDnElzkrITpsUTqwozpAODpiZzrRPjqhWjq8mzozKjppSjqqqTpIYjrJlTolNTqdVDq1oDo7MzplQjqlXTvBmTsuJTtrTjuupTtDOztgZTvOOjugWDu6nTs2LTtnRjuoqztKYDvGlzsoHztsUTuzojs+NjxjPzyjWzy+mzwxKDxpSzysqDxFYzzLNzyeVTy3oDw5MDxlQzynXjzDmTwrIjxqTj2xpT1BOD1gZT3QPD2iWD28nT00Kz1nRz2rqz1IYD3Ilz0mMz2dUj21oj08Mz1jQD2lWz7Bmz4uJT5pSz6vqD5DYz7NOD6gVj66nz43Lj5lRD6pXj7GmT4pTz6zpT4+Nj5hPT+kWT++nT8xKD9nSD+tqj9FYT/LmD8kNT+fUz+3oj85MT9jQT+nXD/Dmz8sIz9oTECxp0BBY0DQOkCiVkC8n0A0K0BlRUCrXkDImUAnUEC1pEA8NEBhPkCmWUDBnUEv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';
diff --git a/components/Moderators/utils/auditUtils.ts b/components/Moderators/utils/auditUtils.ts
index 1141a2b05..1fddfd590 100644
--- a/components/Moderators/utils/auditUtils.ts
+++ b/components/Moderators/utils/auditUtils.ts
@@ -79,101 +79,3 @@ export const getAuditContentUrl = (entry: FlaggedContent): string | null => {
return `/post/${document.id}/${document.slug ?? item?.slug ?? ''}`;
}
};
-
-/**
- * Get content preview text for truncation detection
- */
-export const getAuditContentPreview = (entry: FlaggedContent): string => {
- if (!entry.item) {
- return 'Content not available';
- }
-
- const commentContent = entry.item.comment_content_json;
-
- if (!commentContent) {
- return 'No content available';
- }
-
- // Handle string format (JSON string)
- if (typeof commentContent === 'string') {
- try {
- const parsed = JSON.parse(commentContent);
- return extractTextFromContentJson(parsed);
- } catch {
- return commentContent; // Fallback to raw string
- }
- }
-
- // Handle object format
- if (typeof commentContent === 'object') {
- return extractTextFromContentJson(commentContent);
- }
-
- return 'Content format not supported';
-};
-
-/**
- * Extract plain text from various content JSON formats
- */
-const extractTextFromContentJson = (contentJson: any): string => {
- if (!contentJson) return '';
-
- // Handle Quill Delta format: {"ops": [{"insert": "text"}]}
- if (contentJson.ops && Array.isArray(contentJson.ops)) {
- return contentJson.ops
- .map((op: any) => {
- if (typeof op.insert === 'string') {
- return op.insert;
- }
- // Handle mentions: {"insert": {"mention": {"id": 123, "name": "User"}}}
- if (op.insert && typeof op.insert === 'object' && op.insert.mention) {
- return `@${op.insert.mention.name ?? 'User'}`;
- }
- return '';
- })
- .join('')
- .trim();
- }
-
- // Handle TipTap format: {"type": "doc", "content": [...]}
- if (contentJson.type === 'doc' && contentJson.content) {
- return extractTextFromTipTapArray(contentJson.content);
- }
-
- // Handle direct content array (sometimes TipTap comes without wrapper)
- if (Array.isArray(contentJson.content)) {
- return extractTextFromTipTapArray(contentJson.content);
- }
-
- // Fallback: try to stringify and extract meaningful text
- const str = JSON.stringify(contentJson);
- const textMatch = str.match(/"text":"([^"]+)"/g);
- if (textMatch) {
- return textMatch.map((match) => match.replace(/"text":"([^"]+)"/, '$1')).join(' ');
- }
-
- return 'Content format not recognized';
-};
-
-/**
- * Extract text from TipTap content array
- */
-const extractTextFromTipTapArray = (content: any[]): string => {
- if (!Array.isArray(content)) return '';
-
- return content
- .map((node: any) => {
- if (node.type === 'text') {
- return node.text ?? '';
- }
- if (node.content && Array.isArray(node.content)) {
- return extractTextFromTipTapArray(node.content);
- }
- if (node.type === 'mention' && node.attrs?.label) {
- return `@${node.attrs.label}`;
- }
- return '';
- })
- .join('')
- .trim();
-};
diff --git a/components/Notebook/PublishingForm/index.tsx b/components/Notebook/PublishingForm/index.tsx
index 122d03af7..74a9bddbe 100644
--- a/components/Notebook/PublishingForm/index.tsx
+++ b/components/Notebook/PublishingForm/index.tsx
@@ -26,7 +26,6 @@ import { usePublishingController } from './PublishingFormProvider';
import type { PublishingFormData } from './schema';
export { PublishingFormProvider, usePublishingController } from './PublishingFormProvider';
-export { PublishButton } from './PublishButton';
export { usePublishingCompletion } from './completion';
const FEATURE_FLAG_RESEARCH_COIN = false;
diff --git a/components/tooltips/HotScoreTooltip.tsx b/components/tooltips/HotScoreTooltip.tsx
index bf1fed36c..62765d94f 100644
--- a/components/tooltips/HotScoreTooltip.tsx
+++ b/components/tooltips/HotScoreTooltip.tsx
@@ -102,6 +102,3 @@ export function PopularityScoreTooltip({ score, breakdown }: PopularityScoreTool
);
}
-
-/** @deprecated Use PopularityScoreTooltip instead */
-export const HotScoreTooltip = PopularityScoreTooltip;
diff --git a/components/ui/CollapsibleSection.tsx b/components/ui/CollapsibleSection.tsx
index dd56c112a..9d769dc48 100644
--- a/components/ui/CollapsibleSection.tsx
+++ b/components/ui/CollapsibleSection.tsx
@@ -1,7 +1,7 @@
'use client';
import React from 'react';
-import { ChevronUp, ChevronDown, ChevronRight } from 'lucide-react';
+import { ChevronUp, ChevronDown } from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
interface CollapsibleSectionProps {
@@ -83,64 +83,3 @@ export function CollapsibleSection({
);
}
-
-interface CollapsibleItemProps {
- title: string;
- children: React.ReactNode;
- isOpen: boolean;
- onToggle: () => void;
- icon?: React.ReactNode;
-}
-
-export function CollapsibleItem({
- title,
- icon = ,
- isOpen = false,
- children,
-}: CollapsibleItemProps) {
- return (
-
-
-
{icon}
-
-
{title}
- {isOpen &&
{children}
}
-
-
-
- );
-}
-
-// Simple wrapper that manages its own state
-interface SimpleCollapsibleSectionProps {
- title: string;
- children: React.ReactNode;
- className?: string;
- defaultExpanded?: boolean;
-}
-
-export function SimpleCollapsibleSection({
- title,
- children,
- className = '',
- defaultExpanded = true,
-}: SimpleCollapsibleSectionProps) {
- const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
-
- return (
- }
- isExpanded={isExpanded}
- onToggle={() => setIsExpanded(!isExpanded)}
- className={className}
- >
- {children}
-
- );
-}
diff --git a/components/ui/ContributorsButton.tsx b/components/ui/ContributorsButton.tsx
index a50fb39ee..b010d9026 100644
--- a/components/ui/ContributorsButton.tsx
+++ b/components/ui/ContributorsButton.tsx
@@ -13,115 +13,6 @@ type FlexibleProfile = {
[key: string]: any; // Allow any additional properties
};
-interface LabelBadgeProps {
- count: number;
- label: string;
- size?: number | 'xxs' | 'xs' | 'sm' | 'md' | 'lg';
- removeBadgeSpacing?: boolean;
-}
-
-// Extract the label badge as a separate component
-export function LabelBadge({
- count,
- label,
- size = 'xs',
- removeBadgeSpacing = false,
-}: LabelBadgeProps) {
- // Use singular form if there's only one
- const displayLabel = count === 1 ? label.replace(/s$/, '') : label;
-
- // Size-based styles
- const getFontSize = () => {
- if (typeof size === 'number') {
- return `text-[${Math.max(size * 0.6, 12)}px]`;
- }
-
- switch (size) {
- case 'lg':
- return 'text-base font-medium';
- case 'md':
- return 'text-sm font-medium';
- case 'sm':
- return 'text-xs font-medium';
- case 'xxs':
- case 'xs':
- default:
- return 'text-xs';
- }
- };
-
- const getPadding = () => {
- if (typeof size === 'number') {
- const paddingX = Math.max(Math.floor(size * 0.25), 3);
- const paddingY = Math.max(Math.floor(size * 0.1), 1);
- return `px-${paddingX} py-${paddingY}`;
- }
-
- switch (size) {
- case 'lg':
- return 'px-5 py-1.5';
- case 'md':
- return 'px-4 py-1';
- case 'sm':
- return 'px-3 py-0.5';
- case 'xxs':
- case 'xs':
- default:
- return 'px-3 py-0.5';
- }
- };
-
- const getMargin = () => {
- if (typeof size === 'number') {
- return `-ml-[${Math.max(Math.floor(size * 0.3), 11)}px]`;
- }
-
- switch (size) {
- case 'lg':
- return '-ml-[18px]';
- case 'md':
- return '-ml-[16px]';
- case 'sm':
- return '-ml-[14px]';
- case 'xxs':
- case 'xs':
- default:
- return '-ml-[11px]';
- }
- };
-
- // Get ring size based on badge size
- const getRingSize = () => {
- if (typeof size === 'number') {
- return size >= 32 ? 'ring-[3px]' : 'ring-2';
- }
-
- switch (size) {
- case 'lg':
- return 'ring-[3px]';
- case 'md':
- return 'ring-[2.5px]';
- default:
- return 'ring-2';
- }
- };
-
- return (
-
-
- {count} {displayLabel}
-
-
- );
-}
-
interface ContributorsButtonProps {
contributors: Array<{
profile: FlexibleProfile;
diff --git a/components/ui/LoadErrorState.tsx b/components/ui/LoadErrorState.tsx
index ac238699d..7f5b3338f 100644
--- a/components/ui/LoadErrorState.tsx
+++ b/components/ui/LoadErrorState.tsx
@@ -52,5 +52,3 @@ export const LoadErrorState = ({
);
};
-
-export default LoadErrorState;
diff --git a/components/ui/Popover.tsx b/components/ui/Popover.tsx
index e92b8c6bf..d06064924 100644
--- a/components/ui/Popover.tsx
+++ b/components/ui/Popover.tsx
@@ -15,8 +15,6 @@ import { cn } from '@/utils/styles';
*/
export const Popover = RadixPopover.Root;
export const PopoverTrigger = RadixPopover.Trigger;
-export const PopoverAnchor = RadixPopover.Anchor;
-export const PopoverClose = RadixPopover.Close;
export function PopoverContent({
className,
diff --git a/components/ui/SearchEmpty.tsx b/components/ui/SearchEmpty.tsx
index 24b437a93..3f32dac00 100644
--- a/components/ui/SearchEmpty.tsx
+++ b/components/ui/SearchEmpty.tsx
@@ -34,5 +34,3 @@ export const SearchEmpty = ({
);
};
-
-export default SearchEmpty;
diff --git a/components/ui/SwipeableDrawer.tsx b/components/ui/SwipeableDrawer.tsx
index 74167f497..2a9acc69c 100644
--- a/components/ui/SwipeableDrawer.tsx
+++ b/components/ui/SwipeableDrawer.tsx
@@ -185,5 +185,3 @@ export const SwipeableDrawer: React.FC = ({
// Use createPortal to mount drawer to body
return createPortal(drawerContent, document.body);
};
-
-export default SwipeableDrawer;
diff --git a/components/ui/Table/index.ts b/components/ui/Table/index.ts
index 83dc9176a..44455b47e 100644
--- a/components/ui/Table/index.ts
+++ b/components/ui/Table/index.ts
@@ -1,9 +1,3 @@
export { Table } from './Table';
-export { TableHead } from './TableHead';
-export { TableBody } from './TableBody';
-export { TableHeader, type SortDirection } from './TableHeader';
-export { TableRow } from './TableRow';
-export { TableCell } from './TableCell';
export { TableContainer, type SortableColumn } from './TableContainer';
-export { MobileTableCard, type MobileTableCardProps } from './MobileTableCard';
-export { TableSkeleton, type TableSkeletonProps } from './TableSkeleton';
+export { MobileTableCard } from './MobileTableCard';
diff --git a/components/ui/TopicAndJournalBadge.tsx b/components/ui/TopicAndJournalBadge.tsx
deleted file mode 100644
index 1ab226fb4..000000000
--- a/components/ui/TopicAndJournalBadge.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import Link from 'next/link';
-import { Badge } from './Badge';
-
-export type BadgeType = 'topic' | 'journal';
-export type BadgeSize = 'sm' | 'md' | 'lg';
-export type BadgeVariant = 'primary' | 'secondary';
-
-export interface TopicAndJournalBadgeProps {
- name: string;
- slug: string;
- className?: string;
- disableLink?: boolean;
- size?: BadgeSize;
-}
-
-/**
- * A reusable badge component for topics and journals
- * Displays an avatar if imageUrl is provided
- * Links to the appropriate page based on type and slug
- * Can optionally disable the link functionality with disableLink prop
- * Supports different sizes: sm, md (default), lg
- * Supports different variants: primary (default), secondary
- */
-export const TopicAndJournalBadge = ({
- name,
- slug,
- className = '',
- disableLink = false,
- size = 'md',
-}: TopicAndJournalBadgeProps) => {
- const href = `/topic/${slug}`;
-
- const sizePadding = {
- sm: 'px-1.5 py-0.5',
- md: 'px-2 py-1',
- lg: 'px-2 py-1',
- };
-
- const badge = (
-
- {name}
-
- );
-
- return disableLink ? (
- badge
- ) : (
-
- {badge}
-
- );
-};
diff --git a/components/work/WorkHeader/index.ts b/components/work/WorkHeader/index.ts
index 960d346ff..4e1addc70 100644
--- a/components/work/WorkHeader/index.ts
+++ b/components/work/WorkHeader/index.ts
@@ -1,4 +1,4 @@
export { WorkHeader } from './WorkHeader';
export { WorkHeaderGrant } from './WorkHeaderGrant';
export { WorkHeaderProposal } from './WorkHeaderProposal';
-export { WorkTabProvider, useWorkTab } from './WorkTabContext';
+export { WorkTabProvider } from './WorkTabContext';
diff --git a/contexts/AuthModalContext.tsx b/contexts/AuthModalContext.tsx
index 6cd0720dc..b826fd3e9 100644
--- a/contexts/AuthModalContext.tsx
+++ b/contexts/AuthModalContext.tsx
@@ -3,7 +3,6 @@
import { createContext, useContext, useState, useCallback } from 'react';
import AuthModal from '@/components/modals/Auth/AuthModal';
import { useSession } from 'next-auth/react';
-import { ReactNode } from 'react';
import AnalyticsService, { LogEvent } from '@/services/analytics.service';
interface AuthModalContextType {
@@ -73,18 +72,3 @@ export function useAuthenticatedAction() {
return { executeAuthenticatedAction };
}
-
-interface AuthenticatedContentProps {
- children: ReactNode;
- fallback?: ReactNode;
-}
-
-export const AuthenticatedContent = ({ children, fallback = null }: AuthenticatedContentProps) => {
- const { status } = useSession();
-
- if (status !== 'authenticated') {
- return fallback;
- }
-
- return <>{children}>;
-};
diff --git a/hooks/useBounties.ts b/hooks/useBounties.ts
index f91c46cab..96f66d96e 100644
--- a/hooks/useBounties.ts
+++ b/hooks/useBounties.ts
@@ -4,7 +4,13 @@ import { FeedEntry } from '@/types/feed';
import { BountyService } from '@/services/bounty.service';
import { useNavigation, getFeedKey } from '@/contexts/NavigationContext';
import { useClickContext } from '@/contexts/ClickContext';
-import { Hub } from '@/components/Earn/BountyHubSelector';
+
+interface Hub {
+ id: string | number;
+ name: string;
+ description?: string;
+ color?: string;
+}
export const useBounties = () => {
const pathname = usePathname();
diff --git a/hooks/useNote.ts b/hooks/useNote.ts
index 9da2a5b0d..4a1f5ded3 100644
--- a/hooks/useNote.ts
+++ b/hooks/useNote.ts
@@ -1,12 +1,6 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { NoteService, NoteError, type NoteInvitePreview } from '@/services/note.service';
-import {
- isChangelogNote,
- type NoteWithContent,
- type Note,
- type NoteAccess,
- type NoteContent,
-} from '@/types/note';
+import { isChangelogNote, type Note, type NoteAccess, type NoteContent } from '@/types/note';
import { ID } from '@/types/root';
import { Editor } from '@tiptap/react';
import { getHTMLFromFragment, getText, getTextSerializersFromSchema } from '@tiptap/core';
@@ -84,73 +78,6 @@ export function useAcceptNoteInvite(): UseAcceptNoteInviteReturn {
return [{ isLoading, error }, acceptInvite];
}
-interface UseNoteState {
- note: NoteWithContent | null;
- isLoading: boolean;
- error: Error | null;
-}
-
-type FetchNoteFn = () => Promise;
-type UseNoteReturn = [UseNoteState, FetchNoteFn];
-
-/**
- * Custom hook to fetch and manage note data.
- * Accepts an optional initialNote to prevent unnecessary fetching when data is already available.
- *
- * TODO: Future Collaboration Implementation
- * This hook will be updated to use TipTap's collaboration features:
- * 1. Initialize Y.js document
- * 2. Configure TipTap collaboration extension
- * 3. Set up WebSocket connection via TiptapCollabProvider
- * 4. Handle real-time updates and presence
- *
- * Example future implementation:
- * ```typescript
- * const doc = new Y.Doc();
- * const editor = useEditor({
- * extensions: [
- * StarterKit.configure({ history: false }), // Disable for collaboration
- * Collaboration.configure({ document: doc }),
- * // Add cursor presence, etc.
- * ],
- * });
- * ```
- *
- * @param noteId - The ID of the note to fetch
- * @returns UseNoteReturn object containing note data and loading state
- */
-export function useNote(
- noteId: string,
- options: UseNoteOptions = { sendImmediately: true }
-): UseNoteReturn {
- const [note, setNote] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- const fetch = useCallback(async () => {
- try {
- setIsLoading(true);
- setError(null);
-
- const noteData = await NoteService.getNote(noteId);
- setNote(noteData);
- } catch (err) {
- setError(err instanceof Error ? err : new Error('Failed to fetch note'));
- setNote(null);
- } finally {
- setIsLoading(false);
- }
- }, [noteId]);
-
- useEffect(() => {
- if (options.sendImmediately !== false) {
- fetch();
- }
- }, [fetch, options.sendImmediately]);
-
- return [{ note, isLoading, error }, fetch];
-}
-
interface CreateNoteInput {
title: string;
grouping: NoteAccess;
@@ -474,80 +401,6 @@ export const useUpdateNote = (noteId: ID, options: UpdateNoteOptions = {}): UseU
return [{ isLoading, error }, updateNote, saveNoteNow];
};
-interface UseMakeNotePrivateState {
- isLoading: boolean;
- error: Error | null;
-}
-
-type MakeNotePrivateFn = (noteId: ID) => Promise;
-type UseMakeNotePrivateReturn = [UseMakeNotePrivateState, MakeNotePrivateFn];
-
-export const useMakeNotePrivate = (): UseMakeNotePrivateReturn => {
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- const makeNotePrivate = async (noteId: ID) => {
- setIsLoading(true);
- setError(null);
-
- try {
- const response = await NoteService.makePrivate(noteId);
- return response;
- } catch (err) {
- const errorMsg = err instanceof NoteError ? err.message : 'Failed to make note private';
- const error = new Error(errorMsg);
- setError(error);
- throw error;
- } finally {
- setIsLoading(false);
- }
- };
-
- return [{ isLoading, error }, makeNotePrivate];
-};
-
-interface UpdateNotePermissionsInput {
- noteId: ID;
- organizationId: ID;
- accessType?: 'ADMIN';
-}
-
-interface UseUpdateNotePermissionsState {
- isLoading: boolean;
- error: Error | null;
-}
-
-type UpdateNotePermissionsFn = (params: UpdateNotePermissionsInput) => Promise;
-type UseUpdateNotePermissionsReturn = [UseUpdateNotePermissionsState, UpdateNotePermissionsFn];
-
-export const useUpdateNotePermissions = (): UseUpdateNotePermissionsReturn => {
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- const updatePermissions = async (params: UpdateNotePermissionsInput) => {
- setIsLoading(true);
- setError(null);
-
- try {
- const response = await NoteService.updateNotePermissions(
- params.noteId,
- params.organizationId,
- params.accessType
- );
- return response;
- } catch (err) {
- const errorMsg = err instanceof NoteError ? err.message : 'Failed to update note permissions';
- const error = new Error(errorMsg);
- setError(error);
- throw error;
- } finally {
- setIsLoading(false);
- }
- };
-
- return [{ isLoading, error }, updatePermissions];
-};
-
interface UseDuplicateNoteState {
isLoading: boolean;
error: Error | null;
diff --git a/hooks/useOrganization.ts b/hooks/useOrganization.ts
index 356018b47..4da0bfa1b 100644
--- a/hooks/useOrganization.ts
+++ b/hooks/useOrganization.ts
@@ -4,45 +4,6 @@ import { useState, useCallback } from 'react';
import { OrganizationService, OrganizationError } from '@/services/organization.service';
import { Organization } from '@/types/organization';
-interface UseUpdateOrgDetailsState {
- data: Organization | null;
- isLoading: boolean;
- error: string | null;
-}
-
-type UpdateOrgDetailsFn = (orgId: string, name: string) => Promise;
-type UseUpdateOrgDetailsReturn = [UseUpdateOrgDetailsState, UpdateOrgDetailsFn];
-
-/**
- * Hook for updating organization details
- * @returns A tuple containing the state and update function
- */
-export const useUpdateOrgDetails = (): UseUpdateOrgDetailsReturn => {
- const [data, setData] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- const updateOrgDetails = async (orgId: string, name: string): Promise => {
- setIsLoading(true);
- setError(null);
-
- try {
- const response = await OrganizationService.updateOrgDetails(orgId, name);
- setData(response);
- return response;
- } catch (err) {
- const errorMsg =
- err instanceof OrganizationError ? err.message : 'Failed to update organization details';
- setError(errorMsg);
- throw new Error(errorMsg);
- } finally {
- setIsLoading(false);
- }
- };
-
- return [{ data, isLoading, error }, updateOrgDetails];
-};
-
interface UseInviteUserToOrgState {
isLoading: boolean;
error: string | null;
@@ -289,50 +250,3 @@ export const useFetchOrgByInviteToken = () => {
return [{ data, isLoading, error }, fetchOrgByInviteToken] as const;
};
-
-interface UseUpdateOrgCoverImageState {
- data: Organization | null;
- isLoading: boolean;
- error: string | null;
-}
-
-type UpdateOrgCoverImageFn = (
- orgId: string | number,
- coverImage: File | Blob
-) => Promise;
-type UseUpdateOrgCoverImageReturn = [UseUpdateOrgCoverImageState, UpdateOrgCoverImageFn];
-
-/**
- * Hook for updating an organization's cover image
- * @returns A tuple containing the state and update function
- */
-export const useUpdateOrgCoverImage = (): UseUpdateOrgCoverImageReturn => {
- const [data, setData] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [error, setError] = useState(null);
-
- const updateOrgCoverImage = async (
- orgId: string | number,
- coverImage: File | Blob
- ): Promise => {
- setIsLoading(true);
- setError(null);
-
- try {
- const response = await OrganizationService.updateOrgCoverImage(orgId, coverImage);
- setData(response);
- return response;
- } catch (err) {
- const errorMsg =
- err instanceof OrganizationError
- ? err.message
- : 'Failed to update organization cover image';
- setError(errorMsg);
- throw new Error(errorMsg);
- } finally {
- setIsLoading(false);
- }
- };
-
- return [{ data, isLoading, error }, updateOrgCoverImage];
-};
diff --git a/hooks/usePinchZoom.ts b/hooks/usePinchZoom.ts
index a169188dc..4f7a3eab3 100644
--- a/hooks/usePinchZoom.ts
+++ b/hooks/usePinchZoom.ts
@@ -380,10 +380,3 @@ export function usePinchZoom({
transformOrigin,
};
}
-
-/**
- * Utility to detect if a touch event is a pinch gesture
- */
-export function isPinchGesture(e: TouchEvent): boolean {
- return e.touches.length === 2;
-}
diff --git a/lib/utils.ts b/lib/utils.ts
index a850cd0de..9e95658f6 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -7,8 +7,3 @@ import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
-
-export function toNumberOrNull(value: any): number | null {
- const num = Number(value);
- return Number.isFinite(num) ? num : null;
-}
diff --git a/package-lock.json b/package-lock.json
index f895678db..2e75b375d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -35,7 +35,6 @@
"@tippyjs/react": "^4.2.6",
"@tiptap-pro/extension-import": "3.9.2",
"@tiptap/core": "3.29.2",
- "@tiptap/extension-bullet-list": "3.29.2",
"@tiptap/extension-character-count": "3.29.2",
"@tiptap/extension-code-block": "3.29.2",
"@tiptap/extension-code-block-lowlight": "3.29.2",
@@ -55,8 +54,6 @@
"@tiptap/extension-link": "3.29.2",
"@tiptap/extension-mathematics": "3.29.2",
"@tiptap/extension-mention": "3.29.2",
- "@tiptap/extension-ordered-list": "3.29.2",
- "@tiptap/extension-paragraph": "3.29.2",
"@tiptap/extension-placeholder": "3.29.2",
"@tiptap/extension-subscript": "3.29.2",
"@tiptap/extension-superscript": "3.29.2",
diff --git a/package.json b/package.json
index 12e0c53d9..30a540fa9 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,6 @@
"@tippyjs/react": "^4.2.6",
"@tiptap-pro/extension-import": "3.9.2",
"@tiptap/core": "3.29.2",
- "@tiptap/extension-bullet-list": "3.29.2",
"@tiptap/extension-character-count": "3.29.2",
"@tiptap/extension-code-block": "3.29.2",
"@tiptap/extension-code-block-lowlight": "3.29.2",
@@ -64,8 +63,6 @@
"@tiptap/extension-link": "3.29.2",
"@tiptap/extension-mathematics": "3.29.2",
"@tiptap/extension-mention": "3.29.2",
- "@tiptap/extension-ordered-list": "3.29.2",
- "@tiptap/extension-paragraph": "3.29.2",
"@tiptap/extension-placeholder": "3.29.2",
"@tiptap/extension-subscript": "3.29.2",
"@tiptap/extension-superscript": "3.29.2",
diff --git a/services/author.service.ts b/services/author.service.ts
index 8b47f5dd8..3497412ba 100644
--- a/services/author.service.ts
+++ b/services/author.service.ts
@@ -43,11 +43,6 @@ export interface AuthorUpdatePayload {
google_scholar?: string | null;
}
-// Interface for the update payload parameters
-export interface AuthorUpdateParams extends AuthorUpdatePayload {
- profileImageDataUrl?: string | null; // Add image data URL
-}
-
export class AuthorService {
private static readonly AUTHORS_PATH = '/api/author';
diff --git a/services/content-moderation.service.ts b/services/content-moderation.service.ts
index 56507c680..364d0964a 100644
--- a/services/content-moderation.service.ts
+++ b/services/content-moderation.service.ts
@@ -3,8 +3,6 @@ import { ID } from '@/types/root';
import { FeedService } from './feed.service';
import { GrantModerationService, type PendingWorksResponse } from './grant-moderation.service';
-export type { PendingWorksResponse };
-
export type PendingModule = 'funding_opportunities' | 'proposals';
/** Number of pending items per module, as shown on the tab badges. */
diff --git a/services/hub.service.ts b/services/hub.service.ts
index 205f95292..b5528c7a0 100644
--- a/services/hub.service.ts
+++ b/services/hub.service.ts
@@ -1,6 +1,5 @@
import { Topic, transformTopicSuggestions, transformTopic } from '@/types/topic';
import { ApiClient } from './client';
-import { createTransformer, BaseTransformed } from '@/types/transformer';
interface HubResponse {
id: number;
@@ -38,17 +37,6 @@ export interface Hub {
description?: string;
}
-export type TransformedHub = Hub & BaseTransformed;
-
-// Transform the API response to our internal Hub model
-export const transformHub = createTransformer((hub) => ({
- id: hub.id,
- name: hub.name,
- slug: hub.slug,
- imageUrl: hub.hub_image || undefined,
- description: hub.description,
-}));
-
export class HubService {
private static readonly BASE_PATH = '/api/hub';
private static readonly SUGGEST_PATH = '/api/search/hubs/suggest';
diff --git a/services/reaction.service.ts b/services/reaction.service.ts
index b22474186..a2c6aac0c 100644
--- a/services/reaction.service.ts
+++ b/services/reaction.service.ts
@@ -56,11 +56,6 @@ export interface VoteOnCommentOptions {
documentType: DocumentType;
}
-export interface MarkNotInterestedOptions {
- documentType: DocumentType;
- documentId: ID;
-}
-
export class ReactionService {
private static readonly BASE_PATH = '/api';
diff --git a/services/types/api.ts b/services/types/api.ts
index a9f5710bc..2e73cd709 100644
--- a/services/types/api.ts
+++ b/services/types/api.ts
@@ -1,9 +1,4 @@
// API Infrastructure
-export interface ApiResponse {
- data: T;
- message?: string;
-}
-
export class ApiError extends Error {
constructor(
public message: string,
diff --git a/services/types/notification.dto.ts b/services/types/notification.dto.ts
index a9826d1ea..a2ab84fe3 100644
--- a/services/types/notification.dto.ts
+++ b/services/types/notification.dto.ts
@@ -12,7 +12,6 @@ export interface NotificationCountResponse {
count: number;
}
-export type TransformedNotificationListResponse = NotificationListResponse & BaseTransformed;
export type TransformedNotificationCountResponse = NotificationCountResponse & BaseTransformed;
export const transformNotificationListResponse = createTransformer(
diff --git a/types/authorProfile.ts b/types/authorProfile.ts
index c63d7d067..12a3ea6e8 100644
--- a/types/authorProfile.ts
+++ b/types/authorProfile.ts
@@ -1,4 +1,4 @@
-import { createTransformer, BaseTransformed } from './transformer';
+import { createTransformer } from './transformer';
import { User, transformUser } from './user';
import { Topic, transformTopic } from './topic';
@@ -46,8 +46,6 @@ export interface AuthorProfile {
isHubEditor?: boolean;
}
-export type TransformedAuthorProfile = AuthorProfile & BaseTransformed;
-
export function extractHeadline(value: unknown): string {
if (!value) return '';
if (typeof value === 'string') return value;
diff --git a/types/comment.ts b/types/comment.ts
index 414a79538..5889c83cc 100644
--- a/types/comment.ts
+++ b/types/comment.ts
@@ -81,13 +81,6 @@ export const transformThread: BaseTransformer = (raw) => ({
raw,
});
-export const transformContent = (raw: any): string => {
- if (raw.html) {
- return raw.html;
- }
- return raw.comment_content_json || '';
-};
-
export const transformComment = (raw: any): Comment => {
// Transform user_vote from API
// It can be either an object with vote_type or a direct numeric value
diff --git a/types/feed.ts b/types/feed.ts
index 1f0769e4c..429801c8b 100644
--- a/types/feed.ts
+++ b/types/feed.ts
@@ -1,15 +1,8 @@
import { AuthorProfile, transformAuthorProfile } from './authorProfile';
import { ContentMetrics } from './metrics';
import { Topic, transformTopic } from './topic';
-import { createTransformer, BaseTransformed } from './transformer';
-import {
- Work,
- transformPaper,
- transformPost,
- FundingRequest,
- ContentType,
- type WorkGrantSummary,
-} from './work';
+import { createTransformer } from './transformer';
+import { Work, transformPaper, transformPost, ContentType, type WorkGrantSummary } from './work';
import { mapApiDocumentTypeToClientType, type ApiDocumentType } from '@/utils/contentTypeMapping';
import { Bounty, BountyWithComment, transformBounty } from './bounty';
import { Comment, CommentType, ContentFormat, transformComment } from './comment';
@@ -24,9 +17,6 @@ import { FundingPool, GrantStatus, transformFundingPool } from './grant';
export type FeedActionType = 'contribute' | 'open' | 'publish' | 'post';
-// Re-export FundingRequest for backward compatibility
-export type { FundingRequest };
-
// Simplified structure for parent comment preview - now recursive
export interface ParentCommentPreview {
id: number;
@@ -626,9 +616,6 @@ export function getUnifiedDocumentId(content_object: any): string | undefined {
return undefined;
}
-export type TransformedContent = Content & BaseTransformed;
-export type TransformedFeedEntry = FeedEntry & BaseTransformed;
-
function transformActivityRelatedWorkGrant(rawGrant: unknown): WorkGrantSummary | undefined {
if (!rawGrant || typeof rawGrant !== 'object') return undefined;
@@ -1582,92 +1569,6 @@ export const transformBountyCommentToFeedItem = (
};
};
-/**
- * Creates a FeedEntry from a Work object, typically used for bounty entries
- * where we need to display the related work (paper or post) as a feed item.
- * @param work The Work object to transform into a FeedEntry
- * @param originalEntry The original FeedEntry to extract metadata from (metrics, userVote, tips)
- * @returns A FeedEntry object with the work as content, or null if the work cannot be transformed
- */
-export const createFeedEntryFromWork = (work: Work, originalEntry: FeedEntry): FeedEntry | null => {
- if (!work) return null;
-
- const contentType = work.contentType === 'paper' ? 'PAPER' : 'POST';
- if (!contentType) return null;
-
- const bountyEntry = originalEntry.content as FeedBountyContent;
- const originalBounty = bountyEntry.bounty;
- const bountyWithComment: BountyWithComment = {
- ...originalBounty,
- comment: bountyEntry.comment,
- };
-
- // Transform Work to FeedPostContent or FeedPaperContent
- if (contentType === 'POST') {
- const postContent: FeedPostContent = {
- id: work.id,
- bounties: [bountyWithComment],
- contentType: work.postType === 'PREREGISTRATION' ? 'PREREGISTRATION' : 'POST',
- createdDate: work.createdDate,
- createdBy: work.authors?.[0]?.authorProfile || bountyEntry.createdBy,
- textPreview: work.previewContent || work.abstract || '',
- slug: work.slug,
- title: work.title,
- previewImage: work.image,
- authors: work.authors?.map((a: { authorProfile: any }) => a.authorProfile) || [],
- topics: work.topics || [],
- postType: work.postType,
- };
-
- return {
- id: work.id.toString(),
- recommendationId: null,
- timestamp: work.createdDate,
- action: 'publish',
- contentType: contentType,
- content: postContent,
- relatedWork: undefined,
- metrics: originalEntry.metrics,
- userVote: originalEntry.userVote,
- tips: originalEntry.tips,
- };
- } else if (contentType === 'PAPER') {
- const paperContent: FeedPaperContent = {
- id: work.id,
- bounties: [bountyWithComment],
- contentType: 'PAPER',
- createdDate: work.createdDate,
- createdBy: work.authors?.[0]?.authorProfile || bountyEntry.createdBy,
- textPreview: work.abstract || '',
- slug: work.slug,
- title: work.title,
- authors: work.authors?.map((a: { authorProfile: any }) => a.authorProfile) || [],
- topics: work.topics || [],
- journal: work.journal || {
- id: 0,
- name: '',
- slug: '',
- description: '',
- },
- };
-
- return {
- id: work.id.toString(),
- recommendationId: null,
- timestamp: work.createdDate,
- action: 'publish',
- contentType: 'PAPER',
- content: paperContent,
- relatedWork: undefined,
- metrics: originalEntry.metrics,
- userVote: originalEntry.userVote,
- tips: originalEntry.tips,
- };
- }
-
- return null;
-};
-
export type { AuthorProfile };
export type { Fundraise };
diff --git a/types/leaderboard.ts b/types/leaderboard.ts
index e0dc28dc0..ede60679b 100644
--- a/types/leaderboard.ts
+++ b/types/leaderboard.ts
@@ -75,9 +75,6 @@ export interface LeaderboardMeResponse {
funder: RawTopFunder | null;
}
-export type LeaderboardReviewersResponse = RawTopReviewer[];
-export type LeaderboardFundersResponse = RawTopFunder[];
-
// Transformer for TopReviewer
export const transformTopReviewer = createTransformer(
(raw: RawTopReviewer) => {
diff --git a/types/note.ts b/types/note.ts
index 03b6a10d2..053f97840 100644
--- a/types/note.ts
+++ b/types/note.ts
@@ -1,6 +1,6 @@
import { CHANGELOG_NOTEBOOK_ROLLOUT_AT, CHANGELOG_POST_IDS } from '@/constants/changelog';
import type { Organization } from './organization';
-import { createTransformer, BaseTransformed } from './transformer';
+import { createTransformer } from './transformer';
import { transformOrganization } from './organization';
import { Currency, ID } from './root';
import { ContentType, ModerationStatus } from './work';
@@ -221,22 +221,6 @@ export interface NoteVersionEvent {
export const NOTE_VERSION_CREATED = 'note_version_created';
-export interface NoteApiItem {
- id: number;
- access: NoteAccess;
- organization: {
- id: number;
- cover_image: string | null;
- name: string;
- slug: string;
- };
- created_date: string;
- updated_date: string;
- title: string;
-}
-
-export type TransformedNote = Note & BaseTransformed;
-
const buildFullName = (raw: any): string =>
`${raw.first_name || ''} ${raw.last_name || ''}`.trim() || 'Unknown';
diff --git a/types/notification.ts b/types/notification.ts
index cda66aa1f..28ec864bb 100644
--- a/types/notification.ts
+++ b/types/notification.ts
@@ -49,9 +49,7 @@ export interface Notification {
createdDate: Date;
}
-export type TransformedNotification = Notification & BaseTransformed;
export type TransformedNotificationExtra = NotificationExtra & BaseTransformed;
-export type TransformedNotificationBodyElement = NotificationBodyElement & BaseTransformed;
export type NotificationForWork = NonNullable;
diff --git a/types/search.ts b/types/search.ts
index 1a7e81836..c87ea8f29 100644
--- a/types/search.ts
+++ b/types/search.ts
@@ -1,4 +1,4 @@
-import { createTransformer, BaseTransformed } from './transformer';
+import { createTransformer } from './transformer';
import { buildWorkUrl, buildAuthorUrl, buildTopicUrl } from '@/utils/url';
import { mapApiDocumentTypeToClientType } from '@/utils/contentTypeMapping';
import { AuthorProfile, extractHeadline } from './authorProfile';
@@ -6,7 +6,6 @@ import { ID } from './root';
import { transformTopic } from './topic';
import { ContentType } from './work';
-export type SuggestionSource = 'api' | 'recent' | 'researchhub' | 'openalex';
export type EntityType = 'user' | 'paper' | 'author' | 'post' | 'hub';
export interface BaseSuggestion {
@@ -62,17 +61,6 @@ export interface TopicSuggestion extends BaseSuggestion {
export type SearchSuggestion = WorkSuggestion | UserSuggestion | PostSuggestion | TopicSuggestion;
-export interface RecentPageView {
- id: number;
- title: string;
- doi?: string;
- authors: string[];
- lastVisited: string;
- slug: string;
-}
-
-export type TransformedSearchSuggestion = SearchSuggestion & BaseTransformed;
-
export const transformSearchSuggestion = createTransformer((raw: any) => {
try {
if (raw.lastVisited) {
diff --git a/types/work.ts b/types/work.ts
index cfe025602..dbec4533c 100644
--- a/types/work.ts
+++ b/types/work.ts
@@ -146,22 +146,7 @@ export interface WorkGrantSummary {
endDate?: string;
}
-export interface FundingRequest extends Work {
- type: 'funding_request';
- contentType: 'funding_request';
- status: 'OPEN' | 'CLOSED' | 'FUNDED';
- amount: number;
- goalAmount: number;
- deadline: string;
- preregistered?: boolean;
- image?: string;
-}
-
-// Transformed types
-export type TransformedAuthorship = Authorship & BaseTransformed;
export type TransformedJournal = Journal & BaseTransformed;
-export type TransformedTopic = Topic & BaseTransformed;
-export type TransformedDocumentVersion = DocumentVersion & BaseTransformed;
export type TransformedWork = Work & BaseTransformed;
// Transformers
diff --git a/utils/number.ts b/utils/number.ts
index 03650c2b4..788bda69e 100644
--- a/utils/number.ts
+++ b/utils/number.ts
@@ -200,57 +200,6 @@ export function extractExchangeRate(
return 0;
}
-interface FormatCombinedBalanceOptions {
- balance: BalanceData | null;
- lockedBalance: BalanceData | null;
- showUSD: boolean;
- includeRSCSuffix?: boolean;
-}
-
-/**
- * Formats the combined balance (available + locked) in the preferred currency
- * @param options Formatting options
- * @returns Formatted string in the preferred currency
- */
-export function formatCombinedBalance({
- balance,
- lockedBalance,
- showUSD,
- includeRSCSuffix = true,
-}: FormatCombinedBalanceOptions): string {
- const totalRaw = (balance?.raw || 0) + (lockedBalance?.raw || 0);
-
- if (showUSD) {
- const exchangeRate = extractExchangeRate(balance, lockedBalance);
- return exchangeRate > 0 ? formatUsdValue(totalRaw.toString(), exchangeRate) : '$0.00';
- } else {
- const formatted = formatRSC({ amount: totalRaw });
- return includeRSCSuffix ? `${formatted} RSC` : formatted;
- }
-}
-
-/**
- * Gets the secondary currency display for combined balance
- * @param options Formatting options
- * @returns Formatted string in the secondary currency
- */
-export function formatCombinedBalanceSecondary({
- balance,
- lockedBalance,
- showUSD,
-}: FormatCombinedBalanceOptions): string {
- const totalRaw = (balance?.raw || 0) + (lockedBalance?.raw || 0);
-
- if (showUSD) {
- // Secondary is RSC when primary is USD
- return `${formatRSC({ amount: totalRaw })} RSC`;
- } else {
- // Secondary is USD when primary is RSC
- const exchangeRate = extractExchangeRate(balance, lockedBalance);
- return exchangeRate > 0 ? formatUsdValue(totalRaw.toString(), exchangeRate) : '$0.00 USD';
- }
-}
-
/**
* Parse a decimal amount from user input. Accepts optional thousand separators
* (`,` or spaces) and a `.` decimal; rejects trailing/leading junk that
diff --git a/utils/preprintUtil.ts b/utils/preprintUtil.ts
index ff3b060e9..194ea179e 100644
--- a/utils/preprintUtil.ts
+++ b/utils/preprintUtil.ts
@@ -29,9 +29,6 @@ export const isPreprintServer = (slug: string): boolean => {
return ['arxiv', 'biorxiv', 'chemrxiv', 'medrxiv'].includes(slug.toLowerCase());
};
-// Alias for getSourceLogo (for consistency with other naming conventions)
-export const get_document_metadata = getSourceLogo;
-
// Get display name for preprint servers
export const getPreprintDisplayName = (slug: string): string => {
const sourceLower = slug.toLowerCase();
diff --git a/utils/url.ts b/utils/url.ts
index 8d7b9aa70..3b2652d32 100644
--- a/utils/url.ts
+++ b/utils/url.ts
@@ -1,15 +1,6 @@
import { withShareToken } from '@/lib/shareToken/url';
import type { ContentType } from '@/types/work';
-export const ALL_CONTENT_TYPES: readonly ContentType[] = [
- 'paper',
- 'post',
- 'preregistration',
- 'question',
- 'discussion',
- 'funding_request',
-];
-
// URL path segment (first path segment) → ContentType. Aligns with app routes: /paper/, /post/, /question/, /proposal/, /fund/, /grant/
const ROUTE_SEGMENT_TO_CONTENT_TYPE: Record = {
paper: 'paper',
diff --git a/utils/validation.ts b/utils/validation.ts
index 12473b228..ae7a416f3 100644
--- a/utils/validation.ts
+++ b/utils/validation.ts
@@ -2,11 +2,3 @@ export const isValidEmail = (email: string): boolean => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
-
-export const isValidPassword = (password: string): boolean => {
- return password.length >= 8;
-};
-
-export const isValidName = (name: string): boolean => {
- return name.trim().length > 0;
-};