Skip to content

Commit fe2b27e

Browse files
committed
new architecture wip
1 parent afca578 commit fe2b27e

58 files changed

Lines changed: 709 additions & 3673 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/components/About.astro

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/components/BottomMenu.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/components/CMSList.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { useCallback, useMemo } from 'react'
2+
import type { Product } from '../utils/productsSchema'
3+
import { ProductLogo } from './ProductLogo'
4+
import { useProducts } from '../hooks/useProducts'
5+
import { VirtualizedTable } from './VirtualizedTable'
6+
import type { ColumnDef } from '@tanstack/react-table'
7+
import { cmsProductPricingSortingFn, getCMSProductPricingPreview } from '../utils/cmsProductPricing'
8+
9+
const useProductHelpers = () => {
10+
const getPricingDisplay = useCallback((product: Product) => getCMSProductPricingPreview(product), [])
11+
12+
const getHeadquarters = useCallback((product: Product) => {
13+
if (Array.isArray(product.headquarters)) {
14+
if (product.headquarters.length > 1) {
15+
return `${product.headquarters[0]} (+${product.headquarters.length - 1})`
16+
}
17+
return product.headquarters[0]
18+
}
19+
return product.headquarters
20+
}, [])
21+
22+
const getScreensDisplay = useCallback((product: Product) => {
23+
const screensTotal = product.stats?.screens?.total
24+
if (screensTotal && typeof screensTotal === 'number') {
25+
return screensTotal
26+
}
27+
return '-'
28+
}, [])
29+
30+
return { getPricingDisplay, getHeadquarters, getScreensDisplay }
31+
}
32+
33+
const useTableColumns = () => {
34+
const { getPricingDisplay, getHeadquarters, getScreensDisplay } = useProductHelpers()
35+
36+
return useMemo<ColumnDef<Product>[]>(
37+
() => [
38+
{
39+
header: 'Product',
40+
accessorKey: 'name',
41+
size: 500,
42+
sortingFn: 'alphanumeric',
43+
cell: ({ row }) => {
44+
const product = row.original
45+
return (
46+
<a
47+
href={product.website}
48+
target="_blank"
49+
rel="noopener nofollow ugc"
50+
className="flex items-center gap-3 group"
51+
>
52+
<ProductLogo product={product} />
53+
<div className="flex flex-col">
54+
<div className="flex items-center gap-2 font-medium text-gray-900 group-hover:text-blue-600">
55+
{product.name}
56+
</div>
57+
{product.description && (
58+
<div className="text-sm text-gray-500 mt-1 max-w-md">
59+
{product.description}
60+
</div>
61+
)}
62+
</div>
63+
</a>
64+
)
65+
},
66+
},
67+
{
68+
header: 'Pricing per screen',
69+
accessorFn: (row) => getPricingDisplay(row),
70+
size: 200,
71+
sortingFn: cmsProductPricingSortingFn,
72+
cell: ({ getValue }) => (
73+
<span className="text-sm text-gray-600">{getValue() as string}</span>
74+
),
75+
},
76+
{
77+
header: 'Signup',
78+
accessorFn: (row) => row.self_signup ? 'Self-signup' : 'On request',
79+
size: 150,
80+
cell: ({ getValue }) => (
81+
<span className="text-sm text-gray-600">{getValue() as string}</span>
82+
),
83+
},
84+
{
85+
header: 'Headquarters',
86+
accessorFn: (row) => getHeadquarters(row),
87+
size: 200,
88+
cell: ({ getValue }) => (
89+
<span className="text-sm text-gray-600">{getValue() as string}</span>
90+
),
91+
},
92+
{
93+
header: 'Screens',
94+
accessorFn: (row) => getScreensDisplay(row),
95+
size: 150,
96+
sortingFn: 'alphanumeric',
97+
cell: ({ getValue }) => (
98+
<span className="text-sm text-gray-600">{ `${(getValue() as number) > 0 ? (getValue() as number).toLocaleString() + '+' : '-'}` }</span>
99+
),
100+
},
101+
],
102+
[getPricingDisplay, getHeadquarters, getScreensDisplay]
103+
)
104+
}
105+
106+
export const CMSList = () => {
107+
const products = useProducts()
108+
const columns = useTableColumns()
109+
110+
return (
111+
<VirtualizedTable
112+
data={products}
113+
columns={columns}
114+
initialSorting={[{ id: 'name', desc: false }]}
115+
/>
116+
)
117+
}

src/components/CategoryFilter.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { useStore } from '@nanostores/react'
2+
import { productFilters, setCategoryFilter } from '../stores/productFilters'
3+
import type { ProductCategory } from '../utils/productsSchema'
4+
import { products } from '../utils/products'
5+
import { useMemo } from 'react'
6+
import { filterProducts } from '../utils/filterProducts'
7+
8+
export const CategoryFilter = () => {
9+
const filters = useStore(productFilters)
10+
11+
const allCategories: ProductCategory[] = ['CMS', 'Content provider']
12+
13+
const categoryCounts = useMemo(() => {
14+
return allCategories.reduce((acc, category) => {
15+
acc[category] = filterProducts(products, { ...filters, category }).length
16+
return acc
17+
}, {} as Record<ProductCategory, number>)
18+
}, [filters.searchTerm, filters.showOpenSource, filters.showProprietary])
19+
20+
const handleCategoryClick = (category: ProductCategory) => {
21+
setCategoryFilter(category)
22+
}
23+
24+
return (
25+
<div className="flex flex-col space-y-4">
26+
<div className="flex flex-wrap gap-2">
27+
{allCategories.map((category) => (
28+
<button
29+
key={category}
30+
onClick={() => handleCategoryClick(category)}
31+
className={`px-4 py-2 rounded-lg font-medium text-sm transition-all duration-200 border border-gray-300 hover:border-gray-400 ${
32+
filters.category === category
33+
? 'bg-blue-500 text-white border-blue-500'
34+
: 'bg-white text-gray-700 hover:bg-gray-50'
35+
}`}
36+
>
37+
{category} ({categoryCounts[category]})
38+
</button>
39+
))}
40+
</div>
41+
</div>
42+
)
43+
}

src/components/CollectionHeader.astro

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/components/FilterSync.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { useFilterSync } from '../hooks/useFilterSync'
2+
3+
export const FilterSync = () => {
4+
useFilterSync()
5+
return null
6+
}

src/components/FilteredList.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/components/FilteredProductsCount.tsx

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/components/FiltersModalButton.tsx

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/components/GlobalStats.tsx

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)