From 97c9710ce332cfa722fcec31f84fbdbc4a275fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Wed, 31 Aug 2022 14:28:02 +0200 Subject: [PATCH] docs(showcase): add 74 new showcase sites (#8010) --- website/src/data/__tests__/user.test.ts | 61 ++ website/src/data/users.tsx | 613 +++++++++++++++++- .../_components/ShowcaseCard/index.tsx | 12 +- 3 files changed, 674 insertions(+), 12 deletions(-) diff --git a/website/src/data/__tests__/user.test.ts b/website/src/data/__tests__/user.test.ts index 06f76b53d1cb..8dfcdd1874c2 100644 --- a/website/src/data/__tests__/user.test.ts +++ b/website/src/data/__tests__/user.test.ts @@ -7,6 +7,7 @@ import fs from 'fs-extra'; import path from 'path'; +import _ from 'lodash'; import imageSize from 'image-size'; import {Joi} from '@docusaurus/utils-validation'; import {TagList, sortedUsers, type User} from '../users'; @@ -62,6 +63,7 @@ describe('users data', () => { // The preview should be jest/emptyModule preview: Joi.object({default: Joi.any()}) .unknown(false) + .allow(null) .required() .messages({ 'object.base': @@ -87,6 +89,65 @@ describe('users data', () => { ); } }); + + it('does not contain duplicates', () => { + function normalizeUrl(url: string | null) { + if (url === null) { + return null; + } + if (!url.endsWith('/')) { + return `${url}/`; + } + return url; + } + + function duplicatesBy(mapper: (user: User) => string | null) { + const grouped: {[key: string]: User[]} = _.groupBy(sortedUsers, (user) => + mapper(user), + ); + return Object.fromEntries( + Object.entries(grouped).filter((entry) => entry[1].length > 1), + ); + } + + let duplicatesLog = ''; + + const duplicatesByTitle = duplicatesBy((user) => + user.title.trim().toLowerCase(), + ); + Object.entries(duplicatesByTitle).forEach(([title, users]) => { + duplicatesLog += `Showcase site title '${title}' is used ${users.length} times! Duplicates are not allowed!\n`; + }); + + const duplicatesByDescription = duplicatesBy((user) => + user.description.trim().toLowerCase(), + ); + Object.entries(duplicatesByDescription).forEach(([description, users]) => { + duplicatesLog += `Showcase site description '${description}' is used ${users.length} times! Duplicates are not allowed!\n`; + }); + + const duplicatesByWebsite = duplicatesBy((user) => + normalizeUrl(user.website), + ); + Object.entries(duplicatesByWebsite).forEach(([website, users]) => { + duplicatesLog += `Showcase site website url '${website}' is used ${users.length} times! Duplicates are not allowed!\n`; + }); + + const duplicatesBySource = duplicatesBy((user) => + normalizeUrl(user.source), + ); + Object.entries(duplicatesBySource).forEach(([source, users]) => { + // source is allowed to be null for multiple sites + // "null", see Lodash groupBy issue: https://github.com/lodash/lodash/issues/3060 + if (source && source !== 'null') { + duplicatesLog += `Showcase site source url '${source}' is used ${users.length} times! Duplicates are not allowed!\n`; + } + }); + + if (duplicatesLog) { + throw new Error(duplicatesLog); + } + }); }); describe('preview images', () => { diff --git a/website/src/data/users.tsx b/website/src/data/users.tsx index c48c6ffcda13..79fe70548aec 100644 --- a/website/src/data/users.tsx +++ b/website/src/data/users.tsx @@ -100,8 +100,7 @@ const Users: User[] = [ 'The best search experience for docs, integrates in minutes, for free', preview: require('./showcase/algolia.png'), website: 'https://docsearch.algolia.com/', - source: - 'https://github.com/algolia/docsearch/tree/main/packages/website', + source: 'https://github.com/algolia/docsearch/tree/main/packages/website', tags: ['favorite', 'opensource', 'product'], }, { @@ -445,7 +444,8 @@ const Users: User[] = [ }, { title: 'difranca | Tech-Notes', - description: 'This documentation aims to comprise my learning notes on various tech subjects.', + description: + 'This documentation aims to comprise my learning notes on various tech subjects.', preview: require('./showcase/difranca-technotes.png'), website: 'https://difranca.github.io/', source: 'https://github.com/difranca/difranca.github.io', @@ -1185,8 +1185,7 @@ const Users: User[] = [ }, { title: 'Mixcore CMS', - description: - 'Fully Open Source ASP.Net Core / Dotnet Core CMS UI Toolkit', + description: 'Fully Open Source ASP.Net Core / Dotnet Core CMS UI Toolkit', preview: require('./showcase/mixcore.png'), website: 'https://docs.mixcore.org/', source: 'https://github.com/mixcore/docs/tree/master/website', @@ -1833,7 +1832,7 @@ const Users: User[] = [ title: 'Resoto', description: 'Open-source cloud infrastructure management tool—find leaky resources, manage quota limits, detect drift, and clean up!', - preview: require('./showcase/resoto.png'), + preview: null, website: 'https://resoto.com', source: 'https://github.com/someengineering/resoto.com', tags: ['opensource', 'product', 'design'], @@ -2195,7 +2194,7 @@ const Users: User[] = [ preview: require('./showcase/tauri.png'), website: 'https://tauri.app/', source: 'https://github.com/tauri-apps/tauri-docs', - tags: ['opensource', 'i18n', 'product', 'design'] + tags: ['opensource', 'i18n', 'product', 'design'], }, { title: 'TechHarvesting', @@ -2259,12 +2258,11 @@ const Users: User[] = [ }, { title: 'Tremor', - description: - 'Early-stage event processing system for unstructured data with structural pattern-matching, filtering and transformation', + description: 'Tremor Event Processing Engine', preview: require('./showcase/tremor.png'), website: 'https://www.tremor.rs/', source: 'https://github.com/tremor-rs/tremor-www', - tags: ['opensource', 'versioning'], + tags: ['opensource', 'versioning','large'], }, { title: 'TRPG Engine', @@ -2433,6 +2431,599 @@ const Users: User[] = [ source: 'https://github.com/7Wate/wiki', tags: ['opensource', 'personal'], }, + { + title: 'Discord API Types', + description: 'Discord API Types', + preview: null, + website: 'https://discord-api-types.dev/', + source: 'https://github.com/discordjs/discord-api-types/tree/main/website', + tags: ['opensource', 'versioning', 'large'], + }, + { + title: 'Hanabi', + description: 'A list of Hanabi card game strategies', + preview: null, + website: 'https://hanabi.github.io/', + source: 'https://github.com/hanabi/hanabi.github.io', + tags: ['opensource'], + }, + { + title: 'IsaacScript', + description: 'Write Binding of Isaac: Repentance mods with TypeScript', + preview: null, + website: 'https://isaacscript.github.io/', + source: 'https://github.com/IsaacScript/isaacscript/tree/main/packages/docs', + tags: ['opensource'], + }, + { + title: 'Jest Preview', + description: 'Debug your Jest tests. Effortlessly.', + preview: null, + website: 'https://www.jest-preview.com/', + source: 'https://github.com/nvh95/jest-preview/tree/main/website', + tags: ['opensource'], + }, + { + title: 'Paweł Kosiec', + description: 'Personal website and blog of Paweł Kosiec, Full-stack Cloud Developer.', + preview: null, + website: 'https://kosiec.dev/', + source: 'https://github.com/pkosiec/website', + tags: ['opensource','personal'], + }, + { + title: 'Homarr', + description: 'Homarr is a simple and lightweight homepage for your server.', + preview: null, + website: 'https://homarr.vercel.app/', + source: 'https://github.com/ajnart/homarr/tree/docs', + tags: ['opensource'], + }, + { + title: 'Wings', + description: 'Wings is a modern website-as-service for progressive campaigns', + preview: null, + website: 'https://wings.dev/', + source: null, + tags: ['product','i18n'], + }, + { + title: 'Kishan Gajera', + description: 'Personal portfolio and blog of Kishan Gajera', + preview: null, + website: 'https://www.kgajera.com/', + source: 'https://github.com/kgajera/blog', + tags: ['opensource','personal'], + }, + { + title: 'Harvest CLI', + description: 'A CLI for Harvest\'s time tracking software', + preview: null, + website: 'https://kgajera.github.io/hrvst-cli/', + source: 'https://github.com/kgajera/hrvst-cli/tree/main/website', + tags: ['opensource'], + }, + { + title: 'TSEI.JP', + description: 'TSEI.JP personal website, articles and docs', + preview: null, + website: 'https://tsei.jp/', + source: null, + tags: ['personal'], + }, + { + title: 'Brobot', + description: 'Testable state-based GUI automation.', + preview: null, + website: 'https://jspinak.github.io/brobot/', + source: 'https://github.com/jspinak/brobot/tree/main/docs', + tags: ['opensource'], + }, + { + title: 'Fathym Blog', + description: 'Fathym deploys, hosts and integrates your favorite tech stacks.', + preview: null, + website: 'https://www.fathym.com/blog', + source: 'https://github.com/lowcodeunit/public-web-blog', + tags: ['opensource'], + }, + { + title: 'Tech Interview Handbook', + description: 'Free curated tech interview preparation materials for busy software engineers.', + preview: null, + website: 'https://www.techinterviewhandbook.org/', + source: 'https://github.com/yangshun/tech-interview-handbook', + tags: ['opensource','personal'], + }, + { + title: 'Front End Interview Handbook', + description: 'Free curated tech interview preparation materials for busy software engineers', + preview: null, + website: 'https://www.frontendinterviewhandbook.com/', + source: 'https://github.com/yangshun/front-end-interview-handbook', + tags: ['opensource','personal'], + }, + { + title: 'WIZnet', + description: 'Documentation for various WIZnet products', + preview: null, + website: 'https://docs.wiznet.io/', + source: 'https://github.com/Wiznet/document_framework', + tags: ['opensource','product'], + }, + { + title: 'Xiaohai\'s Mind Palace', + description: 'A place for organizing notes, writing blogs, and showcasing projects.', + preview: null, + website: 'https://xiaohai.wiki/', + source: 'https://github.com/xiaohai-huang/learning-notes', + tags: ['opensource','personal'], + }, + { + title: 'Cho.sh', + description: 'Sunghyun Sho\'s Second Brain on the Web.', + preview: null, + website: 'https://cho.sh/', + source: 'https://github.com/anaclumos/www', + tags: ['opensource','personal','i18n'], + }, + { + title: 'i18n-tools', + description: 'CLI to make common operations around i18n files simpler', + preview: null, + website: 'https://jy95.github.io/i18n-tools/', + source: 'https://github.com/jy95/i18n-tools/tree/master/website', + tags: ['opensource'], + }, + { + title: 'Pure.css', + description: 'A set of small, responsive CSS modules that you can use in every web project.', + preview: null, + website: 'https://purecss.io/', + source: 'https://github.com/pure-css/pure', + tags: ['opensource','design'], + }, + { + title: 'Moodle Developer Resources', + description: 'Moodle - the world\'s open source learning platform', + preview: null, + website: 'https://moodledev.io/', + source: 'https://github.com/moodle/devdocs', + tags: ['opensource','product','large'], + }, + { + title: 'Toggle', + description: 'Open Source real-time feature flags deployment without need of a server with SDK', + preview: null, + website: 'https://www.togglee.com/', + source: 'https://github.com/togglee/togglee-web', + tags: ['opensource','product'], + }, + { + title: 'Barklarm', + description: 'Open Source multiplatform alarm and build status monitoring application', + preview: null, + website: 'https://www.barklarm.com/', + source: 'https://github.com/kanekotic/barklarm-website', + tags: ['opensource','product'], + }, + { + title: 'Nikita\'s Everything I Know Wiki', + description: 'Digital wiki with notes/links.', + preview: null, + website: 'https://wiki.nikiv.dev/', + source: 'https://github.com/nikitavoloboev/knowledge', + tags: ['opensource','personal','large'], + }, + { + title: 'Infinity Works Company Handbook', + description: 'An online company handbook, acting as a one-stop shop for all relevant information needed for colleagues.', + preview: null, + website: 'https://handbook.infinityworks.com/', + source: null, + tags: ['design'], // TODO need a tag for company's corporate websites? + }, + { + title: 'Neo Blockchain Developer Portal', + description: 'A collection of tools and resources to help you build outstanding applications on Neo', + preview: null, + website: 'https://developers.neo.org/', + source: 'https://github.com/neo-project/neo-dev-portal', + tags: ['opensource'], // TODO create crypto/web3 tag? + }, + { + title: 'Yew', + description: 'Documentation of Yew web framework', + preview: null, + website: 'https://yew.rs/', + source: 'https://github.com/yewstack/yew/tree/master/website', + tags: ['opensource','versioning','i18n','large'], + }, + { + title: 'Sensory Percussion help', + description: 'On-line manual for Sensory Percussion, a music production tool for electronic drums.', + preview: null, + website: 'https://help.sunhou.se/', + source: null, + tags: ['product'], + }, + { + title: 'The Fundraising Lore', + description: 'A guide to help founders successfully raise early-stage VC financing', + preview: null, + website: 'https://www.lore.vc/', + source: 'https://github.com/dvitanov/lorevc', + tags: ['opensource','personal'], // TODO find better tag? + }, + { + title: 'LifeOmic PHC Documentation', + description: 'Help and information for LifeOmic PHC', + preview: null, + website: 'https://phc.docs.lifeomic.com/', + source: null, + tags: ['product'], + }, + { + title: 'Kanekotic\'s Page', + description: 'List of open-source projects and blog', + preview: null, + website: 'https://www.kanekotic.com/', + source: 'https://github.com/kanekotic/kanekotic-page', + tags: ['opensource','personal'], + }, + { + title: 'DevTomek', + description: 'A Polish blog about programming, electronics and IoT', + preview: null, + website: 'https://devtomek.pl/', + source: null, + tags: ['personal'], + }, + { + title: 'Vantevo Analytics', + description: 'The most complete and secure Google Analytics alternative.', + preview: null, + website: 'https://vantevo.io/docs/', + source: null, + tags: ['product','i18n'], + }, + { + title: 'lsfusion platform documentation', + description: 'A declarative open-source language-based platform for information systems development', + preview: null, + website: 'https://docs.lsfusion.org/', + source: 'https://github.com/lsfusion/docusaurus', + tags: ['opensource','i18n','versioning'], + }, + { + title: 'Rokt Docs', + description: 'Rokt\'s product documentation', + preview: null, + website: 'https://docs.rokt.com/', + source: null, + tags: ['product'], + }, + { + title: 'Harmonoid', + description: 'A beautiful material-design cross platform music player', + preview: null, + website: 'https://harmonoid.com/', + source: null, + tags: ['product','design'], + }, + { + title: 'Mentorship Guide', + description: 'Making mentorship accessible to all, for mentors and mentees.', + preview: null, + website: 'https://mentorship.guide/', + source: 'https://github.com/mentorship-sponsorship/mentorship-guide-docs', + tags: ['opensource','design'], + }, + { + title: 'Vishal Gandhi', + description: 'The Data Column - Blog by Vishal Gandhi', + preview: null, + website: 'https://vishalgandhi.in/', + source: null, + tags: ['personal'], + }, + { + title: 'Daily.dev Documentation', + description: 'Official product documentation for daily.dev', + preview: null, + website: 'https://docs.daily.dev/', + source: 'https://github.com/dailydotdev/docs', + tags: ['opensource','product','design'], + }, + { + title: 'Formiz', + description: 'React forms with ease! Composable, headless & with built-in multi steps', + preview: null, + website: 'https://formiz-react.com/', + source: 'https://github.com/ivan-dalmet/formiz/tree/master/documentation', + tags: ['opensource'], + }, + { + title: 'Wener Live & Life', + description: 'Notes, Stories, Awesomes', + preview: null, + website: 'https://wener.me/', + source: 'https://github.com/wenerme/wener/tree/master/site', + tags: ['opensource','personal'], + }, + { + title: 'Modrinth Documentation', + description: 'The documentation for Modrinth, an open source Minecraft modding platform', + preview: null, + website: 'https://docs.modrinth.com/', + source: 'https://github.com/modrinth/docs', + tags: ['opensource'], + }, + { + title: 'Codiga Documentation', + description: 'Documentation for Codiga, your Code Analysis & Coding Assistant', + preview: null, + website: 'https://doc.codiga.io/', + source: 'https://github.com/codiga/doc.codiga.io/tree/main/website', + tags: ['opensource','product'], + }, + { + title: 'Takken.io', + description: 'Webber\'s personal website', + preview: null, + website: 'https://takken.io/', + source: 'https://github.com/webbertakken/takken.io', + tags: ['opensource','personal'], + }, + { + title: 'GameCI', + description: 'Open source continuous integration for games', + preview: null, + website: 'https://game.ci/', + source: 'https://github.com/game-ci/documentation', + tags: ['opensource','product','versioning'], + }, + { + title: 'Batect', + description: 'The fast, consistent way to run your development and testing tasks everywhere.', + preview: null, + website: 'https://batect.dev/', + source: 'https://github.com/batect/batect.dev', + tags: ['opensource'], + }, + { + title: 'Boyka-Framework', + description: 'Ultimate test automation for testing any application on any platform', + preview: null, + website: 'https://wasiqbhamla.github.io/boyka-framework/', + source: 'https://github.com/WasiqBhamla/boyka-framework/tree/main/website', + tags: ['opensource'], + }, + { + title: 'Nango', + description: 'Open-source infrastructure for native integrations in SaaS products', + preview: null, + website: 'https://docs.nango.dev/', + source: 'https://github.com/NangoHQ/nango/tree/main/docs', + tags: ['opensource','product'], + }, + { + title: 'YepCode Docs', + description: 'Docs for the all-in-one platform that connects your services and APIs', + preview: null, + website: 'https://docs.yepcode.io/', + source: null, + tags: ['product'], + }, + { + title: 'YepCode Recipes', + description: 'Recipes for the all-in-one platform that connects your services and APIs', + preview: null, + website: 'https://yepcode.io/recipes/', + source: null, + tags: ['product','large'], + }, + { + title: 'Appcircle Docs', + description: 'Appcircle is an easy-to-setup mobile CI/CD platform.', + preview: null, + website: 'https://docs.appcircle.io/', + source: 'https://github.com/appcircleio/appcircle-docusaurus/tree/master/', + tags: ['opensource','product'], + }, + { + title: 'Rowy Docs', + description: 'Open-source low-code platform for Firebase, Cloud Functions and GCP', + preview: null, + website: 'https://docs.rowy.io/', + source: 'https://github.com/rowyio/docs', + tags: ['opensource','product','design'], + }, + { + title: 'Keebio Documentation', + description: 'Mechanical keyboard build guides and keyboard reprogramming info', + preview: null, + website: 'https://docs.keeb.io/', + source: 'https://github.com/keebio/keebio-docs', + tags: ['opensource','product'], + }, + { + title: 'SR50 Finance', + description: 'Reference handbook for personal finance', + preview: null, + website: 'https://sr50.finance/', + source: 'https://github.com/tpascarella/sr50', + tags: ['opensource'], + }, + { + title: '前端大刘', + description: 'Record and share to make progress every day!', + preview: null, + website: 'https://lzwdot.com/', + source: 'https://github.com/lzwdot/lzwdot.github.io', + tags: ['opensource','personal'], + }, + { + title: 'DipScope', + description: 'Open source tools to develop high quality software', + preview: null, + website: 'https://dipscope.com/', + source: null, + tags: ['versioning'], + }, + { + title: 'MutableSecurity', + description: 'Platform for automating the lifecycle of cybersecurity solutions', + preview: null, + website: 'https://www.mutablesecurity.io/', + source: 'https://github.com/MutableSecurity/website', + tags: ['opensource','product'], + }, + { + title: 'Atlas', + description: 'Atlas CLI helps developers manage their database schemas by applying DevOps principles.', + preview: null, + website: 'https://atlasgo.io/', + source: 'https://github.com/ariga/atlas', + tags: ['opensource','product'], + }, + { + title: 'Ent', + description: 'An entity framework for Go', + preview: null, + website: 'https://entgo.io/', + source: 'https://github.com/ent/ent/tree/master/doc/website', + tags: ['opensource','i18n'], + }, + { + title: 'NAYAtel ', + description: 'Documentation for TAC Department', + preview: null, + website: 'https://nayatel.shoaibsajid.com/', + source: null, + tags: [], // TODO not sure which tag to use here + }, + { + title: 'WPShop', + description: 'Docs site for the ShopWP WordPress plugin', + preview: null, + website: 'https://docs.wpshop.io/', + source: null, + tags: ['product'], + }, + { + title: 'Polkadot Wiki', + description: 'The central source of truth for Polkadot Network', + preview: null, + website: 'https://wiki.polkadot.network/', + source: 'https://github.com/w3f/polkadot-wiki/tree/master/polkadot-wiki', + tags: ['opensource'], // TODO add web3 tag? + }, + { + title: 'CodingHabits', + description: 'An interactive learning environment for developers', + preview: null, + website: 'https://www.codinghabits.online/', + source: null, + tags: ['product'], + }, + { + title: 'Crawlee', + description: 'Scalable web crawling, scraping and automation library for JS/Node.js', + preview: null, + website: 'https://crawlee.dev/', + source: 'https://github.com/apify/crawlee/tree/master/website', + tags: ['opensource','versioning'], + }, + { + title: 'codehooks', + description: 'Fast Serverless Backend made Easy', + preview: null, + website: 'https://codehooks.io/', + source: null, + tags: ['product'], + }, + { + title: 'HiCA', + description: 'Free SSL Certificate Provider, supports ACME', + preview: null, + website: 'https://www1.hi.cn/', + source: null, + tags: ['product'], + }, + { + title: 'Ouch1978', + description: 'Personal site of @Ouch1978', + preview: null, + website: 'https://ouch1978.github.io/', + source: 'https://github.com/Ouch1978/ouch1978.github.io', + tags: ['opensource','personal'], + }, + { + title: 'Dojo Documentation', + description: 'Take faster card payments with Dojo.', + preview: null, + website: 'https://docs.dojo.tech/', + source: null, + tags: ['product'], + }, + { + title: 'Computer Science Turkish Resource', + description: 'A Computer Science portal for enthusiasts.', + preview: null, + website: 'https://bb-tr-kaynak.netlify.app/', + source: 'https://github.com/Fire-Oceann/bb-tr-kaynak/', + tags: ['opensource'], + }, + { + title: 'OKP4', + description: 'Documentation portal for the OKP4 blockchain', + preview: null, + website: 'https://docs.okp4.network/', + source: 'https://github.com/okp4/docs', + tags: ['opensource','product','design'], // TODO add web3 tag + }, + { + title: 'Konkatsu Strategy Guide', + description: 'Support konkatsu (marriage hunting) in Japan', + preview: null, + website: 'https://hikonkatsu.com/', + source: null, + tags: ['personal'], + }, + { + title: 'Zondax Documentation', + description: 'Building back-end tech solutions for the Web3 Space.', + preview: null, + website: 'https://docs.zondax.ch/', + source: null, + tags: ['product','design'], // TODO add web3 tag + }, + { + title: 'Embedded IDE', + description: 'A c/c++ development environment for microcontrollers', + preview: null, + website: 'https://em-ide.com/', + source: 'https://github.com/github0null/eide-docs', + tags: ['opensource','i18n'], + }, + { + title: 'ShellHub Documentation', + description: 'A centralized SSH server for the the edge and cloud computing', + preview: null, + website: 'https://docs.shellhub.io/', + source: 'https://github.com/shellhub-io/docs', + tags: ['opensource','product'], + }, + { + title: 'Dynamoose', + description: 'A modeling tool for Amazon\'s DynamoDB', + preview: null, + website: 'https://dynamoosejs.com/', + source: 'https://github.com/dynamoose/dynamoose/tree/main/docs', + tags: ['opensource'], + }, + /* Pro Tip: add your site in alphabetical order. Appending your site here (at the end) is more likely to produce Git conflicts. @@ -2442,7 +3033,7 @@ const Users: User[] = [ export type User = { title: string; description: string; - preview: string; + preview: string | null; // null = use our serverless screenshot service website: string; source: string | null; tags: TagType[]; diff --git a/website/src/pages/showcase/_components/ShowcaseCard/index.tsx b/website/src/pages/showcase/_components/ShowcaseCard/index.tsx index 39c6c07f19dd..f4d1f68cb20f 100644 --- a/website/src/pages/showcase/_components/ShowcaseCard/index.tsx +++ b/website/src/pages/showcase/_components/ShowcaseCard/index.tsx @@ -58,11 +58,21 @@ function ShowcaseCardTag({tags}: {tags: TagType[]}) { ); } +function getCardImage(user: User): string { + return ( + user.preview ?? + `https://slorber-api-screenshot.netlify.app/${encodeURIComponent( + user.website, + )}/showcase` + ); +} + function ShowcaseCard({user}: {user: User}) { + const image = getCardImage(user); return (
  • - {user.title} + {user.title}