diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index fd496a820..000000000 --- a/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "singleQuote": true, - "semi": false -} diff --git a/agents/tasks/feed-feature-plan.plan.md b/agents/tasks/feed-feature-plan.plan.md index 858a2c3ae..71648d408 100644 --- a/agents/tasks/feed-feature-plan.plan.md +++ b/agents/tasks/feed-feature-plan.plan.md @@ -49,7 +49,7 @@ feedEntries: defineTable({ v.literal('major'), v.literal('minor'), v.literal('patch'), - v.literal('prerelease') + v.literal('prerelease'), ), url: v.string(), // GitHub release URL author: v.optional(v.string()), // GitHub username @@ -66,7 +66,7 @@ feedEntries: defineTable({ type: v.literal('manual'), createdBy: v.id('users'), // Admin user who created it editedBy: v.optional(v.id('users')), // Last editor - }) + }), ), // Categorization @@ -79,7 +79,7 @@ feedEntries: defineTable({ v.literal('blog'), v.literal('partner'), v.literal('update'), - v.literal('other') + v.literal('other'), ), // Display control @@ -219,7 +219,7 @@ z.object({ libraries: z.array(librarySchema).optional(), categories: z .array( - z.enum(['release', 'announcement', 'blog', 'partner', 'update', 'other']) + z.enum(['release', 'announcement', 'blog', 'partner', 'update', 'other']), ) .optional(), partners: z.array(z.string()).optional(), diff --git a/agents/tasks/tanstack-com-task-list.md b/agents/tasks/tanstack-com-task-list.md index 3a9509a8c..25866d00f 100644 --- a/agents/tasks/tanstack-com-task-list.md +++ b/agents/tasks/tanstack-com-task-list.md @@ -28,7 +28,6 @@ ### Tasks - [ ] Implement “Trusted By” on homepage - - Status: Backlog - Notes: - Reuse `TrustedByMarquee` but upgrade to support logos + links + tooltip proof. @@ -43,7 +42,6 @@ - Owner: - [ ] Add Real-Time Metrics Counters (per-library + org rollup) - - Status: Partial (org rollup live via `OpenSourceStats`) - Notes: - Extend counters to per-library pages using existing Convex endpoints or add repo-level endpoints via `convex-oss-stats` if needed. @@ -91,7 +89,6 @@ ### Tasks - [ ] Redesign/Create “About” page - - Status: Backlog - Notes: - Route: `src/routes/about.tsx`. @@ -101,7 +98,6 @@ - Links: `src/components/MaintainerCard.tsx`, `src/routes/_libraries/maintainers.tsx`. - [ ] Speaking Engagements section - - Status: Backlog - Notes: - Add to About or standalone `src/routes/speaking.tsx`. @@ -136,7 +132,6 @@ ### Tasks - [ ] “Enterprise” page - - Status: Partial - Notes: - Option 1: Rename and expand `paid-support` into `enterprise` (route alias + updated copy) while keeping legacy route. @@ -165,7 +160,6 @@ ### Tasks - [ ] Public Roadmap page - - Status: Backlog - Notes: - Route: `src/routes/roadmap.tsx`. @@ -194,7 +188,6 @@ ### Tasks - [ ] Press/Media Kit page - - Status: Backlog - Notes: - Route: `src/routes/media-kit.tsx`. @@ -203,7 +196,6 @@ - Acceptance: Page provides direct downloads and usage rules. - [ ] In the News page - - Status: Backlog - Notes: - Route: `src/routes/news.tsx`. diff --git a/convex/capabilities.ts b/convex/capabilities.ts index 5fa79a199..496b0fa92 100644 --- a/convex/capabilities.ts +++ b/convex/capabilities.ts @@ -6,7 +6,7 @@ import { Id } from './_generated/dataModel' // Extracted to avoid circular dependencies between users.ts and roles.ts export async function getEffectiveCapabilities( ctx: QueryCtx, - userId: Id<'users'> + userId: Id<'users'>, ): Promise { // Get user's direct capabilities const user = await ctx.db.get(userId) @@ -32,7 +32,7 @@ export async function getEffectiveCapabilities( // Union of direct capabilities and role capabilities const effectiveCapabilities = Array.from( - new Set([...directCapabilities, ...roleCapabilities]) + new Set([...directCapabilities, ...roleCapabilities]), ) // Admin users automatically get feed capability diff --git a/convex/feed/actions.ts b/convex/feed/actions.ts index 2f7a92c3a..eedb769b7 100644 --- a/convex/feed/actions.ts +++ b/convex/feed/actions.ts @@ -25,7 +25,7 @@ export const syncAllSources = action({ try { const githubResult: { success: boolean } = await ctx.runAction( api.feed.github.syncGitHubReleases, - {} // Uses default of 2 days + {}, // Uses default of 2 days ) results.github.success = githubResult.success } catch (error) { diff --git a/convex/feed/blog.ts b/convex/feed/blog.ts index 09a8b7ff9..5409adef8 100644 --- a/convex/feed/blog.ts +++ b/convex/feed/blog.ts @@ -65,7 +65,7 @@ export const syncBlogPosts = action({ excerpt: v.optional(v.string()), content: v.string(), authors: v.array(v.string()), - }) + }), ), }, handler: async (ctx, args) => { diff --git a/convex/feed/crons.ts b/convex/feed/crons.ts index 5923252bd..41534ce1f 100644 --- a/convex/feed/crons.ts +++ b/convex/feed/crons.ts @@ -10,7 +10,7 @@ crons.hourly( minuteUTC: 0, }, api.feed.github.syncGitHubReleases, - {} + {}, ) // Note: Blog sync requires server-side access to content-collections diff --git a/convex/feed/crypto.ts b/convex/feed/crypto.ts index f6339d693..ac5bf29f3 100644 --- a/convex/feed/crypto.ts +++ b/convex/feed/crypto.ts @@ -19,7 +19,7 @@ export const verifyGitHubSignature = action({ const digest = 'sha256=' + hmac.update(args.payload).digest('hex') return crypto.timingSafeEqual( Buffer.from(args.signature), - Buffer.from(digest) + Buffer.from(digest), ) }, }) diff --git a/convex/feed/github.ts b/convex/feed/github.ts index b4aadf9fd..342fc53dd 100644 --- a/convex/feed/github.ts +++ b/convex/feed/github.ts @@ -155,7 +155,7 @@ async function getLastSyncTime(ctx: any, repo: string): Promise { async function updateLastSyncTime( ctx: any, repo: string, - timestamp: number + timestamp: number, ): Promise { const configKey = `github:sync:${repo}` await ctx.runMutation(api.feed.mutations.setFeedConfig, { @@ -173,7 +173,7 @@ async function updateLastSyncTime( async function fetchRepoReleases( repo: string, token: string, - since?: number + since?: number, ): Promise { const url = `https://api.github.com/repos/${repo}/releases?per_page=100&page=1` @@ -211,7 +211,7 @@ async function fetchRepoReleases( // Filter by since timestamp if provided if (since && since > 0) { return releases.filter( - (release: any) => new Date(release.published_at).getTime() > since + (release: any) => new Date(release.published_at).getTime() > since, ) } @@ -234,7 +234,7 @@ export const syncGitHubReleases = action({ const token = process.env.GITHUB_AUTH_TOKEN if (!token) { throw new Error( - 'GITHUB_AUTH_TOKEN not configured. Please set it in Convex dashboard.' + 'GITHUB_AUTH_TOKEN not configured. Please set it in Convex dashboard.', ) } @@ -323,7 +323,7 @@ export const syncGitHubReleases = action({ } catch (error) { console.error( `Error processing release ${release.id} from ${repo}:`, - error + error, ) errorCount++ } diff --git a/convex/feed/http.ts b/convex/feed/http.ts index 4d140a5da..ae18fd40a 100644 --- a/convex/feed/http.ts +++ b/convex/feed/http.ts @@ -10,7 +10,7 @@ export const handleGitHubWebhook = httpAction(async (ctx, request) => { { status: 500, headers: { 'Content-Type': 'application/json' }, - } + }, ) } @@ -55,7 +55,7 @@ export const handleGitHubWebhook = httpAction(async (ctx, request) => { { status: 200, headers: { 'Content-Type': 'application/json' }, - } + }, ) } @@ -109,6 +109,6 @@ export const handleGitHubWebhook = httpAction(async (ctx, request) => { { status: 200, headers: { 'Content-Type': 'application/json' }, - } + }, ) }) diff --git a/convex/feed/manual.ts b/convex/feed/manual.ts index 1b7dba684..1caef2a0a 100644 --- a/convex/feed/manual.ts +++ b/convex/feed/manual.ts @@ -33,7 +33,7 @@ export function generateManualEntryId(): string { */ export function generateExcerpt( content: string, - maxLength: number = 200 + maxLength: number = 200, ): string { // Remove markdown headers, links, etc. for a cleaner excerpt const plainText = content diff --git a/convex/feed/mutations.ts b/convex/feed/mutations.ts index b3c255bce..12a711047 100644 --- a/convex/feed/mutations.ts +++ b/convex/feed/mutations.ts @@ -34,7 +34,7 @@ export const createFeedEntry = mutation({ const publishedAtValidation = validatePublishedAt(args.publishedAt) if (!publishedAtValidation.valid) { throw new Error( - `Invalid publishedAt: ${publishedAtValidation.error}. publishedAt should represent when the content was actually published, not when it was added to the feed.` + `Invalid publishedAt: ${publishedAtValidation.error}. publishedAt should represent when the content was actually published, not when it was added to the feed.`, ) } @@ -46,7 +46,7 @@ export const createFeedEntry = mutation({ if (existing) { throw new Error( - `Feed entry with ID "${args.id}" already exists. Please try again or edit the existing entry.` + `Feed entry with ID "${args.id}" already exists. Please try again or edit the existing entry.`, ) } @@ -116,7 +116,7 @@ export const updateFeedEntry = mutation({ const publishedAtValidation = validatePublishedAt(args.publishedAt) if (!publishedAtValidation.valid) { throw new Error( - `Invalid publishedAt: ${publishedAtValidation.error}. publishedAt should represent when the content was actually published.` + `Invalid publishedAt: ${publishedAtValidation.error}. publishedAt should represent when the content was actually published.`, ) } updates.publishedAt = args.publishedAt diff --git a/convex/feed/queries.ts b/convex/feed/queries.ts index 51592d880..0f07c48a9 100644 --- a/convex/feed/queries.ts +++ b/convex/feed/queries.ts @@ -21,7 +21,7 @@ export const listFeedEntries = query({ featured: v.optional(v.boolean()), search: v.optional(v.string()), includeHidden: v.optional(v.boolean()), // Admin flag to show all entries - }) + }), ), }, handler: async (ctx, args) => { @@ -36,26 +36,26 @@ export const listFeedEntries = query({ : await ctx.db .query('feedEntries') .withIndex('by_visible', (q) => - q.eq('isVisible', true).gte('publishedAt', 0) + q.eq('isVisible', true).gte('publishedAt', 0), ) .collect() // Apply filters if (filters.sources && filters.sources.length > 0) { entries = entries.filter((entry) => - filters.sources!.includes(entry.source) + filters.sources!.includes(entry.source), ) } if (filters.categories && filters.categories.length > 0) { entries = entries.filter((entry) => - filters.categories!.includes(entry.category) + filters.categories!.includes(entry.category), ) } if (filters.libraries && filters.libraries.length > 0) { entries = entries.filter((entry) => - entry.libraryIds.some((libId) => filters.libraries!.includes(libId)) + entry.libraryIds.some((libId) => filters.libraries!.includes(libId)), ) } @@ -64,14 +64,14 @@ export const listFeedEntries = query({ (entry) => entry.partnerIds && entry.partnerIds.some((partnerId) => - filters.partners!.includes(partnerId) - ) + filters.partners!.includes(partnerId), + ), ) } if (filters.tags && filters.tags.length > 0) { entries = entries.filter((entry) => - filters.tags!.some((tag) => entry.tags.includes(tag)) + filters.tags!.some((tag) => entry.tags.includes(tag)), ) } @@ -83,7 +83,7 @@ export const listFeedEntries = query({ entries = entries.filter((entry) => { // Check if entry has release level tags const releaseLevelTags = entry.tags.filter((tag) => - tag.startsWith('release:') + tag.startsWith('release:'), ) if (releaseLevelTags.length === 0) { // Not a release entry, include it (unless explicitly filtering releases only) @@ -96,7 +96,7 @@ export const listFeedEntries = query({ // Check if this is a prerelease const isPrerelease = releaseLevelTags.some( - (tag) => tag === 'release:prerelease' + (tag) => tag === 'release:prerelease', ) // If it's a prerelease, check includePrerelease flag @@ -109,7 +109,7 @@ export const listFeedEntries = query({ (tag) => tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch' + tag === 'release:patch', ) if (!baseReleaseTag) { return false @@ -136,7 +136,7 @@ export const listFeedEntries = query({ if (filters.search && filters.search.length > 0) { const searchLower = filters.search.toLowerCase() entries = entries.filter((entry) => - entry.title.toLowerCase().includes(searchLower) + entry.title.toLowerCase().includes(searchLower), ) } @@ -247,7 +247,7 @@ export const getFeedFacetCounts = query({ featured: v.optional(v.boolean()), search: v.optional(v.string()), includeHidden: v.optional(v.boolean()), - }) + }), ), }, handler: async (ctx, args) => { @@ -260,7 +260,7 @@ export const getFeedFacetCounts = query({ : await ctx.db .query('feedEntries') .withIndex('by_visible', (q) => - q.eq('isVisible', true).gte('publishedAt', 0) + q.eq('isVisible', true).gte('publishedAt', 0), ) .collect() @@ -286,7 +286,7 @@ export const getFeedFacetCounts = query({ | 'releaseLevels' | 'includePrerelease' | 'featured' - | 'search' + | 'search', ) => { let filtered = [...entriesToFilter] @@ -296,7 +296,7 @@ export const getFeedFacetCounts = query({ filters.sources.length > 0 ) { filtered = filtered.filter((entry) => - filters.sources!.includes(entry.source) + filters.sources!.includes(entry.source), ) } @@ -306,7 +306,7 @@ export const getFeedFacetCounts = query({ filters.categories.length > 0 ) { filtered = filtered.filter((entry) => - filters.categories!.includes(entry.category) + filters.categories!.includes(entry.category), ) } @@ -316,7 +316,7 @@ export const getFeedFacetCounts = query({ filters.libraries.length > 0 ) { filtered = filtered.filter((entry) => - entry.libraryIds.some((libId) => filters.libraries!.includes(libId)) + entry.libraryIds.some((libId) => filters.libraries!.includes(libId)), ) } @@ -329,14 +329,14 @@ export const getFeedFacetCounts = query({ (entry) => entry.partnerIds && entry.partnerIds.some((partnerId) => - filters.partners!.includes(partnerId) - ) + filters.partners!.includes(partnerId), + ), ) } if (excludeFacet !== 'tags' && filters.tags && filters.tags.length > 0) { filtered = filtered.filter((entry) => - filters.tags!.some((tag) => entry.tags.includes(tag)) + filters.tags!.some((tag) => entry.tags.includes(tag)), ) } @@ -347,7 +347,7 @@ export const getFeedFacetCounts = query({ if (filters.releaseLevels !== undefined) { filtered = filtered.filter((entry) => { const releaseLevelTags = entry.tags.filter((tag) => - tag.startsWith('release:') + tag.startsWith('release:'), ) if (releaseLevelTags.length === 0) { return true @@ -356,7 +356,7 @@ export const getFeedFacetCounts = query({ return false } const isPrerelease = releaseLevelTags.some( - (tag) => tag === 'release:prerelease' + (tag) => tag === 'release:prerelease', ) if (isPrerelease && filters.includePrerelease !== true) { return false @@ -365,7 +365,7 @@ export const getFeedFacetCounts = query({ (tag) => tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch' + tag === 'release:patch', ) if (!baseReleaseTag) { return false @@ -386,7 +386,7 @@ export const getFeedFacetCounts = query({ if (excludeFacet !== 'featured' && filters.featured !== undefined) { filtered = filtered.filter( - (entry) => entry.featured === filters.featured + (entry) => entry.featured === filters.featured, ) } @@ -397,7 +397,7 @@ export const getFeedFacetCounts = query({ ) { const searchLower = filters.search.toLowerCase() filtered = filtered.filter((entry) => - entry.title.toLowerCase().includes(searchLower) + entry.title.toLowerCase().includes(searchLower), ) } @@ -443,14 +443,14 @@ export const getFeedFacetCounts = query({ const releaseEntries = applyFiltersExcept(entries, 'releaseLevels') for (const entry of releaseEntries) { const releaseLevelTags = entry.tags.filter((tag) => - tag.startsWith('release:') + tag.startsWith('release:'), ) if (releaseLevelTags.length > 0) { const baseReleaseTag = releaseLevelTags.find( (tag) => tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch' + tag === 'release:patch', ) if (baseReleaseTag) { const level = baseReleaseTag.replace('release:', '') @@ -462,13 +462,13 @@ export const getFeedFacetCounts = query({ // Count prerelease (separate from release levels) const prereleaseEntries = applyFiltersExcept(entries, 'includePrerelease') const prereleaseCount = prereleaseEntries.filter((entry) => - entry.tags.includes('release:prerelease') + entry.tags.includes('release:prerelease'), ).length // Count featured const featuredEntries = applyFiltersExcept(entries, 'featured') const featuredCount = featuredEntries.filter( - (entry) => entry.featured + (entry) => entry.featured, ).length return { diff --git a/convex/feed/schema.ts b/convex/feed/schema.ts index 8fd4bea5e..8b501db50 100644 --- a/convex/feed/schema.ts +++ b/convex/feed/schema.ts @@ -23,9 +23,9 @@ export type ReleaseLevel = (typeof RELEASE_LEVELS)[number] * Convex validators derived from constants */ export const feedCategoryValidator = v.union( - ...FEED_CATEGORIES.map((cat) => v.literal(cat)) + ...FEED_CATEGORIES.map((cat) => v.literal(cat)), ) export const releaseLevelValidator = v.union( - ...RELEASE_LEVELS.map((level) => v.literal(level)) + ...RELEASE_LEVELS.map((level) => v.literal(level)), ) diff --git a/convex/feed/timestamps.ts b/convex/feed/timestamps.ts index 116114885..336cf954f 100644 --- a/convex/feed/timestamps.ts +++ b/convex/feed/timestamps.ts @@ -39,7 +39,7 @@ export function getEffectivePublishedAt(entry: { // Fallback to createdAt if publishedAt is invalid console.warn( - `Invalid publishedAt (${entry.publishedAt}) for entry, using createdAt (${entry.createdAt})` + `Invalid publishedAt (${entry.publishedAt}) for entry, using createdAt (${entry.createdAt})`, ) return entry.createdAt } diff --git a/convex/roles.ts b/convex/roles.ts index 085b40796..b78bfe862 100644 --- a/convex/roles.ts +++ b/convex/roles.ts @@ -20,9 +20,9 @@ export const listRoles = query({ v.literal('admin'), v.literal('disableAds'), v.literal('builder'), - v.literal('feed') - ) - ) + v.literal('feed'), + ), + ), ), }, handler: async (ctx, args) => { @@ -38,14 +38,14 @@ export const listRoles = query({ (role) => role.name.toLowerCase().includes(nameLower) || (role.description && - role.description.toLowerCase().includes(nameLower)) + role.description.toLowerCase().includes(nameLower)), ) } // Apply capability filter if (args.capabilityFilter && args.capabilityFilter.length > 0) { roles = roles.filter((role) => - args.capabilityFilter!.some((cap) => role.capabilities.includes(cap)) + args.capabilityFilter!.some((cap) => role.capabilities.includes(cap)), ) } @@ -78,8 +78,8 @@ export const createRole = mutation({ v.literal('admin'), v.literal('disableAds'), v.literal('builder'), - v.literal('feed') - ) + v.literal('feed'), + ), ), }, handler: async (ctx, args) => { @@ -97,7 +97,7 @@ export const createRole = mutation({ // Validate capabilities const validatedCapabilities = CapabilitySchema.array().parse( - args.capabilities + args.capabilities, ) const now = Date.now() @@ -125,9 +125,9 @@ export const updateRole = mutation({ v.literal('admin'), v.literal('disableAds'), v.literal('builder'), - v.literal('feed') - ) - ) + v.literal('feed'), + ), + ), ), }, handler: async (ctx, args) => { @@ -159,7 +159,7 @@ export const updateRole = mutation({ if (args.description !== undefined) updates.description = args.description if (args.capabilities !== undefined) { const validatedCapabilities = CapabilitySchema.array().parse( - args.capabilities + args.capabilities, ) updates.capabilities = validatedCapabilities } @@ -223,7 +223,7 @@ export const getUserRoles = query({ .collect() const roles = await Promise.all( - roleAssignments.map((ra) => ctx.db.get(ra.roleId)) + roleAssignments.map((ra) => ctx.db.get(ra.roleId)), ) return roles.filter((role) => role !== null) @@ -247,7 +247,7 @@ export const assignRolesToUser = mutation({ // Validate that all roles exist const roles = await Promise.all( - args.roleIds.map((roleId) => ctx.db.get(roleId)) + args.roleIds.map((roleId) => ctx.db.get(roleId)), ) if (roles.some((role) => role === null)) { throw new Error('One or more roles not found') @@ -264,13 +264,13 @@ export const assignRolesToUser = mutation({ // Delete assignments that are no longer needed const toDelete = existingAssignments.filter( - (ra) => !newRoleIds.has(ra.roleId) + (ra) => !newRoleIds.has(ra.roleId), ) await Promise.all(toDelete.map((ra) => ctx.db.delete(ra._id))) // Create new assignments const toCreate = args.roleIds.filter( - (roleId) => !existingRoleIds.has(roleId) + (roleId) => !existingRoleIds.has(roleId), ) const now = Date.now() await Promise.all( @@ -279,8 +279,8 @@ export const assignRolesToUser = mutation({ userId: args.userId, roleId, createdAt: now, - }) - ) + }), + ), ) return { success: true } @@ -322,7 +322,7 @@ export const getBulkUserRoles = query({ // Filter to only assignments for our users const userIdsSet = new Set(args.userIds) const relevantAssignments = allAssignments.filter((ra) => - userIdsSet.has(ra.userId) + userIdsSet.has(ra.userId), ) // Group by userId @@ -338,13 +338,13 @@ export const getBulkUserRoles = query({ // Get all unique role IDs const roleIds = Array.from( - new Set(relevantAssignments.map((ra) => ra.roleId)) + new Set(relevantAssignments.map((ra) => ra.roleId)), ) const roles = await Promise.all(roleIds.map((roleId) => ctx.db.get(roleId))) // Build map of roleId -> role const roleMap = new Map( - roles.filter((r) => r !== null).map((r) => [r!._id, r!]) + roles.filter((r) => r !== null).map((r) => [r!._id, r!]), ) // Group assignments by user @@ -377,7 +377,7 @@ export const getBulkEffectiveCapabilities = query({ // Get all users const users = await Promise.all( - args.userIds.map((userId) => ctx.db.get(userId)) + args.userIds.map((userId) => ctx.db.get(userId)), ) // Get all role assignments in one query @@ -385,12 +385,12 @@ export const getBulkEffectiveCapabilities = query({ const userIdsSet = new Set(args.userIds) const relevantAssignments = allAssignments.filter((ra) => - userIdsSet.has(ra.userId) + userIdsSet.has(ra.userId), ) // Get all unique role IDs const roleIds = Array.from( - new Set(relevantAssignments.map((ra) => ra.roleId)) + new Set(relevantAssignments.map((ra) => ra.roleId)), ) const roles = await Promise.all(roleIds.map((roleId) => ctx.db.get(roleId))) @@ -398,7 +398,7 @@ export const getBulkEffectiveCapabilities = query({ const roleCapabilitiesMap = new Map( roles .filter((r) => r !== null) - .map((r) => [r!._id, r!.capabilities || []]) + .map((r) => [r!._id, r!.capabilities || []]), ) // Build result: userId -> effective capabilities @@ -410,15 +410,15 @@ export const getBulkEffectiveCapabilities = query({ // Get role capabilities for this user const userAssignments = relevantAssignments.filter( - (ra) => ra.userId === user._id + (ra) => ra.userId === user._id, ) const roleCapabilities = userAssignments.flatMap( - (ra) => roleCapabilitiesMap.get(ra.roleId) || [] + (ra) => roleCapabilitiesMap.get(ra.roleId) || [], ) // Union of direct + role capabilities result[user._id] = Array.from( - new Set([...directCapabilities, ...roleCapabilities]) + new Set([...directCapabilities, ...roleCapabilities]), ) }) @@ -471,7 +471,7 @@ export const removeUsersFromRole = mutation({ // Validate that all users exist const users = await Promise.all( - args.userIds.map((userId) => ctx.db.get(userId)) + args.userIds.map((userId) => ctx.db.get(userId)), ) if (users.some((user) => user === null)) { throw new Error('One or more users not found') @@ -503,7 +503,7 @@ export const bulkAssignRolesToUsers = mutation({ // Validate that all users exist const users = await Promise.all( - args.userIds.map((userId) => ctx.db.get(userId)) + args.userIds.map((userId) => ctx.db.get(userId)), ) if (users.some((user) => user === null)) { throw new Error('One or more users not found') @@ -511,7 +511,7 @@ export const bulkAssignRolesToUsers = mutation({ // Validate that all roles exist const roles = await Promise.all( - args.roleIds.map((roleId) => ctx.db.get(roleId)) + args.roleIds.map((roleId) => ctx.db.get(roleId)), ) if (roles.some((role) => role === null)) { throw new Error('One or more roles not found') @@ -533,7 +533,7 @@ export const bulkAssignRolesToUsers = mutation({ .collect() const existingRoleIds = new Set( - existingAssignments.map((ra) => ra.roleId) + existingAssignments.map((ra) => ra.roleId), ) // Add new assignments for roles not already assigned @@ -551,8 +551,8 @@ export const bulkAssignRolesToUsers = mutation({ // Insert all new assignments await Promise.all( assignmentsToCreate.map((assignment) => - ctx.db.insert('roleAssignments', assignment) - ) + ctx.db.insert('roleAssignments', assignment), + ), ) return { success: true, assigned: assignmentsToCreate.length } diff --git a/discord-bot/src/index.js b/discord-bot/src/index.js index e583e3c03..5c06f9425 100644 --- a/discord-bot/src/index.js +++ b/discord-bot/src/index.js @@ -67,7 +67,7 @@ async function init() { console.info(member) member.roles.add( - member.guild.roles.cache.find((i) => i.name === 'Among The Server') + member.guild.roles.cache.find((i) => i.name === 'Among The Server'), ) }) } diff --git a/netlify/functions/refresh-stats-cache-background.ts b/netlify/functions/refresh-stats-cache-background.ts index d99e2abd0..8298c1ad1 100644 --- a/netlify/functions/refresh-stats-cache-background.ts +++ b/netlify/functions/refresh-stats-cache-background.ts @@ -31,7 +31,7 @@ import { setCachedGitHubStats } from '~/utils/stats-db.server' */ export const handler: Handler = async ( event: HandlerEvent, - context: HandlerContext + context: HandlerContext, ) => { console.log('[refresh-stats-cache-background] Starting stats refresh...') @@ -46,7 +46,7 @@ export const handler: Handler = async ( // Refresh GitHub org stats console.log( - '[refresh-stats-cache-background] Refreshing GitHub org stats...' + '[refresh-stats-cache-background] Refreshing GitHub org stats...', ) const githubCacheKey = `org:${org}` const githubStats = await fetchGitHubOwnerStats(org) @@ -54,12 +54,12 @@ export const handler: Handler = async ( // Refresh GitHub stats for each library repo console.log( - '[refresh-stats-cache-background] Refreshing GitHub stats for individual libraries...' + '[refresh-stats-cache-background] Refreshing GitHub stats for individual libraries...', ) const { libraries } = await import('~/libraries') console.log( `[refresh-stats-cache-background] Found ${libraries.length} libraries to process:`, - libraries.map((lib) => ({ id: lib.id, repo: lib.repo })) + libraries.map((lib) => ({ id: lib.id, repo: lib.repo })), ) const libraryResults = [] const libraryErrors = [] @@ -68,13 +68,13 @@ export const handler: Handler = async ( const library = libraries[i] if (!library.repo) { console.log( - `[refresh-stats-cache-background] Skipping library ${library.id} - no repo` + `[refresh-stats-cache-background] Skipping library ${library.id} - no repo`, ) continue } console.log( - `[refresh-stats-cache-background] Processing library ${library.id} (${library.repo})...` + `[refresh-stats-cache-background] Processing library ${library.id} (${library.repo})...`, ) try { const repoStats = await fetchGitHubRepoStats(library.repo) @@ -83,11 +83,11 @@ export const handler: Handler = async ( library.repo }: ${repoStats.starCount} stars, ${ repoStats.contributorCount - } contributors, ${repoStats.dependentCount ?? 'N/A'} dependents` + } contributors, ${repoStats.dependentCount ?? 'N/A'} dependents`, ) await setCachedGitHubStats(library.repo, repoStats, 1) console.log( - `[refresh-stats-cache-background] ✓ Successfully cached stats for ${library.repo}` + `[refresh-stats-cache-background] ✓ Successfully cached stats for ${library.repo}`, ) libraryResults.push({ repo: library.repo, @@ -103,7 +103,7 @@ export const handler: Handler = async ( error instanceof Error ? error.message : String(error) console.error( `[refresh-stats-cache-background] Failed to refresh ${library.repo}:`, - errorMessage + errorMessage, ) libraryErrors.push({ repo: library.repo, @@ -118,7 +118,7 @@ export const handler: Handler = async ( Object.keys(npmStats.packageStats || {}).length } packages), GitHub Org: ${githubStats.starCount.toLocaleString()} stars, Libraries: ${ libraryResults.length - } refreshed, ${libraryErrors.length} failed` + } refreshed, ${libraryErrors.length} failed`, ) return { @@ -154,7 +154,7 @@ export const handler: Handler = async ( console.error( `[refresh-stats-cache-background] ✗ Failed after ${duration}ms:`, - errorMessage + errorMessage, ) if (errorStack) { console.error('[refresh-stats-cache-background] Stack:', errorStack) diff --git a/netlify/functions/sync-github-releases-background.ts b/netlify/functions/sync-github-releases-background.ts index c704bc481..a04f6b312 100644 --- a/netlify/functions/sync-github-releases-background.ts +++ b/netlify/functions/sync-github-releases-background.ts @@ -22,10 +22,10 @@ import { syncGitHubReleases } from '~/server/feed/github.functions' */ export const handler: Handler = async ( event: HandlerEvent, - context: HandlerContext + context: HandlerContext, ) => { console.log( - '[sync-github-releases-background] Starting GitHub release sync...' + '[sync-github-releases-background] Starting GitHub release sync...', ) const startTime = Date.now() @@ -35,7 +35,7 @@ export const handler: Handler = async ( const duration = Date.now() - startTime console.log( - `[sync-github-releases-background] ✓ Completed in ${duration}ms - Synced: ${result.syncedCount}, Skipped: ${result.skippedCount}, Errors: ${result.errorCount}` + `[sync-github-releases-background] ✓ Completed in ${duration}ms - Synced: ${result.syncedCount}, Skipped: ${result.skippedCount}, Errors: ${result.errorCount}`, ) return { @@ -57,7 +57,7 @@ export const handler: Handler = async ( console.error( `[sync-github-releases-background] ✗ Failed after ${duration}ms:`, - errorMessage + errorMessage, ) if (errorStack) { console.error('[sync-github-releases-background] Stack:', errorStack) diff --git a/package.json b/package.json index 8723cff61..ea122f81e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "vite build", "start": "vite start", "lint": "eslint --ext .ts,.tsx ./src", - "format": "prettier --write '**/*' --ignore-unknown", + "format": "prettier --experimental-cli --ignore-unknown '**/*' --write", "linkAll": "node scripts/link.js", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", @@ -115,7 +115,7 @@ "eslint-plugin-unicorn": "^49.0.0", "npm-run-all": "^4.1.5", "postcss": "^8.4.35", - "prettier": "^2.8.8", + "prettier": "^3.7.4", "tailwindcss": "^4.1.11", "tsx": "^4.21.0", "typescript": "^5.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8ecd4661..d5f2323eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -289,8 +289,8 @@ importers: specifier: ^8.4.35 version: 8.5.6 prettier: - specifier: ^2.8.8 - version: 2.8.8 + specifier: ^3.7.4 + version: 3.7.4 tailwindcss: specifier: ^4.1.11 version: 4.1.11 @@ -7083,13 +7083,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.7.4: + resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} engines: {node: '>=14'} hasBin: true @@ -11865,7 +11860,7 @@ snapshots: '@tanstack/router-core': 1.139.12 '@tanstack/router-utils': 1.139.0 '@tanstack/virtual-file-routes': 1.139.0 - prettier: 3.6.2 + prettier: 3.7.4 recast: 0.23.11 source-map: 0.7.6 tsx: 4.21.0 @@ -16184,9 +16179,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@2.8.8: {} - - prettier@3.6.2: {} + prettier@3.7.4: {} pretty-format@3.8.0: {} diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 000000000..2c53b10e3 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,10 @@ +// @ts-check + +/** @type {import('prettier').Config} */ +const config = { + semi: false, + singleQuote: true, + trailingComma: 'all', +} + +export default config diff --git a/scripts/migrate-data.md b/scripts/migrate-data.md index 59f4ec79c..582df0dfb 100644 --- a/scripts/migrate-data.md +++ b/scripts/migrate-data.md @@ -7,7 +7,6 @@ This guide covers migrating data from Convex to PostgreSQL (Neon DB). ## Prerequisites 1. **Export Convex Data** - - Use Convex dashboard or CLI to export all tables - Export format: JSON or CSV - Tables to export: @@ -32,18 +31,15 @@ This guide covers migrating data from Convex to PostgreSQL (Neon DB). Create a transformation script that: 1. **Convert Convex IDs to UUIDs** - - Generate new UUIDs for each record - Maintain mapping for foreign key relationships 2. **Transform Timestamps** - - Convex: milliseconds (number) - PostgreSQL: `timestamp with time zone` (Date object) - Convert: `new Date(timestamp)` for milliseconds 3. **Transform Arrays** - - Convex: stored as arrays - PostgreSQL: array columns (already compatible) - Ensure proper formatting @@ -117,7 +113,6 @@ WHERE u.id IS NULL; ``` 2. **Verify functionality**: - - Test authentication flow - Test feed queries - Test admin interfaces diff --git a/src/blog/announcing-tanstack-form-v1.md b/src/blog/announcing-tanstack-form-v1.md index e55750ffa..9e89d163d 100644 --- a/src/blog/announcing-tanstack-form-v1.md +++ b/src/blog/announcing-tanstack-form-v1.md @@ -75,8 +75,8 @@ We even support type-checking what errors are returned in ``: children={(field) => ( <> - // TypeScript will correctly tell you that `errorMap.onChange` // is an object, - not a string + // TypeScript will correctly tell you that `errorMap.onChange` // is an + object, not a string

{field.state.meta.errorMap.onChange}

)} @@ -154,7 +154,7 @@ const serverValidate = createServerValidate({ export const getFormDataFromServer = createServerFn({ method: 'GET' }).handler( async () => { return getFormData() - } + }, ) ``` diff --git a/src/blog/directives-and-the-platform-boundary.md b/src/blog/directives-and-the-platform-boundary.md index 683b17271..0170be024 100644 --- a/src/blog/directives-and-the-platform-boundary.md +++ b/src/blog/directives-and-the-platform-boundary.md @@ -73,7 +73,7 @@ export const action = server( method: 'POST', headers: { 'x-foo': 'bar' }, middleware: [requireAuth()], - } + }, ) ``` @@ -208,7 +208,7 @@ export const sendEmail = workflow( async (input) => { /* ... */ }, - { retries: 3, timeout: '1m' } + { retries: 3, timeout: '1m' }, ) export const handle = step( @@ -216,7 +216,7 @@ export const handle = step( async () => { /* ... */ }, - { cache: 60 } + { cache: 60 }, ) ``` @@ -240,7 +240,7 @@ export const task = workflow( async () => { /* ... */ }, - { retries: 5 } + { retries: 5 }, ) ``` diff --git a/src/blog/tanstack-db-0.5-query-driven-sync.md b/src/blog/tanstack-db-0.5-query-driven-sync.md index 8d7b40d93..ea12adcfb 100644 --- a/src/blog/tanstack-db-0.5-query-driven-sync.md +++ b/src/blog/tanstack-db-0.5-query-driven-sync.md @@ -18,7 +18,7 @@ const { data: projectTodos } = useLiveQuery((q) => .from({ todos }) .join({ projects }, (t, p) => eq(t.projectId, p.id)) .where(({ todos }) => eq(todos.status, 'active')) - .where(({ projects }) => eq(projects.id, 123)) + .where(({ projects }) => eq(projects.id, 123)), ) // ...becomes these precise API calls automatically: @@ -51,7 +51,7 @@ function TodoList({ filter }) { q .from({ todos: todoCollection }) .where(({ todos }) => eq(todos.status, filter)), - [filter] + [filter], ) return todos.map((t) => ) } @@ -115,7 +115,7 @@ const productsCollection = createCollection( return api.getProducts(params) }, syncMode: 'on-demand', // ← New! - }) + }), ) ``` @@ -126,10 +126,10 @@ const { data: electronics } = useLiveQuery((q) => q .from({ product: productsCollection }) .where(({ product }) => - and(eq(product.category, 'electronics'), lt(product.price, 100)) + and(eq(product.category, 'electronics'), lt(product.price, 100)), ) .orderBy(({ product }) => product.price, 'asc') - .limit(10) + .limit(10), ) ``` @@ -158,12 +158,12 @@ Multiple components requesting the same data trigger exactly one network call: ```tsx // Component A const { data: active } = useLiveQuery((q) => - q.from({ todos }).where(({ todos }) => eq(todos.status, 'active')) + q.from({ todos }).where(({ todos }) => eq(todos.status, 'active')), ) // Component B (same query, different component) const { data: active } = useLiveQuery((q) => - q.from({ todos }).where(({ todos }) => eq(todos.status, 'active')) + q.from({ todos }).where(({ todos }) => eq(todos.status, 'active')), ) // Result: ONE network request @@ -205,7 +205,7 @@ const { data } = useLiveQuery((q) => q .from({ todos }) .join({ projects }, (t, p) => eq(t.projectId, p.id)) - .where(({ todos }) => eq(todos.status, 'active')) + .where(({ todos }) => eq(todos.status, 'active')), ) // Network calls: @@ -254,14 +254,14 @@ const todoCollection = createCollection( electricCollectionOptions({ table: 'todos', syncMode: 'progressive', - }) + }), ) // First query loads immediately (on-demand) const { data: urgentTodos } = useLiveQuery((q) => q .from({ todos: todoCollection }) - .where(({ todos }) => eq(todos.priority, 'urgent')) + .where(({ todos }) => eq(todos.priority, 'urgent')), ) // ~100ms: Network request for urgent todos only @@ -299,7 +299,7 @@ We provide helper functions to make this straightforward: queryFn: async (ctx) => { // Parse expression trees into a simple format const { filters, sorts, limit } = parseLoadSubsetOptions( - ctx.meta?.loadSubsetOptions + ctx.meta?.loadSubsetOptions, ) // Map to your REST API's query parameters diff --git a/src/blog/tanstack-router-typescript-performance.md b/src/blog/tanstack-router-typescript-performance.md index 8c3d754dc..06b31a140 100644 --- a/src/blog/tanstack-router-typescript-performance.md +++ b/src/blog/tanstack-router-typescript-performance.md @@ -79,8 +79,11 @@ export type ParseRoute = TRouteTree extends { ? unknown extends TChildren ? TAcc : TChildren extends ReadonlyArray - ? ParseRoute - : ParseRoute + ? ParseRoute + : ParseRoute< + TChildren[keyof TChildren], + TAcc | TChildren[keyof TChildren] + > : TAcc ``` diff --git a/src/components/AILibraryHero.tsx b/src/components/AILibraryHero.tsx index 758ec47de..87b2ffbd4 100644 --- a/src/components/AILibraryHero.tsx +++ b/src/components/AILibraryHero.tsx @@ -178,10 +178,10 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { const currentSelectedService = getStoreState().selectedService const targetService = getRandomIndex( SERVICES.length, - currentSelectedService ?? undefined + currentSelectedService ?? undefined, ) let currentServiceIndex = Math.floor( - Math.random() * SERVICES.length + Math.random() * SERVICES.length, ) const serviceRotationCount = 6 + Math.floor(Math.random() * 3) @@ -213,7 +213,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { setPhase(AnimationPhase.SELECTING_SERVER) const targetServer = getRandomIndex(SERVERS.length) let currentServerIndex = Math.floor( - Math.random() * SERVERS.length + Math.random() * SERVERS.length, ) const serverRotationCount = 8 + Math.floor(Math.random() * 4) @@ -230,7 +230,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { (iteration - (serverRotationCount - 4)) * 50 addTimeoutHelper( () => rotateServer(iteration + 1), - delay + delay, ) } else { // Final iteration - ensure we land on target @@ -313,10 +313,10 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { const chunkSize = 2 + Math.floor(Math.random() * 7) const nextIndex = Math.min( currentIndex + chunkSize, - fullMessage.length + fullMessage.length, ) updateCurrentAssistantMessage( - fullMessage.slice(0, nextIndex) + fullMessage.slice(0, nextIndex), ) currentIndex = nextIndex // Random delay between 20ms and 80ms @@ -368,7 +368,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { const getOpacity = ( index: number, selectedIndex: number | null, - rotatingIndex: number | null + rotatingIndex: number | null, ) => { if (rotatingIndex !== null && rotatingIndex === index) { return 1.0 @@ -391,7 +391,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { const getConnectionOpacity = ( frameworkIndex: number, - serverIndex: number + serverIndex: number, ) => { const isFrameworkSelected = selectedFramework !== null && selectedFramework === frameworkIndex @@ -412,7 +412,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { const getConnectionStrokeColor = ( frameworkIndex: number, - serverIndex: number + serverIndex: number, ) => { // If no selections, ALWAYS return original stroke color (highest priority check) if (selectedFramework === null || selectedServer === null) { @@ -459,7 +459,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { index: number, selectedIndex: number | null, centerX: number, - centerY: number + centerY: number, ) => { if (selectedIndex === index) { return `translate(${centerX}, ${centerY}) scale(1.1) translate(-${centerX}, -${centerY})` @@ -797,7 +797,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 0, selectedFramework, LIBRARY_CARD_LOCATIONS[0] + LIBRARY_CARD_WIDTH / 2, - LIBRARY_CARD_HEIGHT / 2 + LIBRARY_CARD_HEIGHT / 2, )} /> @@ -817,7 +817,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 1, selectedFramework, LIBRARY_CARD_LOCATIONS[1] + LIBRARY_CARD_WIDTH / 2, - LIBRARY_CARD_HEIGHT / 2 + LIBRARY_CARD_HEIGHT / 2, )} /> @@ -837,7 +837,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 2, selectedFramework, LIBRARY_CARD_LOCATIONS[2] + LIBRARY_CARD_WIDTH / 2, - LIBRARY_CARD_HEIGHT / 2 + LIBRARY_CARD_HEIGHT / 2, )} /> @@ -857,7 +857,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 3, selectedFramework, LIBRARY_CARD_LOCATIONS[3] + LIBRARY_CARD_WIDTH / 2, - LIBRARY_CARD_HEIGHT / 2 + LIBRARY_CARD_HEIGHT / 2, )} /> @@ -902,13 +902,13 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { selectedFramework === null || selectedServer === null ? strokeColor : // Only highlight during specific phases - phase === AnimationPhase.SHOWING_CHAT || - phase === AnimationPhase.PULSING_CONNECTIONS || - phase === AnimationPhase.STREAMING_RESPONSE - ? isDark - ? 'rgba(255, 255, 240, 0.95)' - : 'rgba(255, 255, 240, 0.95)' - : strokeColor + phase === AnimationPhase.SHOWING_CHAT || + phase === AnimationPhase.PULSING_CONNECTIONS || + phase === AnimationPhase.STREAMING_RESPONSE + ? isDark + ? 'rgba(255, 255, 240, 0.95)' + : 'rgba(255, 255, 240, 0.95)' + : strokeColor } strokeWidth={ phase === AnimationPhase.PULSING_CONNECTIONS || @@ -930,10 +930,10 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { selectedServer === null ? 0.3 : phase === AnimationPhase.SHOWING_CHAT || - phase === AnimationPhase.PULSING_CONNECTIONS || - phase === AnimationPhase.STREAMING_RESPONSE - ? 1.0 - : 0.3 + phase === AnimationPhase.PULSING_CONNECTIONS || + phase === AnimationPhase.STREAMING_RESPONSE + ? 1.0 + : 0.3 } className={ getConnectionPulse() @@ -966,7 +966,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 0, selectedService, SERVICE_LOCATIONS[0] + SERVICE_WIDTH / 2, - SERVICE_Y_CENTER + SERVICE_Y_CENTER, )} /> @@ -987,7 +987,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 1, selectedService, SERVICE_LOCATIONS[1] + SERVICE_WIDTH / 2, - SERVICE_Y_CENTER + SERVICE_Y_CENTER, )} /> @@ -1008,7 +1008,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 2, selectedService, SERVICE_LOCATIONS[2] + SERVICE_WIDTH / 2, - SERVICE_Y_CENTER + SERVICE_Y_CENTER, )} /> @@ -1028,7 +1028,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 3, selectedService, SERVICE_LOCATIONS[3] + SERVICE_WIDTH / 2, - SERVICE_Y_CENTER + SERVICE_Y_CENTER, )} /> @@ -1050,7 +1050,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 0, selectedServer, SERVER_CARD_LOCATIONS[0] + SERVER_CARD_WIDTH / 2, - SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2 + SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2, )} /> @@ -1071,7 +1071,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 1, selectedServer, SERVER_CARD_LOCATIONS[1] + SERVER_CARD_WIDTH / 2, - SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2 + SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2, )} /> @@ -1091,7 +1091,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 2, selectedServer, SERVER_CARD_LOCATIONS[2] + SERVER_CARD_WIDTH / 2, - SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2 + SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2, )} /> @@ -1111,7 +1111,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) { 3, selectedServer, SERVER_CARD_LOCATIONS[3] + SERVER_CARD_WIDTH / 2, - SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2 + SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2, )} /> diff --git a/src/components/BackgroundGradient.tsx b/src/components/BackgroundGradient.tsx index 6cb3b81ba..a727ba9b9 100644 --- a/src/components/BackgroundGradient.tsx +++ b/src/components/BackgroundGradient.tsx @@ -32,7 +32,7 @@ export function BackgroundGradient() { 'dark:from-gray-300 dark:via-gray-300/30', 'to-transparent', ]), - 'opacity-20 dark:opacity-20' + 'opacity-20 dark:opacity-20', )} /> ) diff --git a/src/components/BottomCTA.tsx b/src/components/BottomCTA.tsx index 9f47b9be7..35bf7b419 100644 --- a/src/components/BottomCTA.tsx +++ b/src/components/BottomCTA.tsx @@ -27,7 +27,7 @@ export function BottomCTA({ {...linkProps} className={twMerge( 'inline-block py-2 px-4 rounded uppercase font-extrabold transition-colors', - className + className, )} > {label} diff --git a/src/components/BrandContextMenu.tsx b/src/components/BrandContextMenu.tsx index dfcf32156..388703d66 100644 --- a/src/components/BrandContextMenu.tsx +++ b/src/components/BrandContextMenu.tsx @@ -33,7 +33,7 @@ export function BrandContextMenu({ children, ...rest }: BrandContextMenuProps) {
SVG markup is now in your clipboard
- + , ) } catch (err) { console.error('Clipboard error', err) @@ -43,7 +43,7 @@ export function BrandContextMenu({ children, ...rest }: BrandContextMenuProps) {
Try again or download directly from the brand guide
- + , ) } } @@ -93,7 +93,7 @@ export function BrandContextMenu({ children, ...rest }: BrandContextMenuProps) { { try { @@ -111,7 +111,7 @@ export function BrandContextMenu({ children, ...rest }: BrandContextMenuProps) { 'p-1 rounded-full', darkBg ? 'bg-black text-white shadow-lg shadow-white/20' - : 'bg-white text-black shadow-lg' + : 'bg-white text-black shadow-lg', )} > {label} diff --git a/src/components/BytesForm.tsx b/src/components/BytesForm.tsx index 31fb6cf16..3e79d33c9 100644 --- a/src/components/BytesForm.tsx +++ b/src/components/BytesForm.tsx @@ -14,7 +14,7 @@ export default function BytesForm() {
Check your email to confirm your subscription
- + , ) } }, [state, notify]) @@ -27,7 +27,7 @@ export default function BytesForm() {
Please try again in a moment
- + , ) } }, [error, notify]) diff --git a/src/components/ChatPanel.tsx b/src/components/ChatPanel.tsx index 56987904f..b82595516 100644 --- a/src/components/ChatPanel.tsx +++ b/src/components/ChatPanel.tsx @@ -106,8 +106,8 @@ export function ChatPanel({ messages, typingUserMessage }: ChatPanelProps) { ? 'text-gray-200' : 'text-gray-900' : isDark - ? 'text-gray-600 italic' - : 'text-gray-400 italic' + ? 'text-gray-600 italic' + : 'text-gray-400 italic' }`} > {typingUserMessage || 'Type a message...'} diff --git a/src/components/CodeExplorer.tsx b/src/components/CodeExplorer.tsx index 4474ec3ba..176fab99e 100644 --- a/src/components/CodeExplorer.tsx +++ b/src/components/CodeExplorer.tsx @@ -121,12 +121,12 @@ export function CodeExplorer({ isEmbedded className={twMerge( 'h-full border-0', - isFullScreen ? 'max-h-[90dvh]' : 'max-h-[80dvh]' + isFullScreen ? 'max-h-[90dvh]' : 'max-h-[80dvh]', )} > {currentCode} diff --git a/src/components/CookieConsent.tsx b/src/components/CookieConsent.tsx index 86ae3b58d..a565bb6df 100644 --- a/src/components/CookieConsent.tsx +++ b/src/components/CookieConsent.tsx @@ -55,7 +55,7 @@ export default function CookieConsent() { if (!consentSettings.analytics && !consentSettings.ads) { try { const response = await fetch( - 'https://www.cloudflare.com/cdn-cgi/trace' + 'https://www.cloudflare.com/cdn-cgi/trace', ) const data = await response.text() const country = data.match(/loc=(\w+)/)?.[1] @@ -212,7 +212,7 @@ export default function CookieConsent() { } localStorage.setItem( 'cookie_consent', - JSON.stringify(updated) + JSON.stringify(updated), ) updateGTMConsent(updated) }} @@ -237,7 +237,7 @@ export default function CookieConsent() { if (typeof document !== 'undefined') { localStorage.setItem( 'cookie_consent', - JSON.stringify(updated) + JSON.stringify(updated), ) } updateGTMConsent(updated) diff --git a/src/components/CopyMarkdownButton.tsx b/src/components/CopyMarkdownButton.tsx index 704134d52..04062db22 100644 --- a/src/components/CopyMarkdownButton.tsx +++ b/src/components/CopyMarkdownButton.tsx @@ -6,7 +6,7 @@ import { type MouseEventHandler, useEffect, useRef } from 'react' import { useToast } from '~/components/ToastProvider' export function useCopyButton( - onCopy: () => void | Promise + onCopy: () => void | Promise, ): [checked: boolean, onClick: MouseEventHandler] { const [checked, setChecked] = useState(false) const timeoutRef = useRef(null) @@ -61,7 +61,7 @@ export function CopyMarkdownButton({
Source content copied from cache
- + , ) }) } else { @@ -81,7 +81,7 @@ export function CopyMarkdownButton({
Source content copied from GitHub
- + , ) }) }) @@ -97,7 +97,7 @@ export function CopyMarkdownButton({
Fallback: copied rendered page content
- + , ) }) }) diff --git a/src/components/CountdownTimer.tsx b/src/components/CountdownTimer.tsx index e44187b7d..09cd1febe 100644 --- a/src/components/CountdownTimer.tsx +++ b/src/components/CountdownTimer.tsx @@ -37,7 +37,7 @@ const formatNumber = (number: number) => number.toString().padStart(2, '0') const Countdown: React.FC = ({ targetDate }) => { const [timeLeft, setTimeLeft] = useState( - calculateTimeLeft(targetDate) + calculateTimeLeft(targetDate), ) useEffect(() => { diff --git a/src/components/CountdownTimerSmall.tsx b/src/components/CountdownTimerSmall.tsx index 1d81f15b4..80e309879 100644 --- a/src/components/CountdownTimerSmall.tsx +++ b/src/components/CountdownTimerSmall.tsx @@ -34,7 +34,7 @@ const formatNumber = (number: number) => number.toString().padStart(2, '0') const Countdown: React.FC = ({ targetDate }) => { const [timeLeft, setTimeLeft] = useState( - calculateTimeLeft(targetDate) + calculateTimeLeft(targetDate), ) useEffect(() => { diff --git a/src/components/Doc.tsx b/src/components/Doc.tsx index 4bc6e9bae..2670e95d5 100644 --- a/src/components/Doc.tsx +++ b/src/components/Doc.tsx @@ -69,7 +69,7 @@ function DocContent({ map[headingElement.target.id] = headingElement return map }, - headingElementRefs.current + headingElementRefs.current, ) const visibleHeadings: Array = [] @@ -92,8 +92,8 @@ function DocContent({ const headingElements = Array.from( markdownContainerRef.current?.querySelectorAll( - 'h2[id], h3[id], h4[id], h5[id], h6[id]' - ) ?? [] + 'h2[id], h3[id], h4[id], h5[id], h6[id]', + ) ?? [], ) headingElements.forEach((el) => observer.observe(el)) @@ -112,13 +112,13 @@ function DocContent({ className={twMerge( 'w-full flex bg-white/70 dark:bg-black/40 mx-auto rounded-xl max-w-[936px]', isTocVisible && 'max-w-full', - shouldRenderToc && 'lg:pt-0' + shouldRenderToc && 'lg:pt-0', )} >
{title ? ( @@ -156,7 +156,7 @@ function DocContent({ 'prose prose-gray dark:prose-invert max-w-none', '[font-size:14px]', isTocVisible && 'pr-2 lg:pr-4 xl:pr-6', - 'styled-markdown-content' + 'styled-markdown-content', )} > diff --git a/src/components/DocContainer.tsx b/src/components/DocContainer.tsx index d53de8d10..b64cf27df 100644 --- a/src/components/DocContainer.tsx +++ b/src/components/DocContainer.tsx @@ -10,7 +10,7 @@ export function DocContainer({ {...props} className={twMerge( 'w-full max-w-full p-2 xl:p-4 2xl:p-8', - props.className + props.className, )} > {children} diff --git a/src/components/DocsLayout.tsx b/src/components/DocsLayout.tsx index 92eaeaf50..d9d6f547b 100644 --- a/src/components/DocsLayout.tsx +++ b/src/components/DocsLayout.tsx @@ -100,7 +100,7 @@ const useMenuConfig = ({ // Merge the two menus together based on their group labels ...config.sections.map((section): MenuItem | undefined => { const frameworkDocs = section.frameworks?.find( - (f) => f.label === currentFramework.framework + (f) => f.label === currentFramework.framework, ) const frameworkItems = frameworkDocs?.children ?? [] @@ -168,14 +168,14 @@ export function DocsLayout({ const flatMenu = React.useMemo( () => menuConfig.flatMap((d) => d?.children), - [menuConfig] + [menuConfig], ) const docsMatch = matches.find((d) => d.pathname.includes('/docs')) const relativePathname = lastMatch.pathname.replace( docsMatch!.pathname + '/', - '' + '', ) const index = flatMenu.findIndex((d) => d?.to === relativePathname) @@ -186,7 +186,7 @@ export function DocsLayout({ const [isFullWidth, setIsFullWidth] = useLocalStorage('docsFullWidth', false) const activePartners = partners.filter( - (d) => d.status === 'active' && d.name !== 'Nozzle.io' + (d) => d.status === 'active' && d.name !== 'Nozzle.io', ) const menuItems = menuConfig.map((group, i) => { @@ -198,7 +198,7 @@ export function DocsLayout({ typeof group.defaultCollapsed !== 'undefined' ? !group.defaultCollapsed // defaultCollapsed is true means the group is closed : undefined - const isOpen = isChildActive ? true : configGroupOpenState ?? false + const isOpen = isChildActive ? true : (configGroupOpenState ?? false) const detailsProps = group.collapsible ? { open: isOpen } : {} @@ -245,7 +245,7 @@ export function DocsLayout({ 'overflow-auto w-full', props.isActive ? `font-bold text-transparent bg-clip-text bg-linear-to-r ${colorFrom} ${colorTo}` - : '' + : '', )} > {/*
*/} @@ -257,7 +257,7 @@ export function DocsLayout({ className={`text-xs ${ props.isActive ? 'opacity-100' : 'opacity-40' } group-hover:opacity-100 font-bold transition-opacity ${getFrameworkTextColor( - child.badge + child.badge, )}`} > {child.badge} @@ -337,7 +337,7 @@ export function DocsLayout({
{children} @@ -433,7 +433,7 @@ export function DocsLayout({ style={{ width: Math.max( 50 + Math.round(200 * partner.score), - 100 + 100, ), }} > diff --git a/src/components/FeedEntry.tsx b/src/components/FeedEntry.tsx index 9f0560761..f5a78cd7e 100644 --- a/src/components/FeedEntry.tsx +++ b/src/components/FeedEntry.tsx @@ -121,7 +121,7 @@ export function FeedEntry({ tag !== 'release:prerelease' && (tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch') + tag === 'release:patch'), ) if (!releaseLevelTag) return null @@ -172,7 +172,7 @@ export function FeedEntry({ setExpanded(!expanded)} > @@ -188,7 +188,7 @@ export function FeedEntry({ {badge.label} @@ -234,7 +234,7 @@ export function FeedEntry({ {releaseLevelBadge.label} diff --git a/src/components/FeedEntryTimeline.tsx b/src/components/FeedEntryTimeline.tsx index 2890a9d6f..127a2d7c7 100644 --- a/src/components/FeedEntryTimeline.tsx +++ b/src/components/FeedEntryTimeline.tsx @@ -97,7 +97,7 @@ export function FeedEntryTimeline({ tag !== 'release:prerelease' && (tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch') + tag === 'release:patch'), ) if (!releaseLevelTag) return null @@ -146,7 +146,7 @@ export function FeedEntryTimeline({ 'bg-white dark:bg-black border border-gray-200 dark:border-gray-800 rounded-lg p-6 transition-all', 'hover:shadow-lg hover:border-gray-300 dark:hover:border-gray-700', entry.featured && - 'bg-yellow-50 dark:bg-yellow-900/10 border-yellow-200 dark:border-yellow-800' + 'bg-yellow-50 dark:bg-yellow-900/10 border-yellow-200 dark:border-yellow-800', )} > {/* Header */} @@ -157,7 +157,7 @@ export function FeedEntryTimeline({ {badge.label} @@ -166,7 +166,7 @@ export function FeedEntryTimeline({ {releaseLevelBadge.label} @@ -277,7 +277,7 @@ export function FeedEntryTimeline({ 'p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors', entry.featured ? 'text-yellow-500' - : 'text-gray-600 dark:text-gray-400' + : 'text-gray-600 dark:text-gray-400', )} title="Toggle Featured" > diff --git a/src/components/FeedFilters.tsx b/src/components/FeedFilters.tsx index 520fb6043..bcd18e9f3 100644 --- a/src/components/FeedFilters.tsx +++ b/src/components/FeedFilters.tsx @@ -192,7 +192,7 @@ export function FeedFilters({ !selectedReleaseLevels || selectedReleaseLevels.length !== defaultReleaseLevels.length || !defaultReleaseLevels.every((level) => - selectedReleaseLevels.includes(level) + selectedReleaseLevels.includes(level), ) const hasActiveFilters = diff --git a/src/components/FeedPageLayout.tsx b/src/components/FeedPageLayout.tsx index d45d61f5c..518a89da5 100644 --- a/src/components/FeedPageLayout.tsx +++ b/src/components/FeedPageLayout.tsx @@ -68,14 +68,14 @@ interface FeedPageLayoutContextValue { } const FeedPageLayoutContext = createContext( - null + null, ) function useFeedPageLayout() { const context = useContext(FeedPageLayoutContext) if (!context) { throw new Error( - 'FeedPageLayout components must be used within FeedPageLayout.Root' + 'FeedPageLayout components must be used within FeedPageLayout.Root', ) } return context @@ -132,7 +132,7 @@ function FeedPageLayoutRoot({ featured: filters.featured, search: filters.search, includeHidden: adminActions !== undefined, // Admin sees all - }) + }), ) return ( diff --git a/src/components/FeedTicker.tsx b/src/components/FeedTicker.tsx index 0c5dc460f..c5b0ef07c 100644 --- a/src/components/FeedTicker.tsx +++ b/src/components/FeedTicker.tsx @@ -83,7 +83,7 @@ export function FeedTicker() { if (isRelease) { // Get release level badge color const releaseLevelTag = entry.tags.find((tag) => - tag.startsWith('release:') + tag.startsWith('release:'), ) const isPrerelease = entry.tags.includes('release:prerelease') const releaseLevel = releaseLevelTag?.replace('release:', '') || '' diff --git a/src/components/FileExplorer.tsx b/src/components/FileExplorer.tsx index bf1d680dc..360864e4d 100644 --- a/src/components/FileExplorer.tsx +++ b/src/components/FileExplorer.tsx @@ -135,7 +135,7 @@ export function FileExplorer({ } } return expanded - } + }, ) const startResizeRef = React.useRef({ @@ -294,7 +294,7 @@ const RenderFileTree = (props: { `px-2 py-1.5 text-left w-full flex items-center gap-2 text-sm rounded transition-colors duration-200 min-w-0`, props.currentPath === file.path ? `${props.libraryColor}/20 text-gray-900 dark:text-white shadow-sm` - : 'hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300' + : 'hover:bg-gray-200 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300', )} > @@ -318,7 +318,7 @@ const RenderFileTree = (props: { function recursiveFlattenGithubContents( nodes: Array, - bannedDirs: Set = new Set() + bannedDirs: Set = new Set(), ): Array { return nodes.flatMap((node) => { if (node.type === 'dir' && node.children && !bannedDirs.has(node.name)) { @@ -329,7 +329,7 @@ function recursiveFlattenGithubContents( } function flattedOnlyToDirs( - nodes: Array + nodes: Array, ): Array { return nodes.flatMap((node) => { if (node.type === 'dir' && node.children) { diff --git a/src/components/FrameworkCard.tsx b/src/components/FrameworkCard.tsx index 2dfb3983c..9b193d082 100644 --- a/src/components/FrameworkCard.tsx +++ b/src/components/FrameworkCard.tsx @@ -28,7 +28,7 @@ export function FrameworkCard({
{packageName} copied to clipboard
-
+
, ) }) @@ -52,7 +52,7 @@ export function FrameworkCard({ 'hover:shadow-xl hover:-translate-y-1', 'flex flex-col gap-4 group', 'min-h-[180px]', - 'relative' + 'relative', )} style={{ zIndex: index, @@ -126,7 +126,7 @@ export function FrameworkCard({ 'absolute bottom-0 left-0 right-0 h-1 rounded-b-xl', 'transition-opacity duration-300', 'opacity-0 group-hover:opacity-100', - framework.color + framework.color, )} />
diff --git a/src/components/FrameworkIconTabs.tsx b/src/components/FrameworkIconTabs.tsx index 54ae6e466..29831e6d6 100644 --- a/src/components/FrameworkIconTabs.tsx +++ b/src/components/FrameworkIconTabs.tsx @@ -18,14 +18,14 @@ export function FrameworkIconTabs({ }: FrameworkIconTabsProps) { const options = React.useMemo( () => getFrameworkOptions(frameworks), - [frameworks] + [frameworks], ) return (
{options.map((opt) => ( diff --git a/src/components/FrameworkSelect.tsx b/src/components/FrameworkSelect.tsx index dcf4fd52e..62572b832 100644 --- a/src/components/FrameworkSelect.tsx +++ b/src/components/FrameworkSelect.tsx @@ -85,7 +85,7 @@ export function useCurrentFramework(frameworks: Framework[]) { }) localCurrentFramework.setCurrentFramework(framework) }, - [localCurrentFramework, navigate] + [localCurrentFramework, navigate], ) React.useEffect(() => { diff --git a/src/components/Gam.tsx b/src/components/Gam.tsx index 580a3270d..e24d359fd 100644 --- a/src/components/Gam.tsx +++ b/src/components/Gam.tsx @@ -19,7 +19,7 @@ declare global { defineSlot: ( path: string, sizes: [number, number][], - id: string + id: string, ) => { addService: (pubads: any) => { setTargeting: (key: string, value: string[]) => void @@ -103,7 +103,7 @@ function GamAd({ className={twMerge( 'absolute inset-0 bg-white/50 dark:bg-black/20 shadow-xl shadow-black/2', borderClassName, - placeholderClassName + placeholderClassName, )} >
@@ -114,7 +114,7 @@ function GamAd({
@@ -125,7 +125,7 @@ function GamAd({
@@ -149,7 +149,7 @@ function GamAd({ } export function GamFooter( - props: Omit, 'name'> + props: Omit, 'name'>, ) { return ( , 'name'> + props: Omit, 'name'>, ) { return } @@ -191,7 +191,7 @@ export function GamVrec1( export function GamHeader( props: React.HTMLAttributes & { adClassName?: string - } + }, ) { return ( diff --git a/src/components/LazySponsorSection.tsx b/src/components/LazySponsorSection.tsx index 3b48518c7..e1e095890 100644 --- a/src/components/LazySponsorSection.tsx +++ b/src/components/LazySponsorSection.tsx @@ -59,7 +59,7 @@ export function LazySponsorSection({ href="https://github.com/sponsors/tannerlinsley" className={twMerge( 'inline-block py-2 px-4 rounded uppercase font-extrabold transition-colors', - ctaClassName + ctaClassName, )} > Become a Sponsor! diff --git a/src/components/LibraryHero.tsx b/src/components/LibraryHero.tsx index 16c75aae2..84f7dfd07 100644 --- a/src/components/LibraryHero.tsx +++ b/src/components/LibraryHero.tsx @@ -29,7 +29,7 @@ export function LibraryHero({ project, cta, actions }: LibraryHeroProps) { 'absolute bottom-0 right-0 translate-y-full', '[letter-spacing:0] text-sm md:text-base font-black lg:text-lg align-super text-white animate-bounce uppercase', 'dark:text-black bg-black dark:bg-white shadow-black/30 px-2 py-1 rounded-md', - 'leading-none whitespace-nowrap' + 'leading-none whitespace-nowrap', )} > {String(project.badge).toUpperCase().trim()} @@ -52,7 +52,7 @@ export function LibraryHero({ project, cta, actions }: LibraryHeroProps) { {...cta.linkProps} className={twMerge( 'inline-block py-2 px-4 rounded uppercase font-extrabold transition-colors', - cta.className + cta.className, )} > {cta.label} diff --git a/src/components/MaintainerCard.tsx b/src/components/MaintainerCard.tsx index fe150a645..a3651f61c 100644 --- a/src/components/MaintainerCard.tsx +++ b/src/components/MaintainerCard.tsx @@ -94,7 +94,7 @@ function LibraryBadge({ library }: { library: Library }) { href={`${library.to}/latest/docs/contributors`} className={twMerge( `inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold text-green-900 dark:text-green-200 capitalize hover:underline focus:outline-none focus:ring-2 focus:ring-blue-400 transition-colors`, - bgClass + bgClass, )} aria-label={`View contributors for ${library.name}`} tabIndex={0} @@ -109,7 +109,7 @@ function LibraryBadge({ library }: { library: Library }) { - (props: HTMLProps) => - ( - - ) + (props: HTMLProps) => ( + + ) const markdownComponents: Record = { a: MarkdownLink, @@ -144,7 +143,7 @@ export function CodeBlock({
         {lang === 'mermaid' ?  : code}
       
- + , ) React[ @@ -175,18 +174,18 @@ export function CodeBlock({ } return output - }) + }), ) setCodeElement(
pre]:h-full [&>pre]:rounded-none' : '' + isEmbedded ? 'h-full [&>pre]:h-full [&>pre]:rounded-none' : '', )} dangerouslySetInnerHTML={{ __html: htmls.join('') }} ref={ref} - /> + />, ) })() }, [code, lang]) @@ -195,7 +194,7 @@ export function CodeBlock({
@@ -205,7 +204,7 @@ export function CodeBlock({ `absolute flex items-stretch bg-white text-sm z-10 rounded-md`, `dark:bg-gray-800 overflow-hidden divide-x divide-gray-500/20`, 'shadow-md', - isEmbedded ? 'top-2 right-4' : '-top-3 right-2' + isEmbedded ? 'top-2 right-4' : '-top-3 right-2', )} > {lang ?
{lang}
: null} @@ -230,7 +229,7 @@ export function CodeBlock({
Code block copied to clipboard
-
+
, ) }} aria-label="Copy code to clipboard" @@ -269,8 +268,8 @@ const getHighlighter = cache(async (language: string, themes: string[]) => { if (!loadedLanguages.includes(language as any)) { promises.push( highlighter.loadLanguage( - language === 'mermaid' ? 'plaintext' : (language as any) - ) + language === 'mermaid' ? 'plaintext' : (language as any), + ), ) } @@ -303,11 +302,11 @@ const options: HTMLReactParserOptions = { const tabs = attributes.tabs const panelElements = domNode.children?.filter( (child): child is Element => - child instanceof Element && child.name === 'md-tab-panel' + child instanceof Element && child.name === 'md-tab-panel', ) const children = panelElements?.map((panel) => - domToReact(panel.children as any, options) + domToReact(panel.children as any, options), ) return @@ -322,7 +321,7 @@ const options: HTMLReactParserOptions = { return React.createElement( replacer, attributesToProps(domNode.attribs), - domToReact(domNode.children as any, options) + domToReact(domNode.children as any, options), ) } } diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index d170c560f..14988106e 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -51,7 +51,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { const height = containerRef.current.offsetHeight document.documentElement.style.setProperty( '--navbar-height', - `${height}px` + `${height}px`, ) } } @@ -157,7 +157,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { className={twMerge( 'w-full p-2 fixed top-0 z-[100] bg-white/70 dark:bg-black/70 backdrop-blur-lg shadow-xl shadow-black/3', 'flex items-center justify-between gap-4', - 'dark:border-b border-gray-500/20' + 'dark:border-b border-gray-500/20', )} ref={containerRef} > @@ -172,7 +172,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { 'transition-all duration-300 h-8 px-2 py-1 lg:px-0', Title ? 'lg:w-9 lg:opacity-100 lg:translate-x-0' - : 'lg:w-0 lg:opacity-0 lg:-translate-x-full' + : 'lg:w-0 lg:opacity-0 lg:-translate-x-full', )} onClick={toggleMenu} onPointerEnter={() => { @@ -187,7 +187,7 @@ export function Navbar({ children }: { children: React.ReactNode }) {
@@ -291,7 +291,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { linkClasses, props.isActive ? 'bg-gray-500/10 dark:bg-gray-500/30' - : '' + : '', )} > {prefix} {' '} {library.badge} @@ -339,7 +339,7 @@ export function Navbar({ children }: { children: React.ReactNode }) {
{library.menu?.map((item, i) => { @@ -349,7 +349,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { key={i} className={twMerge( 'flex gap-2 items-center px-2 ml-2 my-1 py-0.5', - 'rounded-lg hover:bg-gray-500/10 dark:hover:bg-gray-500/30' + 'rounded-lg hover:bg-gray-500/10 dark:hover:bg-gray-500/30', )} > {item.icon} @@ -365,7 +365,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { }} className={twMerge( 'flex gap-2 items-center px-2 ml-2 my-1 py-0.5', - 'rounded-lg hover:bg-gray-500/10 dark:hover:bg-gray-500/30' + 'rounded-lg hover:bg-gray-500/10 dark:hover:bg-gray-500/30', )} > @@ -411,15 +411,15 @@ export function Navbar({ children }: { children: React.ReactNode }) { {capabilities.some((capability) => (['builder', 'admin'] as const).includes( - capability as 'builder' | 'admin' - ) + capability as 'builder' | 'admin', + ), ) ? ( @@ -533,7 +533,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { className={twMerge(linkClasses, 'font-normal')} activeProps={{ className: twMerge( - 'font-bold! bg-gray-500/10 dark:bg-gray-500/30' + 'font-bold! bg-gray-500/10 dark:bg-gray-500/30', ), }} target={item.to.startsWith('http') ? '_blank' : undefined} @@ -603,7 +603,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { : [ 'fixed bg-white/70 dark:bg-black/50 backdrop-blur-lg -translate-x-full', showMenu && 'translate-x-0', - ] + ], )} onPointerEnter={() => { clearTimeout(leaveTimer.current) @@ -628,7 +628,7 @@ export function Navbar({ children }: { children: React.ReactNode }) { className={twMerge( `min-h-[calc(100dvh-var(--navbar-height))] flex flex-col min-w-0 lg:flex-row w-full transition-all duration-300 - pt-[var(--navbar-height)]` + pt-[var(--navbar-height)]`, )} > {smallMenu} diff --git a/src/components/NpmStatsChart.tsx b/src/components/NpmStatsChart.tsx index 8ccaa529c..8410b9fb6 100644 --- a/src/components/NpmStatsChart.tsx +++ b/src/components/NpmStatsChart.tsx @@ -24,7 +24,7 @@ export function NpmStatsChart({ stats }: { stats: NpmStats[] }) { ...d, package: stat.package, date: new Date(d.day), - })) + })), ) const chart = Plot.plot({ diff --git a/src/components/OpenSourceStats.tsx b/src/components/OpenSourceStats.tsx index 799f8c22c..e0a4f32b4 100644 --- a/src/components/OpenSourceStats.tsx +++ b/src/components/OpenSourceStats.tsx @@ -18,7 +18,7 @@ const StableCounter = ({ const dummyString = Number( Array(value?.toString().length ?? 1) .fill('8') - .join('') + .join(''), ) // TODO don't use locale formatting since it can cause a hydration mismatch //.toLocaleString() diff --git a/src/components/PartnersGrid.tsx b/src/components/PartnersGrid.tsx index 7b5c7b05d..aba3e7786 100644 --- a/src/components/PartnersGrid.tsx +++ b/src/components/PartnersGrid.tsx @@ -9,7 +9,7 @@ type PartnersGridProps = { export function PartnersGrid({ partnersList }: PartnersGridProps) { const items = (partnersList ?? allPartners).filter( - (partner) => partner.status === 'active' + (partner) => partner.status === 'active', ) return ( diff --git a/src/components/PartnersSection.tsx b/src/components/PartnersSection.tsx index 07f477e50..cc874ea1e 100644 --- a/src/components/PartnersSection.tsx +++ b/src/components/PartnersSection.tsx @@ -23,7 +23,7 @@ export function PartnersSection({ const filtered = partners.filter((p) => libraryId ? p.libraries?.includes(libraryId as any) && p.status === 'active' - : p.status === 'active' + : p.status === 'active', ) return ( diff --git a/src/components/PlaceholderSponsorPack.tsx b/src/components/PlaceholderSponsorPack.tsx index 924dfe731..d3f39246f 100644 --- a/src/components/PlaceholderSponsorPack.tsx +++ b/src/components/PlaceholderSponsorPack.tsx @@ -38,7 +38,7 @@ export default function PlaceholderSponsorPack() { radius: 0, distance: 0, }), - [sponsors] + [sponsors], ) const root = React.useMemo( @@ -46,9 +46,9 @@ export default function PlaceholderSponsorPack() { hierarchy(pack) .sum((d: any) => 0.0007 + (d.size || 0)) .sort( - (a, b) => ((b.data as any)?.size ?? 0) - ((a.data as any)?.size ?? 0) + (a, b) => ((b.data as any)?.size ?? 0) - ((a.data as any)?.size ?? 0), ), - [pack] + [pack], ) return ( diff --git a/src/components/RedirectVersionBanner.tsx b/src/components/RedirectVersionBanner.tsx index e4ddd349e..4a8f9e8c2 100644 --- a/src/components/RedirectVersionBanner.tsx +++ b/src/components/RedirectVersionBanner.tsx @@ -15,7 +15,7 @@ export function RedirectVersionBanner(props: { const [showModal, setShowModal] = useLocalStorage( 'showRedirectToLatestModal', true, - 1000 * 60 * 24 * 30 + 1000 * 60 * 24 * 30, ) if (!useClientOnlyRender()) { diff --git a/src/components/SearchButton.tsx b/src/components/SearchButton.tsx index 7241bc1c2..fa1c64061 100644 --- a/src/components/SearchButton.tsx +++ b/src/components/SearchButton.tsx @@ -17,7 +17,7 @@ export function SearchButton({ className }: SearchButtonProps) { onClick={openSearch} className={twMerge( 'flex items-center justify-between w-full p-1 pl-2 text-left bg-gray-500/10 dark:bg-gray-500/20 rounded-lg opacity-80 hover:opacity-100 transition-opacity duration-300 gap-2', - className + className, )} >
diff --git a/src/components/SearchModal.tsx b/src/components/SearchModal.tsx index 9788a178e..a19e88bd9 100644 --- a/src/components/SearchModal.tsx +++ b/src/components/SearchModal.tsx @@ -21,7 +21,7 @@ import { capitalize } from '~/utils/utils' const searchClient = liteClient( 'FQ0DQ6MA3C', - '10c34d6a5c89f6048cf644d601e65172' + '10c34d6a5c89f6048cf644d601e65172', ) const SafeLink = React.forwardRef( @@ -36,7 +36,7 @@ const SafeLink = React.forwardRef( tabIndex, ...props }: React.AnchorHTMLAttributes, - ref: React.Ref + ref: React.Ref, ) => { const isInternal = href?.includes('//tanstack.com') @@ -72,7 +72,7 @@ const SafeLink = React.forwardRef( {children} ) - } + }, ) const Hit = ({ hit, isFocused }: { hit: any; isFocused?: boolean }) => { @@ -104,7 +104,7 @@ const Hit = ({ hit, isFocused }: { hit: any; isFocused?: boolean }) => { href={hit.url} className={twMerge( 'block p-4 focus:outline-none border-b border-gray-500/10', - isFocused ? 'bg-gray-500/20' : 'hover:bg-gray-500/10' + isFocused ? 'bg-gray-500/20' : 'hover:bg-gray-500/10', )} onKeyDown={handleKeyDown} onFocus={() => ref.current?.focus()} @@ -129,7 +129,7 @@ const Hit = ({ hit, isFocused }: { hit: any; isFocused?: boolean }) => { >

- ) : null + ) : null, )} {hit.content ? (

@@ -139,7 +139,7 @@ const Hit = ({ hit, isFocused }: { hit: any; isFocused?: boolean }) => {

{(() => { const framework = frameworkOptions.find((f) => - hit.url.includes(`/framework/${f.value}`) + hit.url.includes(`/framework/${f.value}`), ) if (!framework) return null @@ -174,7 +174,7 @@ function LibraryRefinement() { React.useEffect(() => { const isAlreadyRefined = items.some( - (item) => item.label === subpathname && item.isRefined + (item) => item.label === subpathname && item.isRefined, ) const library = libraries.find((l) => l.id === subpathname) @@ -204,7 +204,7 @@ function LibraryRefinement() { ? library ? library.bgStyle : 'bg-black dark:bg-white' - : 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700' + : 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700', )} > {capitalize(item.label)}{' '} @@ -244,7 +244,7 @@ function FrameworkRefinement() { if (!subpathname) return const isAlreadyRefined = items.some( - (item) => item.value === subpathname && item.isRefined + (item) => item.value === subpathname && item.isRefined, ) const framework = frameworkOptions.find((f) => f.value === subpathname) @@ -263,7 +263,7 @@ function FrameworkRefinement() {
{items.map((item) => { const framework = frameworkOptions.find( - (f) => f.value === item.value + (f) => f.value === item.value, ) return ( @@ -274,7 +274,7 @@ function FrameworkRefinement() { 'px-2 py-0.5 text-xs rounded-full transition-colors font-bold text-white', item.isRefined ? framework?.color || 'bg-black dark:bg-white' - : 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700' + : 'bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700', )} > {capitalize(item.label)}{' '} @@ -474,7 +474,7 @@ function SearchResults({ focusedIndex }: { focusedIndex: number }) { { const index = results.hits.findIndex( - (h) => h.objectID === hit.objectID + (h) => h.objectID === hit.objectID, ) return }} @@ -486,7 +486,7 @@ function SearchResults({ focusedIndex }: { focusedIndex: number }) { '[&>ul]:w-full [&>ul]:flex [&>ul]:justify-center [&>ul]:gap-2 lg:[&>ul]:gap-4', '[&_li>*]:px-3 [&_li>*]:py-1.5', '[&_li>span]:cursor-not-allowed', - '[&_.ais-Pagination-item--selected>*]:bg-emerald-500 [&_.ais-Pagination-item--selected>*]:text-white [&_.ais-Pagination-item--selected>*]:rounded-lg' + '[&_.ais-Pagination-item--selected>*]:bg-emerald-500 [&_.ais-Pagination-item--selected>*]:text-white [&_.ais-Pagination-item--selected>*]:rounded-lg', )} />
diff --git a/src/components/SponsorPack.tsx b/src/components/SponsorPack.tsx index 985690924..83ce0955c 100644 --- a/src/components/SponsorPack.tsx +++ b/src/components/SponsorPack.tsx @@ -20,7 +20,7 @@ export default function SponsorPack({ radius: 0, distance: 0, }), - [sponsors] + [sponsors], ) const root = React.useMemo( @@ -28,7 +28,7 @@ export default function SponsorPack({ hierarchy(pack) .sum((d) => 0.0007 + d.size) .sort((a, b) => (b.data.size ?? 0) - (a.data.size ?? 0)), - [pack] + [pack], ) return ( @@ -119,7 +119,7 @@ export default function SponsorPack({ : `right-1/4 translate-x-full`, tooltipY == 'top' ? `top-1/4 -translate-y-full` - : `bottom-1/4 translate-y-full` + : `bottom-1/4 translate-y-full`, )} >

diff --git a/src/components/SponsorsSection.tsx b/src/components/SponsorsSection.tsx index ea0c40d15..82af89e72 100644 --- a/src/components/SponsorsSection.tsx +++ b/src/components/SponsorsSection.tsx @@ -41,7 +41,7 @@ export function SponsorsSection({ href="https://github.com/sponsors/tannerlinsley" className={twMerge( 'inline-block py-2 px-4 rounded uppercase font-extrabold transition-colors', - ctaClassName + ctaClassName, )} > Become a Sponsor! diff --git a/src/components/TableComponents.tsx b/src/components/TableComponents.tsx index c469d12d9..f798db1a4 100644 --- a/src/components/TableComponents.tsx +++ b/src/components/TableComponents.tsx @@ -73,8 +73,8 @@ export function TableHeaderCell({ align === 'right' ? 'text-right' : align === 'center' - ? 'text-center' - : 'text-left' + ? 'text-center' + : 'text-left' const paddingClass = compact ? 'px-2 py-1.5' : 'px-4 py-2' const textSizeClass = compact ? 'text-[10px]' : 'text-xs' return ( @@ -139,8 +139,8 @@ export function TableCell({ align === 'right' ? 'text-right' : align === 'center' - ? 'text-center' - : 'text-left' + ? 'text-center' + : 'text-left' const paddingClass = compact ? 'px-2 py-2' : 'px-4 py-3' return ( tabs.find((tab) => tab.slug === framework)?.slug || tabs[0].slug + () => tabs.find((tab) => tab.slug === framework)?.slug || tabs[0].slug, ) return ( diff --git a/src/components/ThemeProvider.tsx b/src/components/ThemeProvider.tsx index 93bb3b332..3aa1e03f7 100644 --- a/src/components/ThemeProvider.tsx +++ b/src/components/ThemeProvider.tsx @@ -52,7 +52,7 @@ const updateThemeClass = createClientOnlyFn((themeMode: ThemeMode) => { if (metaThemeColor) { metaThemeColor.setAttribute( 'content', - newTheme === 'dark' ? THEME_COLORS.dark : THEME_COLORS.light + newTheme === 'dark' ? THEME_COLORS.dark : THEME_COLORS.light, ) } }) diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx index bee92928c..9bad36163 100644 --- a/src/components/ThemeToggle.tsx +++ b/src/components/ThemeToggle.tsx @@ -6,7 +6,7 @@ export function ThemeToggle() { const { toggleMode } = useTheme() const handleToggleMode = ( - e: React.MouseEvent + e: React.MouseEvent, ) => { e.preventDefault() e.stopPropagation() diff --git a/src/components/ToastProvider.tsx b/src/components/ToastProvider.tsx index 9d2045446..e34d4889e 100644 --- a/src/components/ToastProvider.tsx +++ b/src/components/ToastProvider.tsx @@ -39,7 +39,7 @@ export function ToastProvider({ setToasts((prev) => [...prev, { id, content, durationMs }]) return id }, - [] + [], ) const removeToast = React.useCallback((id: string) => { @@ -48,7 +48,7 @@ export function ToastProvider({ const contextValue = React.useMemo( () => ({ notify }), - [notify] + [notify], ) return ( diff --git a/src/components/Toc.tsx b/src/components/Toc.tsx index c9790d9ea..11c11a632 100644 --- a/src/components/Toc.tsx +++ b/src/components/Toc.tsx @@ -33,7 +33,7 @@ export function Toc({

+
, ) } finally { setIsLoading(false) diff --git a/src/routes/_libraries/blog.$.tsx b/src/routes/_libraries/blog.$.tsx index d1d4b6a04..e8dd6b23d 100644 --- a/src/routes/_libraries/blog.$.tsx +++ b/src/routes/_libraries/blog.$.tsx @@ -51,7 +51,7 @@ const fetchBlogPost = createServerFn({ method: 'GET' }) 'cache-control': 'public, max-age=0, must-revalidate', 'cdn-cache-control': 'max-age=300, stale-while-revalidate=300, durable', 'Netlify-Vary': 'query=payload', - }) + }), ) return { @@ -75,7 +75,7 @@ export const Route = createFileRoute('/_libraries/blog/$')({ // Use Netlify Image CDN to optimize for social media (1200x630 is the standard for og:image) const netlifyImageUrl = `https://tanstack.com/.netlify/images?url=${encodeURIComponent( - headerImage + headerImage, )}&w=1200&h=630&fit=cover&fm=jpg&q=80` return netlifyImageUrl } @@ -107,7 +107,7 @@ function BlogPost() { const blogContent = `_by ${formatAuthors(authors)} on ${format( new Date(published || 0), - 'MMM dd, yyyy' + 'MMM dd, yyyy', )}._ ${content}` @@ -168,7 +168,7 @@ ${content}` className={twMerge( 'prose prose-gray dark:prose-invert max-w-none', '[font-size:14px]', - 'styled-markdown-content' + 'styled-markdown-content', )} > diff --git a/src/routes/_libraries/blog.index.tsx b/src/routes/_libraries/blog.index.tsx index b76d42da7..c0f33c5f5 100644 --- a/src/routes/_libraries/blog.index.tsx +++ b/src/routes/_libraries/blog.index.tsx @@ -36,7 +36,7 @@ const fetchFrontMatters = createServerFn({ method: 'GET' }).handler( // 'Cache-Control': 'public, max-age=300, s-maxage=3600', // }, // }) - } + }, ) export const Route = createFileRoute('/_libraries/blog/')({ diff --git a/src/routes/_libraries/brand-guide.tsx b/src/routes/_libraries/brand-guide.tsx index b78db4216..78b908be0 100644 --- a/src/routes/_libraries/brand-guide.tsx +++ b/src/routes/_libraries/brand-guide.tsx @@ -49,7 +49,7 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) {
Try again or use Copy URL
-
+ , ) } } @@ -60,13 +60,13 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) { bg === 'dark' ? 'bg-black/80 text-white' : bg === 'light' - ? 'bg-white text-black' - : 'bg-gray-500/20' + ? 'bg-white text-black' + : 'bg-gray-500/20', )} >
{asset} @@ -98,7 +98,7 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) {
Asset URL is now in your clipboard
-
+ , ) } catch (err) { console.error('Failed to copy asset URL', err) @@ -108,7 +108,7 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) {
Try again or download directly from the brand guide
- + , ) } }} @@ -131,7 +131,7 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) {
SVG markup is now in your clipboard
- + , ) } catch (err) { console.error('Failed to copy SVG', err) @@ -141,7 +141,7 @@ function AssetCard({ title, description, asset, url, bg }: AssetCardProps) {
Try again or download directly from the brand guide
- + , ) } }} @@ -251,7 +251,7 @@ function RouteComponent() { ], }, ], - [] + [], ) return (
diff --git a/src/routes/_libraries/feed.$id.tsx b/src/routes/_libraries/feed.$id.tsx index e2ab223f7..e422b102a 100644 --- a/src/routes/_libraries/feed.$id.tsx +++ b/src/routes/_libraries/feed.$id.tsx @@ -19,7 +19,7 @@ export const Route = createFileRoute('/_libraries/feed/$id')({ // Fetch the feed entry by id const entry = await queryClient.ensureQueryData( - getFeedEntryByIdQueryOptions(entryId) + getFeedEntryByIdQueryOptions(entryId), ) if (!entry) { @@ -185,7 +185,7 @@ function FeedEntryView({ entry }: { entry: FeedEntry }) { tag !== 'release:prerelease' && (tag === 'release:major' || tag === 'release:minor' || - tag === 'release:patch') + tag === 'release:patch'), ) if (!releaseLevelTag) return null @@ -252,7 +252,7 @@ function FeedEntryView({ entry }: { entry: FeedEntry }) { className={twMerge( 'bg-white dark:bg-black border border-gray-200 dark:border-gray-800 rounded-lg p-4 lg:p-6', entry.featured && - 'bg-yellow-50 dark:bg-yellow-900/10 border-yellow-200 dark:border-yellow-800' + 'bg-yellow-50 dark:bg-yellow-900/10 border-yellow-200 dark:border-yellow-800', )} > {/* Header */} @@ -262,7 +262,7 @@ function FeedEntryView({ entry }: { entry: FeedEntry }) { {badge.label} @@ -271,7 +271,7 @@ function FeedEntryView({ entry }: { entry: FeedEntry }) { {releaseLevelBadge.label} diff --git a/src/routes/_libraries/feed.index.tsx b/src/routes/_libraries/feed.index.tsx index c323f2ac6..0a117435a 100644 --- a/src/routes/_libraries/feed.index.tsx +++ b/src/routes/_libraries/feed.index.tsx @@ -81,7 +81,7 @@ export const Route = createFileRoute('/_libraries/feed/')({ featured: deps.featured, search: deps.search, }, - }) + }), ) }, headers: () => ({ diff --git a/src/routes/_libraries/index.tsx b/src/routes/_libraries/index.tsx index 3c54a2d62..a20b6fdf1 100644 --- a/src/routes/_libraries/index.tsx +++ b/src/routes/_libraries/index.tsx @@ -55,7 +55,7 @@ const fetchRecentPosts = createServerFn({ method: 'GET' }).handler(async () => { 'cache-control': 'public, max-age=0, must-revalidate', 'cdn-cache-control': 'max-age=300, stale-while-revalidate=300, durable', 'Netlify-Vary': 'query=payload', - }) + }), ) return allPosts @@ -227,7 +227,7 @@ function Index() { 'hover:shadow-2xl hover:shadow-current/20 hover:border-current/50 hover:-translate-y-1', 'relative group', 'min-h-[250px] xl:min-h-[220px]', - library.cardStyles + library.cardStyles, )} style={{ zIndex: i, @@ -244,7 +244,7 @@ function Index() { return (
- ) + ), )}
@@ -423,7 +423,7 @@ function Index() { dateTime={published} title={format( new Date(published), - 'MMM dd, yyyy' + 'MMM dd, yyyy', )} > {' '} @@ -447,7 +447,7 @@ function Index() { ) - } + }, )}
@@ -626,7 +626,7 @@ function Index() {
Check your email to confirm your subscription
-
+ , ) } else if (bytesSignupMutation.status === 'error') { notify( @@ -635,7 +635,7 @@ function Index() {
Please try again in a moment
- + , ) } }} diff --git a/src/routes/_libraries/maintainers.tsx b/src/routes/_libraries/maintainers.tsx index 8c73d9d18..2c98ae898 100644 --- a/src/routes/_libraries/maintainers.tsx +++ b/src/routes/_libraries/maintainers.tsx @@ -310,7 +310,7 @@ function MaintainersFilter({
{selectedLibraries?.map((libraryId) => { const library = availableLibraries.find( - (lib) => lib.id === libraryId + (lib) => lib.id === libraryId, ) const bgStyle = library?.bgStyle ?? 'bg-gray-500' @@ -360,8 +360,8 @@ function MaintainerGrid({ viewMode === 'compact' ? 'grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 gap-6' : viewMode === 'row' - ? 'flex flex-col gap-4' - : 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6' + ? 'flex flex-col gap-4' + : 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6' }`} > {maintainers.map((maintainer, index) => ( @@ -422,19 +422,19 @@ function RouteComponent() { const maintainerLibraries = getPersonsMaintainerOf(maintainer) return ( maintainerLibraries.some((lib) => - search.libraries!.includes(lib.id as Library['id']) + search.libraries!.includes(lib.id as Library['id']), ) || maintainer.creatorOf?.some((lib) => - search.libraries!.includes(lib) + search.libraries!.includes(lib), ) || maintainer.maintainerOf?.some((lib) => - search.libraries!.includes(lib) + search.libraries!.includes(lib), ) || maintainer.contributorOf?.some((lib) => - search.libraries!.includes(lib) + search.libraries!.includes(lib), ) || maintainer.consultantOf?.some((lib) => - search.libraries!.includes(lib) + search.libraries!.includes(lib), ) ) }) @@ -453,11 +453,11 @@ function RouteComponent() { // Sort by role priority within filtered libraries, then core status, then original order const aPriority = getRolePriorityForFilteredLibraries( a, - search.libraries + search.libraries, ) const bPriority = getRolePriorityForFilteredLibraries( b, - search.libraries + search.libraries, ) if (aPriority !== bPriority) { @@ -467,11 +467,11 @@ function RouteComponent() { // Same role priority - use core maintainer status for filtered libraries const aIsCore = getIsCoreMaintainerForFilteredLibraries( a, - search.libraries + search.libraries, ) const bIsCore = getIsCoreMaintainerForFilteredLibraries( b, - search.libraries + search.libraries, ) if (aIsCore && !bIsCore) return -1 @@ -506,29 +506,29 @@ function RouteComponent() { switch (search.groupBy) { case 'core': const coreMaintainers = filteredMaintainers.filter( - (m) => m.isCoreMaintainer + (m) => m.isCoreMaintainer, ) const regularMaintainers = filteredMaintainers.filter( (m) => !m.isCoreMaintainer && ((m.creatorOf && m.creatorOf.length > 0) || - (m.maintainerOf && m.maintainerOf.length > 0)) + (m.maintainerOf && m.maintainerOf.length > 0)), ) const regularContributors = filteredMaintainers.filter( (m) => !m.isCoreMaintainer && (!m.creatorOf || m.creatorOf.length === 0) && - (!m.maintainerOf || m.maintainerOf.length === 0) + (!m.maintainerOf || m.maintainerOf.length === 0), ) // Sort by original order within each group const sortByOriginalOrder = (group: Maintainer[]) => { return group.sort((a, b) => { const aIndex = allMaintainers.findIndex( - (m) => m.github === a.github + (m) => m.github === a.github, ) const bIndex = allMaintainers.findIndex( - (m) => m.github === b.github + (m) => m.github === b.github, ) return aIndex - bIndex }) @@ -579,10 +579,10 @@ function RouteComponent() { const uniqueMaintainers = [...new Set(maintainers)] const sortedMaintainers = uniqueMaintainers.sort((a, b) => { const aIndex = allMaintainers.findIndex( - (m) => m.github === a.github + (m) => m.github === a.github, ) const bIndex = allMaintainers.findIndex( - (m) => m.github === b.github + (m) => m.github === b.github, ) // Get library ID for this group @@ -612,25 +612,25 @@ function RouteComponent() { case 'role': const creators = filteredMaintainers.filter( - (m) => getRoleForFilteredLibraries(m, search.libraries) === 'creator' + (m) => getRoleForFilteredLibraries(m, search.libraries) === 'creator', ) const libraryMaintainers = filteredMaintainers.filter( (m) => - getRoleForFilteredLibraries(m, search.libraries) === 'maintainer' + getRoleForFilteredLibraries(m, search.libraries) === 'maintainer', ) const libraryContributors = filteredMaintainers.filter( (m) => - getRoleForFilteredLibraries(m, search.libraries) === 'contributor' + getRoleForFilteredLibraries(m, search.libraries) === 'contributor', ) // Sort each role group: core maintainers first, then by original order const sortRoleGroup = (group: Maintainer[]) => { return group.sort((a, b) => { const aIndex = allMaintainers.findIndex( - (m) => m.github === a.github + (m) => m.github === a.github, ) const bIndex = allMaintainers.findIndex( - (m) => m.github === b.github + (m) => m.github === b.github, ) // Core maintainers first within each role diff --git a/src/routes/_libraries/paid-support.tsx b/src/routes/_libraries/paid-support.tsx index a7e015a80..708780368 100644 --- a/src/routes/_libraries/paid-support.tsx +++ b/src/routes/_libraries/paid-support.tsx @@ -26,7 +26,7 @@ export const Route = createFileRoute('/_libraries/paid-support')({ function PaidSupportComp() { const [viewMode, setViewMode] = useState<'compact' | 'full' | 'row'>( - 'compact' + 'compact', ) return ( @@ -101,8 +101,8 @@ function PaidSupportComp() { viewMode === 'compact' ? 'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3' : viewMode === 'row' - ? 'flex flex-col gap-4' - : 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6' + ? 'flex flex-col gap-4' + : 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6' }`} > {coreMaintainers.map((maintainer, index) => ( diff --git a/src/routes/_libraries/partners.tsx b/src/routes/_libraries/partners.tsx index bd97cdcb8..a69d2a313 100644 --- a/src/routes/_libraries/partners.tsx +++ b/src/routes/_libraries/partners.tsx @@ -171,7 +171,7 @@ function PartnersFilter({ onClick={() => { // Toggle: if currently inactive, turn off filter, otherwise set to inactive onStatusChange( - selectedStatus === 'active' ? undefined : 'active' + selectedStatus === 'active' ? undefined : 'active', ) }} className={`px-3 py-2 rounded-md text-sm transition-colors ${ @@ -186,7 +186,9 @@ function PartnersFilter({ onClick={() => { // Toggle: if currently inactive, turn off filter, otherwise set to inactive onStatusChange( - selectedStatus === 'inactive' ? undefined : 'inactive' + selectedStatus === 'inactive' + ? undefined + : 'inactive', ) }} className={`px-3 py-2 rounded-md text-sm transition-colors ${ @@ -239,7 +241,7 @@ function PartnersFilter({ {/* Library chips */} {selectedLibraries?.map((libraryId) => { const library = availableLibraries.find( - (lib) => lib.id === libraryId + (lib) => lib.id === libraryId, ) return ( 0) { // Include partners that match any of the selected libraries return partner.libraries?.some((lib) => - search.libraries!.includes(lib as Library['id']) + search.libraries!.includes(lib as Library['id']), ) } @@ -312,15 +314,15 @@ function RouteComp() { {isShowingPrevious ? 'Previous Partners' : isShowingActive - ? 'Current Partners' - : 'Partners'} + ? 'Current Partners' + : 'Partners'}

{isShowingPrevious ? 'Companies and organizations that have supported TanStack in the past' : isShowingActive - ? 'Companies and organizations currently supporting TanStack and our open source mission' - : 'Companies and organizations supporting TanStack and our open source mission'} + ? 'Companies and organizations currently supporting TanStack and our open source mission' + : 'Companies and organizations supporting TanStack and our open source mission'}

diff --git a/src/routes/_libraries/query.$version.index.tsx b/src/routes/_libraries/query.$version.index.tsx index c99019016..f0f5ad0f2 100644 --- a/src/routes/_libraries/query.$version.index.tsx +++ b/src/routes/_libraries/query.$version.index.tsx @@ -77,7 +77,7 @@ function VersionIndex() { className={twMerge( `group bg-white/60 dark:bg-black/40 rounded-lg overflow-hidden shadow-xl max-w-full mx-auto - [&_pre]:bg-transparent! [&_pre]:p-4!` + [&_pre]:bg-transparent! [&_pre]:p-4!`, )} >
diff --git a/src/routes/_libraries/workshops.tsx b/src/routes/_libraries/workshops.tsx index defb50f0d..a5c758d92 100644 --- a/src/routes/_libraries/workshops.tsx +++ b/src/routes/_libraries/workshops.tsx @@ -47,7 +47,7 @@ function WorkshopsPage() { const { seed } = Route.useLoaderData() // Calculate instructors on client side using the seed const availableInstructors = allMaintainers.filter( - (m) => m.workshopsAvailable + (m) => m.workshopsAvailable, ) const shuffled = shuffleWithSeed(availableInstructors, seed, (m) => m.name) const instructors = shuffled.slice(0, 4) as Maintainer[] @@ -525,7 +525,7 @@ function TestimonialsMarquee() {
{testimonial.company}
- ) + ), )} diff --git a/src/routes/admin/feed.$id.tsx b/src/routes/admin/feed.$id.tsx index 7908fd97c..932040afb 100644 --- a/src/routes/admin/feed.$id.tsx +++ b/src/routes/admin/feed.$id.tsx @@ -73,7 +73,7 @@ function FeedEditorPage() {
navigate({ to: '/admin/feed' })} onCancel={() => navigate({ to: '/admin/feed' })} /> diff --git a/src/routes/admin/feed.index.tsx b/src/routes/admin/feed.index.tsx index b2373701c..3df092bcc 100644 --- a/src/routes/admin/feed.index.tsx +++ b/src/routes/admin/feed.index.tsx @@ -62,7 +62,7 @@ export const Route = createFileRoute('/admin/feed/')({ ? z .array(releaseLevelSchema) .catch( - Array.isArray(releaseLevelsValue) ? releaseLevelsValue : [] + Array.isArray(releaseLevelsValue) ? releaseLevelsValue : [], ) : z .array(releaseLevelSchema) @@ -113,7 +113,7 @@ function FeedAdminPage() { const handleToggleVisibility = async ( entry: FeedEntry, - isVisible: boolean + isVisible: boolean, ) => { await toggleVisibility.mutateAsync({ id: entry.id, isVisible }) feedQuery.refetch() diff --git a/src/routes/admin/github-stats.tsx b/src/routes/admin/github-stats.tsx index cf864fed0..1fb873416 100644 --- a/src/routes/admin/github-stats.tsx +++ b/src/routes/admin/github-stats.tsx @@ -296,7 +296,7 @@ function GitHubStatsAdmin() { }, }, ], - [refreshingKey, refreshAllMutation] + [refreshingKey, refreshAllMutation], ) const table = useReactTable({ @@ -360,7 +360,7 @@ function GitHubStatsAdmin() { {error.cacheKey}:{' '} {error.error}
- ) + ), )}
@@ -389,7 +389,7 @@ function GitHubStatsAdmin() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} diff --git a/src/routes/admin/npm-stats.tsx b/src/routes/admin/npm-stats.tsx index dd89f7f3a..9e0e560c5 100644 --- a/src/routes/admin/npm-stats.tsx +++ b/src/routes/admin/npm-stats.tsx @@ -135,7 +135,7 @@ function NpmStatsAdmin() { ), }, ], - [] + [], ) const packageColumns = useMemo[]>( @@ -255,7 +255,7 @@ function NpmStatsAdmin() { ), }, ], - [refreshPackageMutation] + [refreshPackageMutation], ) const libraryTable = useReactTable({ @@ -443,7 +443,7 @@ function NpmStatsAdmin() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -457,7 +457,7 @@ function NpmStatsAdmin() { {flexRender( cell.column.columnDef.cell, - cell.getContext() + cell.getContext(), )} ))} @@ -500,7 +500,7 @@ function NpmStatsAdmin() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -514,7 +514,7 @@ function NpmStatsAdmin() { {flexRender( cell.column.columnDef.cell, - cell.getContext() + cell.getContext(), )} ))} diff --git a/src/routes/admin/roles.$roleId.tsx b/src/routes/admin/roles.$roleId.tsx index 9ec4209a9..d7a95c4c9 100644 --- a/src/routes/admin/roles.$roleId.tsx +++ b/src/routes/admin/roles.$roleId.tsx @@ -65,7 +65,7 @@ function RoleDetailPage() { alert( error instanceof Error ? error.message - : 'Failed to remove users from role' + : 'Failed to remove users from role', ) } }, [selectedUserIds, roleId, removeUsersFromRole]) @@ -80,7 +80,7 @@ function RoleDetailPage() { } setSelectedUserIds(newSelection) }, - [selectedUserIds] + [selectedUserIds], ) const toggleAllSelection = useCallback(() => { @@ -202,7 +202,7 @@ function RoleDetailPage() { }, }, ], - [selectedUserIds, usersWithRole, toggleAllSelection, toggleUserSelection] + [selectedUserIds, usersWithRole, toggleAllSelection, toggleUserSelection], ) const table = useReactTable({ @@ -303,7 +303,7 @@ function RoleDetailPage() { onClick={() => { if ( window.confirm( - `Remove ${selectedUserIds.size} user(s) from this role?` + `Remove ${selectedUserIds.size} user(s) from this role?`, ) ) { handleRemoveUsers() @@ -345,7 +345,7 @@ function RoleDetailPage() { alert( error instanceof Error ? error.message - : 'Failed to remove user' + : 'Failed to remove user', ) } }} @@ -373,7 +373,7 @@ function RoleDetailPage() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -394,7 +394,7 @@ function RoleDetailPage() { {flexRender( cell.column.columnDef.cell, - cell.getContext() + cell.getContext(), )} ))} diff --git a/src/routes/admin/roles.index.tsx b/src/routes/admin/roles.index.tsx index f1d917fb9..005f9cde6 100644 --- a/src/routes/admin/roles.index.tsx +++ b/src/routes/admin/roles.index.tsx @@ -68,7 +68,7 @@ function RolesPage() { const capabilityFilters = useMemo( () => Array.isArray(search.cap) ? search.cap : search.cap ? [search.cap] : [], - [search.cap] + [search.cap], ) const [expandedSections, setExpandedSections] = useState< @@ -183,7 +183,7 @@ function RolesPage() { const availableCapabilities = useMemo( () => ['admin', 'disableAds', 'builder', 'feed'], - [] + [], ) const handleCreateRole = useCallback(() => { @@ -256,20 +256,20 @@ function RolesPage() { alert(error instanceof Error ? error.message : 'Failed to delete role') } }, - [deleteRole] + [deleteRole], ) const toggleCapability = useCallback( (capability: string) => { if (editingCapabilities.includes(capability)) { setEditingCapabilities( - editingCapabilities.filter((c: string) => c !== capability) + editingCapabilities.filter((c: string) => c !== capability), ) } else { setEditingCapabilities([...editingCapabilities, capability]) } }, - [editingCapabilities] + [editingCapabilities], ) const handleCapabilityFilterToggle = useCallback( @@ -285,7 +285,7 @@ function RolesPage() { }), }) }, - [capabilityFilters, navigate] + [capabilityFilters, navigate], ) // Define columns using the column helper @@ -441,7 +441,7 @@ function RolesPage() { handleEditRole, handleDeleteRole, toggleCapability, - ] + ], ) // Create table instance @@ -619,7 +619,7 @@ function RolesPage() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -641,7 +641,7 @@ function RolesPage() { > {flexRender( cell.column.columnDef.cell, - cell.getContext() + cell.getContext(), )} ))} diff --git a/src/routes/admin/users.tsx b/src/routes/admin/users.tsx index 5d2720ea4..d3b19a63f 100644 --- a/src/routes/admin/users.tsx +++ b/src/routes/admin/users.tsx @@ -203,7 +203,7 @@ function UsersPage() { const capabilityFilters = useMemo( () => Array.isArray(search.cap) ? search.cap : search.cap ? [search.cap] : [], - [search.cap] + [search.cap], ) const noCapabilitiesFilter = search.noCapabilities ?? false const adsDisabledFilter = search.ads ?? 'all' @@ -429,7 +429,7 @@ function UsersPage() { // Bulk fetch user roles and effective capabilities to avoid N+1 queries const userIds = useMemo( () => (usersQuery?.data?.page || []).map((u: User) => u._id), - [usersQuery?.data?.page] + [usersQuery?.data?.page], ) const bulkUserRolesQuery = useQuery({ ...getBulkUserRolesQueryOptions(userIds), @@ -444,7 +444,7 @@ function UsersPage() { const availableCapabilities = useMemo( () => ['admin', 'disableAds', 'builder', 'feed'], - [] + [], ) const handleEditUser = useCallback((user: User) => { @@ -518,13 +518,13 @@ function UsersPage() { (capability: string) => { if (editingCapabilities.includes(capability)) { setEditingCapabilities( - editingCapabilities.filter((c) => c !== capability) + editingCapabilities.filter((c) => c !== capability), ) } else { setEditingCapabilities([...editingCapabilities, capability]) } }, - [editingCapabilities] + [editingCapabilities], ) const toggleRole = useCallback( @@ -535,7 +535,7 @@ function UsersPage() { setEditingRoleIds([...editingRoleIds, roleId]) } }, - [editingRoleIds] + [editingRoleIds], ) const toggleUserSelection = useCallback( @@ -548,7 +548,7 @@ function UsersPage() { } setSelectedUserIds(newSelection) }, - [selectedUserIds] + [selectedUserIds], ) const toggleAllSelection = useCallback(() => { @@ -582,7 +582,7 @@ function UsersPage() { if ( !window.confirm( - `Update capabilities for ${selectedUserIds.size} user(s)?` + `Update capabilities for ${selectedUserIds.size} user(s)?`, ) ) { return @@ -599,11 +599,11 @@ function UsersPage() { alert( error instanceof Error ? error.message - : 'Failed to update capabilities' + : 'Failed to update capabilities', ) } }, - [selectedUserIds, bulkUpdateUserCapabilities] + [selectedUserIds, bulkUpdateUserCapabilities], ) const handleToggleAdsDisabled = useCallback( @@ -613,7 +613,7 @@ function UsersPage() { adsDisabled: nextValue, }) }, - [adminSetAdsDisabled] + [adminSetAdsDisabled], ) const handleCapabilityToggle = useCallback( @@ -630,7 +630,7 @@ function UsersPage() { }), }) }, - [capabilityFilters, navigate] + [capabilityFilters, navigate], ) // Define columns using the column helper @@ -869,7 +869,7 @@ function UsersPage() { usersQuery, bulkUserRoles, bulkEffectiveCapabilities, - ] + ], ) // Pagination state @@ -1043,7 +1043,7 @@ function UsersPage() { ? null : flexRender( header.column.columnDef.header, - header.getContext() + header.getContext(), )} ))} @@ -1065,7 +1065,7 @@ function UsersPage() { > {flexRender( cell.column.columnDef.cell, - cell.getContext() + cell.getContext(), )} ))} @@ -1092,7 +1092,7 @@ function UsersPage() { currentPage={currentPageIndex} totalPages={Math.max( 1, - Math.ceil((usersQuery?.data?.counts?.filtered ?? 0) / pageSize) + Math.ceil((usersQuery?.data?.counts?.filtered ?? 0) / pageSize), )} totalItems={usersQuery?.data?.counts?.total ?? 0} filteredItems={usersQuery?.data?.counts?.filtered} diff --git a/src/routes/auth/$provider/start.tsx b/src/routes/auth/$provider/start.tsx index 69cba1669..ce6e74144 100644 --- a/src/routes/auth/$provider/start.tsx +++ b/src/routes/auth/$provider/start.tsx @@ -24,7 +24,7 @@ export const Route = createFileRoute('/auth/$provider/start')({ // Store state in HTTPS-only cookie for CSRF protection // SameSite=Strict prevents CSRF attacks const stateCookie = `oauth_state=${encodeURIComponent( - state + state, )}; HttpOnly; Path=/; Max-Age=${10 * 60}; SameSite=Strict${ process.env.NODE_ENV === 'production' ? '; Secure' : '' }` @@ -41,9 +41,9 @@ export const Route = createFileRoute('/auth/$provider/start')({ throw new Error('GITHUB_OAUTH_CLIENT_ID is not configured') } authUrl = `https://github.com/login/oauth/authorize?client_id=${encodeURIComponent( - clientId + clientId, )}&redirect_uri=${encodeURIComponent( - redirectUri + redirectUri, )}&scope=user:email&state=${state}` } else { // Google @@ -52,9 +52,9 @@ export const Route = createFileRoute('/auth/$provider/start')({ throw new Error('GOOGLE_OAUTH_CLIENT_ID is not configured') } authUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${encodeURIComponent( - clientId + clientId, )}&redirect_uri=${encodeURIComponent( - redirectUri + redirectUri, )}&response_type=code&scope=openid email profile&state=${state}` } diff --git a/src/routes/libraries.tsx b/src/routes/libraries.tsx index 0dc34b8c4..c4e1e33ca 100644 --- a/src/routes/libraries.tsx +++ b/src/routes/libraries.tsx @@ -22,7 +22,7 @@ export const Route = createFileRoute('/libraries')({ function LibrariesPage() { const allLibraries = libraries.filter((d) => d.to) const others = allLibraries.filter( - (l) => l.id !== 'ranger' && l.id !== 'config' && l.id !== 'react-charts' + (l) => l.id !== 'ranger' && l.id !== 'config' && l.id !== 'react-charts', ) const ranger = allLibraries.filter((l) => l.id === 'ranger') const config = allLibraries.filter((l) => l.id === 'config') @@ -63,7 +63,7 @@ function LibrariesPage() { : 'border-gray-200 dark:border-gray-800/50 hover:shadow-2xl hover:shadow-current/20 hover:border-current/50 hover:-translate-y-1', 'relative group', 'min-h-[250px] xl:min-h-[220px]', - !isRanger && library.cardStyles + !isRanger && library.cardStyles, )} style={{ zIndex: i, @@ -75,7 +75,7 @@ function LibrariesPage() {
@@ -109,7 +109,7 @@ function LibrariesPage() { `text-sm italic font-medium mt-3`, isRanger ? 'text-slate-500 dark:text-slate-400' - : 'text-current' + : 'text-current', )} > {library.tagline} @@ -162,7 +162,7 @@ function LibrariesPage() { className={twMerge( `absolute -top-2 -right-2 z-40 px-2 py-1 rounded-md`, ['bg-gradient-to-r', library.colorFrom, library.colorTo], - 'uppercase text-white font-black italic text-xs' + 'uppercase text-white font-black italic text-xs', )} style={{ animation: 'pulseScale 3s infinite', @@ -198,7 +198,7 @@ function LibrariesPage() {
Shop {item.name} diff --git a/src/routes/partners-embed.tsx b/src/routes/partners-embed.tsx index c6db14278..1774b9ecc 100644 --- a/src/routes/partners-embed.tsx +++ b/src/routes/partners-embed.tsx @@ -21,7 +21,7 @@ export const Route = createFileRoute('/partners-embed')({ function PartnersEmbed() { const activePartners = partners.filter( - (partner) => partner.status === 'active' + (partner) => partner.status === 'active', ) return ( diff --git a/src/routes/stats/npm/-comparisons.ts b/src/routes/stats/npm/-comparisons.ts index a86fa9397..e6413f376 100644 --- a/src/routes/stats/npm/-comparisons.ts +++ b/src/routes/stats/npm/-comparisons.ts @@ -5,7 +5,7 @@ export const packageGroupSchema = z.object({ z.object({ name: z.string(), hidden: z.boolean().optional(), - }) + }), ), color: z.string().nullable().optional(), baseline: z.boolean().optional(), diff --git a/src/routes/stats/npm/index.tsx b/src/routes/stats/npm/index.tsx index 97b42cfc4..9c07a353c 100644 --- a/src/routes/stats/npm/index.tsx +++ b/src/routes/stats/npm/index.tsx @@ -142,10 +142,13 @@ const binningOptions = [ }, ] as const -const binningOptionsByType = binningOptions.reduce((acc, option) => { - acc[option.value] = option - return acc -}, {} as Record) +const binningOptionsByType = binningOptions.reduce( + (acc, option) => { + acc[option.value] = option + return acc + }, + {} as Record, +) type TransformMode = z.infer @@ -232,11 +235,11 @@ function npmQueryOptions({ // Get the earliest creation date among all packages const getEarliestCreationDate = async () => { const packageNames = packageGroups.flatMap((pkg) => - pkg.packages.filter((p) => !p.hidden).map((p) => p.name) + pkg.packages.filter((p) => !p.hidden).map((p) => p.name), ) const creationDates = await Promise.all( - packageNames.map(getPackageCreationDate) + packageNames.map(getPackageCreationDate), ) return new Date(Math.min(...creationDates.map((date) => date.getTime()))) } @@ -298,7 +301,7 @@ function npmQueryOptions({ const chunks = await Promise.all( chunkRanges.map(async (chunk) => { const url = `https://api.npmjs.org/downloads/range/${formatDate( - chunk.start + chunk.start, )}:${formatDate(chunk.end)}/${pkg.name}` const response = await fetch(url) if (!response.ok) { @@ -308,7 +311,7 @@ function npmQueryOptions({ throw new Error('fetch_failed') } return response.json() - }) + }), ) // Combine all chunks and ensure no gaps @@ -316,7 +319,7 @@ function npmQueryOptions({ .flatMap((chunk) => chunk.downloads || []) .sort( (a, b) => - new Date(a.day).getTime() - new Date(b.day).getTime() + new Date(a.day).getTime() - new Date(b.day).getTime(), ) // Find the earliest non-zero download @@ -326,7 +329,7 @@ function npmQueryOptions({ } return { ...pkg, downloads } - }) + }), ) return { @@ -351,7 +354,7 @@ function npmQueryOptions({ : 'Failed to fetch package data (see console for details)', } } - }) + }), ) }, placeholderData: keepPreviousData, @@ -361,11 +364,11 @@ function npmQueryOptions({ // Get or assign colors for packages function getPackageColor( packageName: string, - packages: z.infer[] + packages: z.infer[], ) { // Find the package group that contains this package const packageInfo = packages.find((pkg) => - pkg.packages.some((p) => p.name === packageName) + pkg.packages.some((p) => p.name === packageName), ) if (packageInfo?.color) { return packageInfo.color @@ -373,7 +376,7 @@ function getPackageColor( // Otherwise, assign a default color based on the package's position const packageIndex = packages.findIndex((pkg) => - pkg.packages.some((p) => p.name === packageName) + pkg.packages.some((p) => p.name === packageName), ) return defaultColors[packageIndex % defaultColors.length] } @@ -513,7 +516,7 @@ function NpmStatsChart({ // Filter out any sub packages that are hidden before // summing them into a unified downloads count const visiblePackages = packageGroup.packages.filter( - (p, i) => !i || !p.hidden + (p, i) => !i || !p.hidden, ) const downloadsByDate: Map = new Map() @@ -527,7 +530,7 @@ function NpmStatsChart({ downloadsByDate.set( date.getTime(), // Sum the downloads for each date - (downloadsByDate.get(date.getTime()) || 0) + d.downloads + (downloadsByDate.get(date.getTime()) || 0) + d.downloads, ) }) }) @@ -535,7 +538,7 @@ function NpmStatsChart({ return { ...packageGroup, downloads: Array.from(downloadsByDate.entries()).map( - ([date, downloads]) => [d3.utcDay(new Date(date)), downloads] + ([date, downloads]) => [d3.utcDay(new Date(date)), downloads], ) as [Date, number][], } }) @@ -547,9 +550,9 @@ function NpmStatsChart({ d3.rollup( packageGroup.downloads, (v) => d3.sum(v, (d) => d[1]), - (d) => binUnit.floor(d[0]) + (d) => binUnit.floor(d[0]), ), - (d) => d[0] + (d) => d[0], ) const downloads = binned.map((d) => ({ @@ -581,7 +584,7 @@ function NpmStatsChart({ d.date.getTime(), firstValue === 0 ? 1 : firstValue / d.downloads, ] - }) + }), ) })() : undefined @@ -607,7 +610,7 @@ function NpmStatsChart({ // Filter out any top-level hidden packages const filteredPackageData = correctedPackageData.filter( - (pkg) => !pkg.baseline && !pkg.packages[0].hidden + (pkg) => !pkg.baseline && !pkg.packages[0].hidden, ) const plotData = filteredPackageData.flatMap((d) => d.downloads) @@ -657,7 +660,7 @@ function NpmStatsChart({ strokeDasharray: '2 4', strokeOpacity: 0.8, curve: 'monotone-x', - } + }, ), ], Plot.lineY( @@ -667,7 +670,7 @@ function NpmStatsChart({ stroke: 'name', strokeWidth: 2, curve: 'monotone-x', - } + }, ), Plot.tip( effectiveShowDataMode === 'all' @@ -684,7 +687,7 @@ function NpmStatsChart({ year: 'numeric', }), }, - } as Plot.TipOptions) + } as Plot.TipOptions), ), ].filter(Boolean), x: { @@ -696,15 +699,15 @@ function NpmStatsChart({ transform === 'normalize-y' ? 'Downloads Growth' : baselinePackage - ? 'Downloads (baseline-adjusted)' - : 'Downloads', + ? 'Downloads (baseline-adjusted)' + : 'Downloads', labelOffset: 35, }, grid: true, color: { domain: [...new Set(plotData.map((d) => d.name))], range: [...new Set(plotData.map((d) => d.name))].map((pkg) => - getPackageColor(pkg, packages) + getPackageColor(pkg, packages), ), legend: false, }, @@ -755,12 +758,12 @@ function PackageSearch({ const response = await fetch( `https://api.npms.io/v2/search?q=${encodeURIComponent( - debouncedInputValue - )}&size=10` + debouncedInputValue, + )}&size=10`, ) const data = await response.json() const hasInputValue = data.results.find( - (r: any) => r.package.name === debouncedInputValue + (r: any) => r.package.name === debouncedInputValue, ) return [ @@ -862,7 +865,7 @@ const defaultRangeBinTypes: Record = { // Add a function to check if a binning option is valid for a time range function isBinningOptionValidForRange( range: TimeRange, - binType: BinType + binType: BinType, ): boolean { switch (range) { case '7-days': @@ -908,7 +911,7 @@ function RouteComponent() { height = 400, } = Route.useSearch() const [combiningPackage, setCombiningPackage] = React.useState( - null + null, ) const navigate = Route.useNavigate() const [colorPickerPackage, setColorPickerPackage] = React.useState< @@ -919,7 +922,7 @@ function RouteComponent() { y: number } | null>(null) const [openMenuPackage, setOpenMenuPackage] = React.useState( - null + null, ) const binType = binTypeParam ?? defaultRangeBinTypes[range] @@ -978,10 +981,10 @@ function RouteComponent() { ? { ...pkg, packages: pkg.packages.map((p) => - p.name === packageName ? { ...p, hidden: !p.hidden } : p + p.name === packageName ? { ...p, hidden: !p.hidden } : p, ), } - : pkg + : pkg, ), }), replace: true, @@ -993,7 +996,7 @@ function RouteComponent() { npmQueryOptions({ packageGroups: packageGroups, range, - }) + }), ) const handleCombineSelect = (selectedPackage: NpmPackage) => { @@ -1001,7 +1004,7 @@ function RouteComponent() { // Find the package group that contains the combining package const packageGroup = packageGroups.find((pkg) => - pkg.packages.some((p) => p.name === combiningPackage) + pkg.packages.some((p) => p.name === combiningPackage), ) if (packageGroup) { @@ -1015,7 +1018,7 @@ function RouteComponent() { { name: selectedPackage.name, hidden: true }, ], } - : pkg + : pkg, ) navigate({ @@ -1052,19 +1055,19 @@ function RouteComponent() { const handleRemoveFromGroup = (mainPackage: string, subPackage: string) => { // Find the package group const packageGroup = packageGroups.find((pkg) => - pkg.packages.some((p) => p.name === mainPackage) + pkg.packages.some((p) => p.name === mainPackage), ) if (!packageGroup) return // Remove the subpackage const updatedPackages = packageGroup.packages.filter( - (p) => p.name !== subPackage + (p) => p.name !== subPackage, ) // Update the packages array const newPackages = packageGroups .map((pkg) => - pkg === packageGroup ? { ...pkg, packages: updatedPackages } : pkg + pkg === packageGroup ? { ...pkg, packages: updatedPackages } : pkg, ) .filter((pkg) => pkg.packages.length > 0) @@ -1084,7 +1087,7 @@ function RouteComponent() { search: (prev) => ({ ...prev, packageGroups: prev.packageGroups.filter( - (_, i) => i !== packageGroupIndex + (_, i) => i !== packageGroupIndex, ), }), resetScroll: false, @@ -1139,7 +1142,7 @@ function RouteComponent() { to: '.', search: (prev) => { const packageGroup = packageGroups.find((pkg) => - pkg.packages.some((p) => p.name === packageName) + pkg.packages.some((p) => p.name === packageName), ) if (!packageGroup) return prev @@ -1148,7 +1151,7 @@ function RouteComponent() { ? color === null ? { packages: pkg.packages } : { ...pkg, color } - : pkg + : pkg, ) return { @@ -1162,7 +1165,7 @@ function RouteComponent() { }, { wait: 100, - } + }, ) const onHeightChange = useThrottledCallback( @@ -1175,7 +1178,7 @@ function RouteComponent() { }, { wait: 16, - } + }, ) const handleMenuOpenChange = (packageName: string, open: boolean) => { @@ -1229,7 +1232,7 @@ function RouteComponent() { // Find the package group that contains the combining package const packageGroup = packageGroups.find((pkg) => - pkg.packages.some((p) => p.name === combiningPackage) + pkg.packages.some((p) => p.name === combiningPackage), ) if (packageGroup) { @@ -1240,7 +1243,7 @@ function RouteComponent() { ...pkg, packages: [...pkg.packages, { name: packageName }], } - : pkg + : pkg, ) navigate({ @@ -1297,7 +1300,7 @@ function RouteComponent() { className={twMerge( 'w-full px-2 py-1.5 text-left text-sm rounded hover:bg-gray-500/20 flex items-center gap-2 outline-none cursor-pointer', value === range ? 'text-blue-500 bg-blue-500/10' : '', - 'data-highlighted:bg-gray-500/20 data-highlighted:text-blue-500' + 'data-highlighted:bg-gray-500/20 data-highlighted:text-blue-500', )} > {label} @@ -1311,7 +1314,7 @@ function RouteComponent() {