Website last fixes (#19895)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Thomas des Francs
2026-04-21 07:43:06 +02:00
committed by GitHub
parent 6ef15713b1
commit 3ee1b528a1
60 changed files with 456 additions and 239 deletions
+121 -82
View File
@@ -1,126 +1,170 @@
<p align="center">
<a href="https://www.producthunt.com/products/twenty-crm?launch=twenty-2-0">
<img src="./packages/twenty-website/public/images/readme/product-hunt-banner.png" alt="We're live on Product Hunt — Support us" />
</a>
</p>
<p align="center"> <p align="center">
<a href="https://www.twenty.com"> <a href="https://www.twenty.com">
<img src="./packages/twenty-website/public/images/core/logo.svg" width="100px" alt="Twenty logo" /> <img src="./packages/twenty-website/public/images/core/logo.svg" width="100px" alt="Twenty logo" />
</a> </a>
</p> </p>
<h2 align="center" >The #1 Open-Source CRM </h2> <h2 align="center" >The #1 Open-Source CRM</h2>
<p align="center"><a href="https://twenty.com">🌐 Website</a> · <a href="https://docs.twenty.com">📚 Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a></p>
<br />
<p align="center"><a href="https://twenty.com"><img src="./packages/twenty-website/public/images/readme/globe-icon.svg" width="12" height="12"/> Website</a> · <a href="https://docs.twenty.com"><img src="./packages/twenty-website/public/images/readme/book-icon.svg" width="12" height="12"/> Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website/public/images/readme/map-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a></p>
<p align="center"> <p align="center">
<a href="https://www.twenty.com"> <a href="https://www.twenty.com">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/github-cover-dark.png" /> <source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/github-cover-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/github-cover-light.png" /> <source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/github-cover-light.png" />
<img src="./packages/twenty-website/public/images/readme/github-cover-light.png" alt="Cover" /> <img src="./packages/twenty-website/public/images/readme/github-cover-light.png" alt="Twenty banner" />
</picture> </picture>
</a> </a>
</p> </p>
<br /> <br />
# Installation
See:
🚀 [Self-hosting](https://docs.twenty.com/developers/self-host/capabilities/docker-compose)
🖥️ [Local Setup](https://docs.twenty.com/developers/contribute/capabilities/local-setup)
# Why Twenty # Why Twenty
We built Twenty for three reasons: Twenty gives technical teams the building blocks for a custom CRM that meets complex business needs and quickly adapts as the business evolves. Twenty is the CRM you build, ship, and version like the rest of your stack.
**CRMs are too expensive, and users are trapped.** Companies use locked-in customer data to hike prices. It shouldn't be that way. <a href="https://twenty.com/why-twenty"><img src="./packages/twenty-website/public/images/readme/star-icon.svg" width="14" height="14"/> Learn more about why we built Twenty</a>
**A fresh start is required to build a better experience.** We can learn from past mistakes and craft a cohesive experience inspired by new UX patterns from tools like Notion, Airtable or Linear.
**We believe in open-source and community.** Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
<br /> <br />
# What You Can Do With Twenty # Installation
Please feel free to flag any specific needs you have by creating an issue. ### <img src="./packages/twenty-website/public/images/readme/globe-icon.svg" width="14" height="14"/> Cloud
Below are a few features we have implemented to date: The fastest way to get started. Sign up at [twenty.com](https://twenty.com) and spin up a workspace in under a minute, with no infrastructure to manage and always up to date.
+ [Personalize layouts with filters, sort, group by, kanban and table views](#personalize-layouts-with-filters-sort-group-by-kanban-and-table-views) ### <img src="./packages/twenty-website/public/images/readme/book-icon.svg" width="14" height="14"/> Build an app
+ [Customize your objects and fields](#customize-your-objects-and-fields)
+ [Create and manage permissions with custom roles](#create-and-manage-permissions-with-custom-roles)
+ [Automate workflow with triggers and actions](#automate-workflow-with-triggers-and-actions)
+ [Emails, calendar events, files, and more](#emails-calendar-events-files-and-more)
Scaffold a new app with the Twenty CLI:
## Personalize layouts with filters, sort, group by, kanban and table views ```bash
npx create-twenty-app my-app
```
<p align="center"> Define objects, fields, and views as code:
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/views-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/views-light.png" />
<img src="./packages/twenty-website/public/images/readme/views-light.png" alt="Companies Kanban Views" />
</picture>
</p>
## Customize your objects and fields ```ts
import { defineObject, FieldType } from 'twenty-sdk/define';
<p align="center"> export default defineObject({
<picture> nameSingular: 'deal',
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/data-model-dark.png" /> namePlural: 'deals',
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/data-model-light.png" /> labelSingular: 'Deal',
<img src="./packages/twenty-website/public/images/readme/data-model-light.png" alt="Setting Custom Objects" /> labelPlural: 'Deals',
</picture> fields: [
</p> { name: 'name', label: 'Name', type: FieldType.TEXT },
{ name: 'amount', label: 'Amount', type: FieldType.CURRENCY },
{ name: 'closeDate', label: 'Close Date', type: FieldType.DATE_TIME },
],
});
```
## Create and manage permissions with custom roles Then ship it to your workspace:
<p align="center"> ```bash
<picture> npx twenty deploy
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/permissions-dark.png" /> ```
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/permissions-light.png" />
<img src="./packages/twenty-website/public/images/readme/permissions-light.png" alt="Permissions" />
</picture>
</p>
## Automate workflow with triggers and actions See the [app development guide](https://docs.twenty.com/developers/extend/apps/getting-started) for objects, views, agents, and logic functions.
<p align="center"> ### <img src="./packages/twenty-website/public/images/readme/rocket-icon.svg" width="14" height="14"/> Self-hosting
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/workflows-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/workflows-light.png" />
<img src="./packages/twenty-website/public/images/readme/workflows-light.png" alt="Workflows" />
</picture>
</p>
## Emails, calendar events, files, and more Run Twenty on your own infrastructure with [Docker Compose](https://docs.twenty.com/developers/self-host/capabilities/docker-compose), or contribute locally via the [local setup guide](https://docs.twenty.com/developers/contribute/capabilities/local-setup).
<p align="center"> <br />
<picture> <br />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/plus-other-features-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/refs/heads/main/packages/twenty-website/public/images/readme/plus-other-features-light.png" /> # Everything you need
<img src="./packages/twenty-website/public/images/readme/plus-other-features-light.png" alt="Other Features" />
</picture> Twenty gives you the building blocks of a modern CRM (objects, views, workflows, and agents) and lets you extend them as code. Here's a tour of what's in the box.
</p>
Want to go deeper? Read the <a href="https://docs.twenty.com/user-guide/introduction"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="14" height="14"/> User Guide</a> for product walkthroughs, or the <a href="https://docs.twenty.com"><img src="./packages/twenty-website/public/images/readme/book-icon.svg" width="14" height="14"/> Documentation</a> for developer reference.
<table align="center">
<tr>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-build-apps-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-build-apps-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-build-apps-light.png" alt="Create your apps" />
</picture>
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/getting-started"><img src="./packages/twenty-website/public/images/readme/code-icon.svg" width="16" height="16"/> Learn more about apps in doc</a></p>
</td>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-version-control-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-version-control-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-version-control-light.png" alt="Stay on top with version control" />
</picture>
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/publishing"><img src="./packages/twenty-website/public/images/readme/monitor-icon.svg" width="16" height="16"/> Learn more about version control in doc</a></p>
</td>
</tr>
<tr>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-all-tools-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-all-tools-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-all-tools-light.png" alt="All the tools you need to build anything" />
</picture>
<p align="center"><a href="https://docs.twenty.com/developers/extend/apps/building"><img src="./packages/twenty-website/public/images/readme/rocket-icon.svg" width="16" height="16"/> Learn more about primitives in doc</a></p>
</td>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-tools-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-tools-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-tools-light.png" alt="Customize your layouts" />
</picture>
<p align="center"><a href="https://docs.twenty.com/user-guide/views-pipelines/overview"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="16" height="16"/> Learn more about layouts in doc</a></p>
</td>
</tr>
<tr>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-ai-agents-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-ai-agents-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-ai-agents-light.png" alt="AI agents and chats" />
</picture>
<p align="center"><a href="https://docs.twenty.com/user-guide/ai/overview"><img src="./packages/twenty-website/public/images/readme/message-icon.svg" width="16" height="16"/> Learn more about AI in doc</a></p>
</td>
<td width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./packages/twenty-website/public/images/readme/v2-crm-tools-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="./packages/twenty-website/public/images/readme/v2-crm-tools-light.png" />
<img src="./packages/twenty-website/public/images/readme/v2-crm-tools-light.png" alt="Plus all the tools of a good CRM" />
</picture>
<p align="center"><a href="https://docs.twenty.com/user-guide/introduction"><img src="./packages/twenty-website/public/images/readme/star-icon.svg" width="16" height="16"/> Learn more about CRM features in doc</a></p>
</td>
</tr>
</table>
<br /> <br />
# Stack # Stack
- [TypeScript](https://www.typescriptlang.org/)
- [Nx](https://nx.dev/) - <a href="https://www.typescriptlang.org/"><img src="./packages/twenty-website/public/images/readme/stack-typescript.svg" width="14" height="14"/> TypeScript</a>
- [NestJS](https://nestjs.com/), with [BullMQ](https://bullmq.io/), [PostgreSQL](https://www.postgresql.org/), [Redis](https://redis.io/) - <a href="https://nx.dev/"><img src="./packages/twenty-website/public/images/readme/stack-nx.svg" width="14" height="14"/> Nx</a>
- [React](https://reactjs.org/), with [Jotai](https://jotai.org/), [Linaria](https://linaria.dev/) and [Lingui](https://lingui.dev/) - <a href="https://nestjs.com/"><img src="./packages/twenty-website/public/images/readme/stack-nestjs.svg" width="14" height="14"/> NestJS</a>, with <a href="https://bullmq.io/">BullMQ</a>, <a href="https://www.postgresql.org/"><img src="./packages/twenty-website/public/images/readme/stack-postgresql.svg" width="14" height="14"/> PostgreSQL</a>, <a href="https://redis.io/"><img src="./packages/twenty-website/public/images/readme/stack-redis.svg" width="14" height="14"/> Redis</a>
- <a href="https://reactjs.org/"><img src="./packages/twenty-website/public/images/readme/stack-react.svg" width="14" height="14"/> React</a>, with <a href="https://jotai.org/">Jotai</a>, <a href="https://linaria.dev/">Linaria</a> and <a href="https://lingui.dev/">Lingui</a>
# Thanks # Thanks
<p align="center"> <p align="center">
<a href="https://www.chromatic.com/"><img src="./packages/twenty-website/public/images/readme/chromatic.png" height="30" alt="Chromatic" /></a> <a href="https://www.chromatic.com/"><img src="./packages/twenty-website/public/images/readme/chromatic.png" height="28" alt="Chromatic" /></a>
<a href="https://greptile.com"><img src="./packages/twenty-website/public/images/readme/greptile.png" height="30" alt="Greptile" /></a> &nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://sentry.io/"><img src="./packages/twenty-website/public/images/readme/sentry.png" height="30" alt="Sentry" /></a> <a href="https://greptile.com"><img src="./packages/twenty-website/public/images/readme/greptile.png" height="28" alt="Greptile" /></a>
<a href="https://crowdin.com/"><img src="./packages/twenty-website/public/images/readme/crowdin.png" height="30" alt="Crowdin" /></a> &nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://e2b.dev/"><img src="./packages/twenty-website/public/images/readme/e2b.svg" height="30" alt="E2B" /></a> <a href="https://sentry.io/"><img src="./packages/twenty-website/public/images/readme/sentry.png" height="28" alt="Sentry" /></a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://crowdin.com/"><img src="./packages/twenty-website/public/images/readme/crowdin.png" height="28" alt="Crowdin" /></a>
</p> </p>
Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin). Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
@@ -128,9 +172,4 @@ Below are a few features we have implemented to date:
# Join the Community # Join the Community
- Star the repo <p><a href="https://github.com/twentyhq/twenty"><img src="./packages/twenty-website/public/images/readme/star-icon.svg" width="12" height="12"/> Star the repo</a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://github.com/twentyhq/twenty/discussions"><img src="./packages/twenty-website/public/images/readme/message-icon.svg" width="12" height="12"/> Feature requests</a> · <a href="https://github.com/orgs/twentyhq/projects/1/views/35"><img src="./packages/twenty-website/public/images/readme/rocket-icon.svg" width="12" height="12"/> Releases</a> · <a href="https://twitter.com/twentycrm"><img src="./packages/twenty-website/public/images/readme/x-icon.svg" width="12" height="12"/> X</a> · <a href="https://www.linkedin.com/company/twenty/"><img src="./packages/twenty-website/public/images/readme/linkedin-icon.svg" width="12" height="12"/> LinkedIn</a> · <a href="https://twenty.crowdin.com/twenty"><img src="./packages/twenty-website/public/images/readme/language-icon.svg" width="12" height="12"/> Crowdin</a> · <a href="https://github.com/twentyhq/twenty/contribute"><img src="./packages/twenty-website/public/images/readme/code-icon.svg" width="12" height="12"/> Contribute</a></p>
- Subscribe to releases (watch -> custom -> releases)
- Follow us on [Twitter](https://twitter.com/twentycrm) or [LinkedIn](https://www.linkedin.com/company/twenty/)
- Join our [Discord](https://discord.gg/cx5n4Jzs57)
- Improve translations on [Crowdin](https://twenty.crowdin.com/twenty)
- [Contributions](https://github.com/twentyhq/twenty/contribute) are, of course, most welcome!
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@@ -11,6 +11,7 @@ import { TalkToUsButton } from '@/app/components/ContactCalModal';
import { FAQ_DATA, MENU_DATA, TRUSTED_BY_DATA } from '@/app/_constants'; import { FAQ_DATA, MENU_DATA, TRUSTED_BY_DATA } from '@/app/_constants';
import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components'; import { Body, Eyebrow, Heading, LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages'; import { Pages } from '@/enums/pages';
import { ArrowRightUpIcon } from '@/icons';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats'; import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels'; import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { Faq } from '@/sections/Faq/components'; import { Faq } from '@/sections/Faq/components';
@@ -28,11 +29,15 @@ import { styled } from '@linaria/react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Twenty | Open Source CRM', title: 'Twenty | #1 open source CRM',
description: 'Modular, scalable open source CRM for modern teams.', description:
'The #1 open source CRM for modern teams. Modular, scalable, and built to fit your business.',
}; };
const HOME_TOP_BACKGROUND_COLOR = '#F4F4F4'; const HOME_TOP_BACKGROUND_COLOR = '#F4F4F4';
const PRODUCT_HUNT_LAUNCH_URL =
'https://www.producthunt.com/products/twenty-crm?launch=twenty-2-0';
const PRODUCT_HUNT_BRAND_COLOR = '#DA552F';
const HeroHeadingGroup = styled.div` const HeroHeadingGroup = styled.div`
align-items: center; align-items: center;
@@ -41,11 +46,63 @@ const HeroHeadingGroup = styled.div`
gap: ${theme.spacing(3)}; gap: ${theme.spacing(3)};
width: 100%; width: 100%;
> *:nth-child(2) { > *:last-child {
margin-top: 0; margin-top: 0;
} }
`; `;
const HeroLaunchChip = styled.a`
align-items: center;
background: ${theme.colors.primary.background[100]};
border: 1px solid ${theme.colors.primary.border[10]};
border-radius: 999px;
color: ${theme.colors.primary.text[100]};
display: inline-flex;
font-family: ${theme.font.family.mono};
font-size: ${theme.font.size(2.5)};
font-weight: ${theme.font.weight.medium};
gap: ${theme.spacing(2)};
line-height: ${theme.lineHeight(3)};
padding: ${theme.spacing(2)} ${theme.spacing(3)};
text-decoration: none;
text-transform: uppercase;
transition:
border-color 180ms ease,
color 180ms ease,
transform 180ms ease;
white-space: nowrap;
&:is(:hover, :focus-visible) {
border-color: ${PRODUCT_HUNT_BRAND_COLOR};
color: ${PRODUCT_HUNT_BRAND_COLOR};
transform: translateY(-1px);
}
&:focus-visible {
outline: 1px solid ${theme.colors.highlight[100]};
outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
transition: none;
}
`;
const HeroLaunchChipDot = styled.span`
background: ${PRODUCT_HUNT_BRAND_COLOR};
border-radius: 999px;
display: block;
flex-shrink: 0;
height: ${theme.spacing(2)};
width: ${theme.spacing(2)};
`;
const HeroLaunchChipLabel = styled.span`
align-items: center;
display: inline-flex;
gap: ${theme.spacing(1.5)};
`;
const HeroIntroGroup = styled.div` const HeroIntroGroup = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
@@ -109,6 +166,17 @@ export default async function HomePage() {
<Hero.Root backgroundColor={HOME_TOP_BACKGROUND_COLOR} showHomeBackground> <Hero.Root backgroundColor={HOME_TOP_BACKGROUND_COLOR} showHomeBackground>
<HeroIntroGroup data-halftone-exclude> <HeroIntroGroup data-halftone-exclude>
<HeroHeadingGroup> <HeroHeadingGroup>
<HeroLaunchChip
href={PRODUCT_HUNT_LAUNCH_URL}
rel="noopener noreferrer"
target="_blank"
>
<HeroLaunchChipDot />
<HeroLaunchChipLabel>
Live on Product Hunt
<ArrowRightUpIcon size={8} strokeColor="currentColor" />
</HeroLaunchChipLabel>
</HeroLaunchChip>
<Hero.Heading page={Pages.Home} segments={HERO_DATA.heading} /> <Hero.Heading page={Pages.Home} segments={HERO_DATA.heading} />
<Hero.Body page={Pages.Home} body={HERO_DATA.body} size="sm" /> <Hero.Body page={Pages.Home} body={HERO_DATA.body} size="sm" />
</HeroHeadingGroup> </HeroHeadingGroup>
@@ -25,7 +25,7 @@ export const FAQ_DATA: FaqDataType = {
fontFamily: 'sans', fontFamily: 'sans',
}, },
answer: { answer: {
text: "Yes. Twenty is the #1 open-source CRM on GitHub. Most teams run it on our managed cloud for zero-ops setup; self-hosting is always available if you'd rather own the infrastructure.", text: "Yes. Twenty is the #1 open source CRM on GitHub. Most teams run it on our managed cloud for zero-ops setup; self-hosting is always available if you'd rather own the infrastructure.",
}, },
}, },
{ {
@@ -40,7 +40,7 @@ export const MENU_DATA: MenuDataType = {
image: '/images/shared/menu/developers-preview.png', image: '/images/shared/menu/developers-preview.png',
imageAlt: 'Blue developer illustration with branching arrows', imageAlt: 'Blue developer illustration with branching arrows',
imagePosition: 'center', imagePosition: 'center',
imageScale: 1.4, imageScale: 1.6,
title: 'Build on an open platform', title: 'Build on an open platform',
description: description:
'APIs, SDKs and webhooks to extend Twenty and ship apps on top of your CRM data.', 'APIs, SDKs and webhooks to extend Twenty and ship apps on top of your CRM data.',
@@ -120,7 +120,7 @@ export const CASE_STUDY_CATALOG_ENTRIES: CaseStudyCatalogEntry[] = [
'NetZero uses Twenty as a modular CRM across product lines and countries, with a roadmap into AI-assisted workflows.', 'NetZero uses Twenty as a modular CRM across product lines and countries, with a roadmap into AI-assisted workflows.',
date: '2025', date: '2025',
coverImageSrc: coverImageSrc:
'https://images.unsplash.com/photo-1510524474345-1c4bac68d1d0?w=1600&q=80', 'https://images.unsplash.com/photo-1744830343976-ce690ba2a67c?w=1600&q=80',
}, },
}, },
{ {
@@ -10,7 +10,7 @@ import { theme } from '@/theme';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
const PLACEHOLDER_HERO = const PLACEHOLDER_HERO =
'https://images.unsplash.com/photo-1510524474345-1c4bac68d1d0?w=1600&q=80'; 'https://images.unsplash.com/photo-1744830343976-ce690ba2a67c?w=1600&q=80';
const CASE_STUDY: CaseStudyData = { const CASE_STUDY: CaseStudyData = {
meta: { meta: {
@@ -66,8 +66,9 @@ const StyledMain = styled.main`
`; `;
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Twenty | Open Source CRM', title: 'Twenty | #1 open source CRM',
description: 'Modular, scalable open source CRM for modern teams.', description:
'The #1 open source CRM for modern teams. Modular, scalable, and built to fit your business.',
}; };
export default function RootLayout({ export default function RootLayout({
@@ -6,6 +6,6 @@ export const HERO_DATA = {
{ text: 'our partner', fontFamily: 'sans', newLine: true }, { text: 'our partner', fontFamily: 'sans', newLine: true },
], ],
body: { body: {
text: "We're building the #1 open-source CRM, but we can't do it alone. Join our partner ecosystem and grow with us.", text: "We're building the #1 open source CRM, but we can't do it alone. Join our partner ecosystem and grow with us.",
}, },
} satisfies HeroBaseDataType; } satisfies HeroBaseDataType;
@@ -34,7 +34,7 @@ export const THREE_CARDS_ILLUSTRATION_DATA: ThreeCardsIllustrationDataType = {
{ {
heading: { text: 'Content & Community Partners', fontFamily: 'sans' }, heading: { text: 'Content & Community Partners', fontFamily: 'sans' },
body: { body: {
text: "Share Twenty with your audience and help shape the future of open-source CRM. We're looking for creators, educators, and community builders who want to showcase great software.", text: "Share Twenty with your audience and help shape the future of the #1 open source CRM. We're looking for creators, educators, and community builders who want to showcase great software.",
}, },
benefits: [ benefits: [
{ text: 'Revenue share for referred customers', icon: 'tag' }, { text: 'Revenue share for referred customers', icon: 'tag' },
@@ -26,6 +26,7 @@ import { ThreeCards } from '@/sections/ThreeCards/components';
import { TrustedBy } from '@/sections/TrustedBy/components'; import { TrustedBy } from '@/sections/TrustedBy/components';
import type { ThreeCardsScrollLayoutOptions } from '@/sections/ThreeCards/utils/three-cards-scroll-layout'; import type { ThreeCardsScrollLayoutOptions } from '@/sections/ThreeCards/utils/three-cards-scroll-layout';
import { theme } from '@/theme'; import { theme } from '@/theme';
import { styled } from '@linaria/react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
const PARTNER_ILLUSTRATION_CARDS_SCROLL_LAYOUT_OPTIONS: ThreeCardsScrollLayoutOptions = const PARTNER_ILLUSTRATION_CARDS_SCROLL_LAYOUT_OPTIONS: ThreeCardsScrollLayoutOptions =
@@ -37,10 +38,18 @@ const PARTNER_ILLUSTRATION_CARDS_SCROLL_LAYOUT_OPTIONS: ThreeCardsScrollLayoutOp
stagger: 0.16, stagger: 0.16,
}; };
const PromoSpacing = styled.div`
margin-bottom: ${theme.spacing(8)};
@media (min-width: ${theme.breakpoints.md}px) {
margin-bottom: ${theme.spacing(12)};
}
`;
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Partners | Twenty', title: 'Partners | Twenty',
description: description:
'Join our partner ecosystem and grow with us as we build the #1 open-source CRM.', 'Join our partner ecosystem and grow with us as we build the #1 open source CRM.',
}; };
export default async function PartnerPage() { export default async function PartnerPage() {
@@ -72,13 +81,16 @@ export default async function PartnerPage() {
<TrustedBy.Root <TrustedBy.Root
backgroundColor={theme.colors.primary.background[100]} backgroundColor={theme.colors.primary.background[100]}
compactBottom
> >
<TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} /> <TrustedBy.Separator separator={TRUSTED_BY_DATA.separator} />
<TrustedBy.Logos logos={TRUSTED_BY_DATA.logos} /> <TrustedBy.Logos logos={TRUSTED_BY_DATA.logos} />
<TrustedBy.ClientCount label={TRUSTED_BY_DATA.clientCountLabel.text} /> <TrustedBy.ClientCount label={TRUSTED_BY_DATA.clientCountLabel.text} />
</TrustedBy.Root> </TrustedBy.Root>
<CaseStudyCatalog.Promo entries={CASE_STUDY_CATALOG_ENTRIES} /> <PromoSpacing>
<CaseStudyCatalog.Promo compactTop entries={CASE_STUDY_CATALOG_ENTRIES} />
</PromoSpacing>
<ThreeCards.Root backgroundColor={theme.colors.secondary.background[5]}> <ThreeCards.Root backgroundColor={theme.colors.secondary.background[5]}>
<ThreeCards.Intro page={Pages.Partners} align="left"> <ThreeCards.Intro page={Pages.Partners} align="left">
@@ -37,7 +37,7 @@ const PricingBannerContainer = styled.div`
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Pricing | Twenty', title: 'Pricing | Twenty',
description: description:
'Plans that scale with your team. Compare tiers of the #1 open-source CRM.', 'Plans that scale with your team. Compare tiers of the #1 open source CRM.',
}; };
export default async function PricingPage() { export default async function PricingPage() {
@@ -7,5 +7,5 @@ export const RELEASE_NOTES_HERO_HEADING: HeadingType[] = [
]; ];
export const RELEASE_NOTES_HERO_BODY: BodyType = { export const RELEASE_NOTES_HERO_BODY: BodyType = {
text: 'Discover the newest features and improvements in Twenty,\nthe #1 open-source CRM.', text: 'Discover the newest features and improvements in Twenty,\nthe #1 open source CRM.',
}; };
@@ -21,7 +21,7 @@ import { Fragment } from 'react';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Releases | Twenty', title: 'Releases | Twenty',
description: description:
'Discover the newest features and improvements in Twenty, the open-source CRM.', 'Discover the newest features and improvements in Twenty, the #1 open source CRM.',
}; };
export default async function ReleasesPage() { export default async function ReleasesPage() {
@@ -11,7 +11,6 @@ import { LinkButton } from '@/design-system/components';
import { Pages } from '@/enums/pages'; import { Pages } from '@/enums/pages';
import { fetchCommunityStats } from '@/lib/community/fetch-community-stats'; import { fetchCommunityStats } from '@/lib/community/fetch-community-stats';
import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels'; import { mergeSocialLinkLabels } from '@/lib/community/merge-social-link-labels';
import { OverflowProbe } from '@/lib/debug/overflow-probe';
import { Editorial } from '@/sections/Editorial/components'; import { Editorial } from '@/sections/Editorial/components';
import { Hero } from '@/sections/Hero/components'; import { Hero } from '@/sections/Hero/components';
import { Marquee } from '@/sections/Marquee/components'; import { Marquee } from '@/sections/Marquee/components';
@@ -72,7 +71,6 @@ export default async function WhyTwentyPage() {
return ( return (
<> <>
<OverflowProbe />
<Menu.Root <Menu.Root
backgroundColor={theme.colors.secondary.background[100]} backgroundColor={theme.colors.secondary.background[100]}
scheme="secondary" scheme="secondary"
@@ -1,4 +1,4 @@
const PLUS_PATH = "M.5 7.25H14M7.25 14V.5"; const PLUS_PATH = 'M1.5 7.5H13.5M7.5 13.5V1.5';
interface PlusIconProps { interface PlusIconProps {
size: number; size: number;
@@ -13,10 +13,13 @@ export function PlusIcon({ size, strokeColor }: PlusIconProps) {
viewBox="0 0 15 15" viewBox="0 0 15 15"
fill="none" fill="none"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
overflow="visible"
style={{ display: 'block' }}
> >
<path <path
d={PLUS_PATH} d={PLUS_PATH}
stroke={strokeColor} stroke={strokeColor}
strokeWidth={1.25}
strokeMiterlimit={10} strokeMiterlimit={10}
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
@@ -32,7 +32,8 @@ const StyledContainer = styled(Container)<{ compactTop: boolean }>`
} }
`; `;
const CORNER_OFFSET = '-6px'; const CORNER_SIZE = 14;
const CORNER_OFFSET = '-7px';
const FramedGrid = styled.div` const FramedGrid = styled.div`
position: relative; position: relative;
@@ -89,11 +90,12 @@ const FrameRailBottom = styled.span`
const FrameCorner = styled.span` const FrameCorner = styled.span`
align-items: center; align-items: center;
display: none; display: none;
height: 12px; height: ${CORNER_SIZE}px;
justify-content: center; justify-content: center;
line-height: 0;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
width: 12px; width: ${CORNER_SIZE}px;
@media (min-width: ${theme.breakpoints.md}px) { @media (min-width: ${theme.breakpoints.md}px) {
display: flex; display: flex;
@@ -157,18 +159,30 @@ export function Grid({
{!compactTop && ( {!compactTop && (
<> <>
<FrameCornerTopLeft aria-hidden> <FrameCornerTopLeft aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerTopLeft> </FrameCornerTopLeft>
<FrameCornerTopRight aria-hidden> <FrameCornerTopRight aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerTopRight> </FrameCornerTopRight>
</> </>
)} )}
<FrameCornerBottomLeft aria-hidden> <FrameCornerBottomLeft aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerBottomLeft> </FrameCornerBottomLeft>
<FrameCornerBottomRight aria-hidden> <FrameCornerBottomRight aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerBottomRight> </FrameCornerBottomRight>
<CardGrid> <CardGrid>
{entries.map((entry, index) => { {entries.map((entry, index) => {
@@ -11,7 +11,9 @@ import { PromoMic } from '@/illustrations/CaseStudyCatalog/PromoMic';
import { theme } from '@/theme'; import { theme } from '@/theme';
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
const CORNER_OFFSET = '-6px'; const CORNER_SIZE = 14;
const CORNER_OFFSET = '-7px';
const CONNECTED_TOP_OFFSET = '6px';
const LINE_INSET = '20px'; const LINE_INSET = '20px';
const TRUSTED_BY_BOTTOM_PADDING = 12; const TRUSTED_BY_BOTTOM_PADDING = 12;
const TRUSTED_BY_BOTTOM_PADDING_DESKTOP = 16; const TRUSTED_BY_BOTTOM_PADDING_DESKTOP = 16;
@@ -59,12 +61,13 @@ const FrameBoard = styled.div`
} }
`; `;
const Frame = styled.div` const Frame = styled.div<{ compactTop: boolean }>`
bottom: ${theme.spacing(12)}; bottom: ${theme.spacing(12)};
left: ${theme.spacing(10)}; left: ${theme.spacing(10)};
position: absolute; position: absolute;
right: ${theme.spacing(10)}; right: ${theme.spacing(10)};
top: ${theme.spacing(12)}; top: ${({ compactTop }) =>
compactTop ? CONNECTED_TOP_OFFSET : theme.spacing(12)};
`; `;
const FrameLine = styled.span` const FrameLine = styled.span`
@@ -86,28 +89,29 @@ const FrameLineBottom = styled(FrameLine)`
right: ${LINE_INSET}; right: ${LINE_INSET};
`; `;
const FrameLineLeft = styled(FrameLine)` const FrameLineLeft = styled(FrameLine)<{ compactTop: boolean }>`
bottom: ${LINE_INSET}; bottom: ${LINE_INSET};
left: 0; left: 0;
top: ${LINE_INSET}; top: ${({ compactTop }) => (compactTop ? '0' : LINE_INSET)};
width: 1px; width: 1px;
`; `;
const FrameLineRight = styled(FrameLine)` const FrameLineRight = styled(FrameLine)<{ compactTop: boolean }>`
bottom: ${LINE_INSET}; bottom: ${LINE_INSET};
right: 0; right: 0;
top: ${LINE_INSET}; top: ${({ compactTop }) => (compactTop ? '0' : LINE_INSET)};
width: 1px; width: 1px;
`; `;
const FrameCorner = styled.span` const FrameCorner = styled.span`
align-items: center; align-items: center;
display: flex; display: flex;
height: 12px; height: ${CORNER_SIZE}px;
justify-content: center; justify-content: center;
line-height: 0;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
width: 12px; width: ${CORNER_SIZE}px;
`; `;
const FrameCornerTopLeft = styled(FrameCorner)` const FrameCornerTopLeft = styled(FrameCorner)`
@@ -130,16 +134,20 @@ const FrameCornerBottomRight = styled(FrameCorner)`
right: ${CORNER_OFFSET}; right: ${CORNER_OFFSET};
`; `;
const StyledContainer = styled(Container)` const StyledContainer = styled(Container)<{ compactTop: boolean }>`
align-items: center; align-items: center;
display: grid; display: grid;
gap: ${theme.spacing(10)}; gap: ${theme.spacing(10)};
grid-template-columns: 1fr; grid-template-columns: 1fr;
min-height: 520px; min-height: 520px;
padding-bottom: ${theme.spacing(24 + TRUSTED_BY_BOTTOM_PADDING)}; padding-bottom: ${({ compactTop }) =>
compactTop
? theme.spacing(16)
: theme.spacing(24 + TRUSTED_BY_BOTTOM_PADDING)};
padding-left: ${theme.spacing(4)}; padding-left: ${theme.spacing(4)};
padding-right: ${theme.spacing(4)}; padding-right: ${theme.spacing(4)};
padding-top: ${theme.spacing(20)}; padding-top: ${({ compactTop }) =>
compactTop ? theme.spacing(16) : theme.spacing(20)};
position: relative; position: relative;
z-index: 1; z-index: 1;
@@ -147,12 +155,14 @@ const StyledContainer = styled(Container)`
column-gap: ${theme.spacing(16)}; column-gap: ${theme.spacing(16)};
grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
min-height: 500px; min-height: 500px;
padding-bottom: ${theme.spacing( padding-bottom: ${({ compactTop }) =>
40 + TRUSTED_BY_BOTTOM_PADDING_DESKTOP, compactTop
)}; ? `calc(${theme.spacing(24)} + ${theme.spacing(12)} - ${CONNECTED_TOP_OFFSET})`
: theme.spacing(40 + TRUSTED_BY_BOTTOM_PADDING_DESKTOP)};
padding-left: ${theme.spacing(10)}; padding-left: ${theme.spacing(10)};
padding-right: ${theme.spacing(10)}; padding-right: ${theme.spacing(10)};
padding-top: ${theme.spacing(32)}; padding-top: ${({ compactTop }) =>
compactTop ? theme.spacing(24) : theme.spacing(32)};
} }
`; `;
@@ -250,41 +260,57 @@ type PromoProps = {
entries: readonly CaseStudyCatalogEntry[]; entries: readonly CaseStudyCatalogEntry[];
ctaHref?: string; ctaHref?: string;
ctaLabel?: string; ctaLabel?: string;
compactTop?: boolean;
}; };
export function Promo({ export function Promo({
entries, entries,
ctaHref = '/customers', ctaHref = '/customers',
ctaLabel = 'Explore customer stories', ctaLabel = 'Explore customer stories',
compactTop = false,
}: PromoProps) { }: PromoProps) {
const featured = entries[0];
return ( return (
<Section aria-label="Customer stories preview"> <Section aria-label="Customer stories preview">
<BackgroundLayer aria-hidden> <BackgroundLayer aria-hidden>
<FrameBoard> <FrameBoard>
<Frame> <Frame compactTop={compactTop}>
<FrameLineTop /> {!compactTop && <FrameLineTop />}
<FrameLineBottom /> <FrameLineBottom />
<FrameLineLeft /> <FrameLineLeft compactTop={compactTop} />
<FrameLineRight /> <FrameLineRight compactTop={compactTop} />
<FrameCornerTopLeft> {!compactTop && (
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <>
</FrameCornerTopLeft> <FrameCornerTopLeft>
<FrameCornerTopRight> <PlusIcon
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> size={CORNER_SIZE}
</FrameCornerTopRight> strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerTopLeft>
<FrameCornerTopRight>
<PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerTopRight>
</>
)}
<FrameCornerBottomLeft> <FrameCornerBottomLeft>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerBottomLeft> </FrameCornerBottomLeft>
<FrameCornerBottomRight> <FrameCornerBottomRight>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</FrameCornerBottomRight> </FrameCornerBottomRight>
</Frame> </Frame>
</FrameBoard> </FrameBoard>
</BackgroundLayer> </BackgroundLayer>
<StyledContainer> <StyledContainer compactTop={compactTop}>
<VisualColumn> <VisualColumn>
<VisualStage> <VisualStage>
<MicFrame aria-hidden> <MicFrame aria-hidden>
@@ -8,10 +8,7 @@ import {
} from '@/icons'; } from '@/icons';
import type { FaqQuestionType } from '@/sections/Faq/types/FaqQuestion'; import type { FaqQuestionType } from '@/sections/Faq/types/FaqQuestion';
import { theme } from '@/theme'; import { theme } from '@/theme';
import { import { Accordion as BaseAccordion } from '@base-ui/react/accordion';
Accordion as BaseAccordion,
type AccordionTriggerState,
} from '@base-ui/react/accordion';
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
const QuestionText = styled.span` const QuestionText = styled.span`
@@ -55,12 +52,29 @@ const ToggleVisual = styled.span`
display: inline-flex; display: inline-flex;
height: 36px; height: 36px;
justify-content: center; justify-content: center;
position: relative;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1); transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1);
width: 36px; width: 36px;
`; `;
const ToggleIconLayer = styled.span`
align-items: center;
display: inline-flex;
inset: 0;
justify-content: center;
position: absolute;
transition:
opacity 0.2s ease,
transform 0.2s ease;
&[data-icon='minus'] {
opacity: 0;
transform: scale(0.9);
}
`;
const RowTrigger = styled.button` const RowTrigger = styled.button`
background: transparent; background: transparent;
border: none; border: none;
@@ -123,6 +137,16 @@ export const ItemRow = styled.div`
opacity: 1; opacity: 1;
} }
&[data-open] ${ToggleIconLayer}[data-icon='plus'] {
opacity: 0;
transform: scale(0.9);
}
&[data-open] ${ToggleIconLayer}[data-icon='minus'] {
opacity: 1;
transform: scale(1);
}
@media (min-width: ${theme.breakpoints.md}px) { @media (min-width: ${theme.breakpoints.md}px) {
grid-template-columns: 14px 60px 1fr 80px 36px; grid-template-columns: 14px 60px 1fr 80px 36px;
row-gap: ${theme.spacing(4)}; row-gap: ${theme.spacing(4)};
@@ -186,42 +210,41 @@ export function Item({ question, value }: ItemProps) {
return ( return (
<BaseAccordion.Item key={value} value={value} render={<ItemRow />}> <BaseAccordion.Item key={value} value={value} render={<ItemRow />}>
<BaseAccordion.Header render={<Header />}> <BaseAccordion.Header render={<Header />}>
<BaseAccordion.Trigger <BaseAccordion.Trigger render={<RowTrigger type="button" />}>
render={(props, state: AccordionTriggerState) => { <QuestionIconContainer aria-hidden>
const isOpen = state.open; <QuestionIconLayer data-layer="outline">
const ToggleIcon = isOpen ? MinusIcon : PlusIcon; <RectangleOutlineIcon
return ( size={14}
// oxlint-disable-next-line react/jsx-props-no-spreading -- Accordion.Trigger host props strokeColor={theme.colors.secondary.text[100]}
<RowTrigger {...props} type="button"> />
<QuestionIconContainer aria-hidden> </QuestionIconLayer>
<QuestionIconLayer data-layer="outline"> <QuestionIconLayer data-layer="fill">
<RectangleOutlineIcon <RectangleFillIcon
size={14} size={14}
strokeColor={theme.colors.secondary.text[100]} fillColor={theme.colors.secondary.text[100]}
/> />
</QuestionIconLayer> </QuestionIconLayer>
<QuestionIconLayer data-layer="fill"> </QuestionIconContainer>
<RectangleFillIcon
size={14}
fillColor={theme.colors.secondary.text[100]}
/>
</QuestionIconLayer>
</QuestionIconContainer>
<QuestionText>{question.question.text}</QuestionText> <QuestionText>{question.question.text}</QuestionText>
<ToggleContainer> <ToggleContainer>
<ToggleVisual aria-hidden> <ToggleVisual aria-hidden>
<ToggleIcon <ToggleIconLayer data-icon="plus">
size={12} <PlusIcon
strokeColor={theme.colors.secondary.border[80]} size={12}
/> strokeColor={theme.colors.secondary.border[80]}
</ToggleVisual> />
</ToggleContainer> </ToggleIconLayer>
</RowTrigger> <ToggleIconLayer data-icon="minus">
); <MinusIcon
}} size={12}
/> strokeColor={theme.colors.secondary.border[80]}
/>
</ToggleIconLayer>
</ToggleVisual>
</ToggleContainer>
</BaseAccordion.Trigger>
</BaseAccordion.Header> </BaseAccordion.Header>
<BaseAccordion.Panel render={<AnswerWrapper />} keepMounted> <BaseAccordion.Panel render={<AnswerWrapper />} keepMounted>
@@ -4,7 +4,8 @@ import { theme } from '@/theme';
import { styled } from '@linaria/react'; import { styled } from '@linaria/react';
import { Children, type ReactNode } from 'react'; import { Children, type ReactNode } from 'react';
const CORNER_OFFSET = '-6px'; const CORNER_SIZE = 14;
const CORNER_OFFSET = '-7px';
const StyledSection = styled.section<{ const StyledSection = styled.section<{
compactTop: boolean; compactTop: boolean;
@@ -18,6 +19,7 @@ const StyledSection = styled.section<{
compactTop ? theme.spacing(4) : theme.spacing(12)}; compactTop ? theme.spacing(4) : theme.spacing(12)};
position: relative; position: relative;
width: 100%; width: 100%;
z-index: ${({ compactBottom }) => (compactBottom ? 2 : 'auto')};
@media (min-width: ${theme.breakpoints.md}px) { @media (min-width: ${theme.breakpoints.md}px) {
padding-bottom: ${({ compactBottom }) => padding-bottom: ${({ compactBottom }) =>
@@ -97,11 +99,12 @@ const StyledCountCell = styled(StyledCell)`
const CornerMarker = styled.span` const CornerMarker = styled.span`
align-items: center; align-items: center;
display: flex; display: flex;
height: 12px; height: ${CORNER_SIZE}px;
justify-content: center; justify-content: center;
line-height: 0;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
width: 12px; width: ${CORNER_SIZE}px;
`; `;
const CornerTopLeft = styled(CornerMarker)` const CornerTopLeft = styled(CornerMarker)`
@@ -150,16 +153,28 @@ export function Root({
<StyledContainer> <StyledContainer>
<StyledCard backgroundColor={cardBackgroundColor}> <StyledCard backgroundColor={cardBackgroundColor}>
<CornerTopLeft aria-hidden> <CornerTopLeft aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</CornerTopLeft> </CornerTopLeft>
<CornerTopRight aria-hidden> <CornerTopRight aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</CornerTopRight> </CornerTopRight>
<CornerBottomLeft aria-hidden> <CornerBottomLeft aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</CornerBottomLeft> </CornerBottomLeft>
<CornerBottomRight aria-hidden> <CornerBottomRight aria-hidden>
<PlusIcon size={12} strokeColor={theme.colors.highlight[100]} /> <PlusIcon
size={CORNER_SIZE}
strokeColor={theme.colors.highlight[100]}
/>
</CornerBottomRight> </CornerBottomRight>
<StyledLabelCell>{label}</StyledLabelCell> <StyledLabelCell>{label}</StyledLabelCell>
<StyledLogosCell>{logos}</StyledLogosCell> <StyledLogosCell>{logos}</StyledLogosCell>
@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M3 19a9 9 0 0 1 9 0a9 9 0 0 1 9 0"/>
<path d="M3 6a9 9 0 0 1 9 0a9 9 0 0 1 9 0"/>
<path d="M3 6v13"/>
<path d="M12 6v13"/>
<path d="M21 6v13"/>
</svg>

After

Width:  |  Height:  |  Size: 368 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M7 8l-4 4l4 4"/>
<path d="M17 8l4 4l-4 4"/>
<path d="M14 4l-4 16"/>
</svg>

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 827 KiB

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 699 KiB

After

Width:  |  Height:  |  Size: 302 KiB

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="12" cy="12" r="9"/>
<path d="M3.6 9h16.8"/>
<path d="M3.6 15h16.8"/>
<path d="M11.5 3a17 17 0 0 0 0 18"/>
<path d="M12.5 3a17 17 0 0 1 0 18"/>
</svg>

After

Width:  |  Height:  |  Size: 370 B

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 5h7"/>
<path d="M9 3v2c0 4.418 -2.239 8 -5 8"/>
<path d="M5 9c0 2.144 2.952 3.908 6.7 4"/>
<path d="M12 20l4 -9l4 9"/>
<path d="M19.1 18h-6.2"/>
</svg>

After

Width:  |  Height:  |  Size: 372 B

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"/>
<path d="M8 11l0 5"/>
<path d="M8 8l0 .01"/>
<path d="M12 16l0 -5"/>
<path d="M16 16v-3a2 2 0 0 0 -4 0"/>
</svg>

After

Width:  |  Height:  |  Size: 413 B

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M3 7l6 -3l6 3l6 -3v13l-6 3l-6 -3l-6 3v-13"/>
<path d="M9 4v13"/>
<path d="M15 7v13"/>
</svg>

After

Width:  |  Height:  |  Size: 306 B

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M3 20l1.3 -3.9a9 8 0 1 1 3.4 2.9l-4.7 1"/>
<path d="M12 12l0 .01"/>
<path d="M8 12l0 .01"/>
<path d="M16 12l0 .01"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="3" y="4" width="18" height="12" rx="1"/>
<path d="M7 20h10"/>
<path d="M9 16v4"/>
<path d="M15 16v4"/>
</svg>

After

Width:  |  Height:  |  Size: 325 B

@@ -1,55 +1,5 @@
<?xml version="1.0" encoding="iso-8859-1"?> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"/>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <path d="M4 12h16"/>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> <path d="M12 4v8"/>
<svg version="1.1" id="_x36_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" </svg>
viewBox="0 0 512 512" xml:space="preserve">
<g>
<g>
<g>
<path style="fill:#504F4F;" d="M512,28.891v308.708c0,0.986-0.071,1.973-0.141,2.959c-0.07,0.916-0.212,1.832-0.423,2.678
c-2.819,13.177-14.939,23.112-29.454,23.112H30.018c-1.762,0-3.523-0.141-5.214-0.423c-12.754-2.184-22.76-12.049-24.522-24.522
c-0.071-0.493-0.141-1.057-0.141-1.55C0,339.078,0,338.374,0,337.599V28.891c0-1.903,0.212-3.805,0.564-5.638
C3.312,10.006,15.502,0,30.018,0h451.964c1.057,0,2.184,0.071,3.241,0.141c1.057,0.141,2.044,0.282,3.1,0.493
c11.838,2.466,21.069,11.697,23.183,23.183c0.141,0.704,0.282,1.409,0.352,2.114C511.929,26.918,512,27.904,512,28.891z"/>
<path style="fill:#C2C1C1;" d="M80.119,0v366.419H28.82c-1.268,0-2.537-0.071-3.805-0.282
c-12.895-1.691-23.042-11.909-24.733-24.733c-0.071-0.493-0.141-1.057-0.141-1.55C0,339.078,0,338.374,0,337.599V28.891
c0-1.903,0.212-3.805,0.564-5.638C3.171,10.006,14.798,0,28.82,0H80.119z"/>
<path style="fill:#C2C1C1;" d="M512,28.891v308.708c0,0.986-0.071,1.973-0.141,2.959c-1.48,14.445-13.741,25.861-28.679,25.861
h-51.298V0h51.298c1.691,0,3.382,0.141,4.933,0.423c11.979,2.114,21.351,11.556,23.465,23.465
c0.141,0.705,0.211,1.339,0.282,2.043C511.929,26.918,512,27.904,512,28.891z"/>
</g>
<g>
<path style="fill:#FFFFFF;" d="M246.925,28.905v313.198H62.734c-5.9,0-11.303-2.148-15.463-5.674
c-5.176-4.385-8.477-10.941-8.477-18.265V52.844c0-13.224,10.715-23.939,23.94-23.939H246.925z"/>
<g>
<path style="fill:#FFFFFF;" d="M254.348,28.905v313.198h184.191c5.9,0,11.303-2.148,15.462-5.674
c5.176-4.385,8.477-10.941,8.477-18.265V52.844c0-13.224-10.715-23.939-23.94-23.939H254.348z"/>
</g>
</g>
<polygon style="fill:#E14D4B;" points="406.02,0 406.02,91.182 373.818,73.707 341.545,91.182 341.545,0 "/>
<path style="fill:#FFFFFF;" d="M387.656,36.571h-11.063v-0.07l-3.03-9.372l-0.423-1.409h-0.141l-0.423,1.409l-3.1,9.442h-11.063
v0.141l8.949,6.624l-1.127,3.523l-2.396,7.328l0.141,0.071l9.09-6.765l9.02,6.765l0.141-0.071l-3.523-10.851l8.949-6.624V36.571z"
/>
<rect x="73.178" y="75.654" style="fill:#D8D8D8;" width="145.522" height="72.479"/>
<rect x="282.812" y="102.763" style="fill:#D8D8D8;" width="42.42" height="41.549"/>
<rect x="335.706" y="102.763" style="fill:#D8D8D8;" width="42.42" height="41.549"/>
<rect x="388.6" y="103.253" style="fill:#D8D8D8;" width="42.42" height="41.549"/>
<rect x="73.178" y="170.951" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="73.178" y="207.12" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="73.178" y="250.071" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="73.178" y="283.98" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<g>
<rect x="283.411" y="170.951" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="283.411" y="207.12" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="283.411" y="250.071" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
<rect x="283.411" y="283.98" style="fill:#D8D8D8;" width="145.522" height="6.782"/>
</g>
</g>
<path style="opacity:0.03;fill:#040000;" d="M507.842,28.82v308.708c0,0.423-0.141,0.704-0.141,1.127
c-0.563,14.868-12.402,26.988-27.199,27.693c-0.493,0.071-0.987,0.071-1.48,0.071h-51.369v-0.071H49.255l30.864-30.864
l44.746-44.745l6.764-6.765l27.129-27.129l6.764-6.765l36.149-36.149l6.835-6.835l45.873-45.873l30.934-30.934l27.552-27.552
l54.117-54.117l10.358-10.288v-0.071l9.372-9.372L406.02,9.583L415.603,0h63.419c3.805,0,7.399,0.775,10.781,2.114
c7.117,2.889,12.825,8.597,15.714,15.714c1.268,3.03,2.044,6.342,2.184,9.794C507.701,28.045,507.842,28.468,507.842,28.82z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 13a8 8 0 0 1 7 7a6 6 0 0 0 3 -5a9 9 0 0 0 6 -8a3 3 0 0 0 -3 -3a9 9 0 0 0 -8 6a6 6 0 0 0 -5 3"/>
<path d="M7 14a6 6 0 0 0 -3 6a6 6 0 0 0 6 -3"/>
<circle cx="15" cy="9" r="1"/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

@@ -0,0 +1 @@
<svg width="24" height="24" fill="#143055" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Nx</title><path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.1 KiB

@@ -0,0 +1 @@
<svg width="24" height="24" fill="#61DAFB" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

@@ -0,0 +1 @@
<svg width="24" height="24" fill="#FF4438" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Redis</title><path d="M22.71 13.145c-1.66 2.092-3.452 4.483-7.038 4.483-3.203 0-4.397-2.825-4.48-5.12.701 1.484 2.073 2.685 4.214 2.63 4.117-.133 6.94-3.852 6.94-7.239 0-4.05-3.022-6.972-8.268-6.972-3.752 0-8.4 1.428-11.455 3.685C2.59 6.937 3.885 9.958 4.35 9.626c2.648-1.904 4.748-3.13 6.784-3.744C8.12 9.244.886 17.05 0 18.425c.1 1.261 1.66 4.648 2.424 4.648.232 0 .431-.133.664-.365a100.49 100.49 0 0 0 5.54-6.765c.222 3.104 1.748 6.898 6.014 6.898 3.819 0 7.604-2.756 9.33-8.965.2-.764-.73-1.361-1.261-.73zm-4.349-5.013c0 1.959-1.926 2.922-3.685 2.922-.941 0-1.664-.247-2.235-.568 1.051-1.592 2.092-3.225 3.21-4.973 1.972.334 2.71 1.43 2.71 2.619z"/></svg>

After

Width:  |  Height:  |  Size: 776 B

@@ -0,0 +1 @@
<svg width="24" height="24" fill="#3178C6" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>TypeScript</title><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1.002l3.086 -6.253l3.086 6.253l6.9 1.002l-5 4.867l1.179 6.873z"/>
</svg>

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#4A38F5" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M4 4l11.733 16h4.267l-11.733 -16z"/>
<path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772"/>
</svg>

After

Width:  |  Height:  |  Size: 310 B