mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
update stack builder icons and ui
This commit is contained in:
@@ -1,20 +1,5 @@
|
||||
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="mask0_408_139" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="180" height="180">
|
||||
<circle cx="90" cy="90" r="90" fill="black"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_408_139)">
|
||||
<circle cx="90" cy="90" r="87" fill="black" stroke="white" stroke-width="6"/>
|
||||
<path d="M149.508 157.52L69.142 54H54V125.97H66.1136V69.3836L139.999 164.845C143.333 162.614 146.509 160.165 149.508 157.52Z" fill="url(#paint0_linear_408_139)"/>
|
||||
<rect x="115" y="54" width="12" height="72" fill="url(#paint1_linear_408_139)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_408_139" x1="109" y1="116.5" x2="144.5" y2="160.5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_408_139" x1="121" y1="54" x2="120.799" y2="106.875" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="white"/>
|
||||
<stop offset="1" stop-color="white" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg viewBox="0 0 64 55.425" width="64" height="55.425" version="1.0" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect id="background" width="100%" height="100%" fill="none" />
|
||||
<path id="emblem" d="m32 0-14.255 24.69c5.409-1.6676 11.228-1.9148 16.869-0.58434l4.8177 1.1372-4.5328 19.22-4.8247-1.1372c-5.9293-1.3987-11.628 1.716-14.036 6.6851l-4.4595-2.1575c3.4034-7.0291 11.424-11.285 19.636-9.3476l2.2595-9.579c-8.0938-1.9081-16.624-9e-3 -23.145 5.153-6.5204 5.1607-10.329 13.028-10.329 21.344l64 7.9e-4z" fill="#60a5fa" stroke-linecap="square" stroke-width="4.8768" style="paint-order:markers fill stroke" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 652 B |
1
apps/web/public/icon/turso.svg
Normal file
1
apps/web/public/icon/turso.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg fill="none" height="170" viewBox="0 0 201 170" width="201" xmlns="http://www.w3.org/2000/svg"><path d="m100.055 170c-2.1901 0-18.2001-12.8-21.3001-16.45-2.44 3.73-6.44 7.96-6.44 7.96-11.05-5.57-25.17-20.06-27.83-25.13-2.62-5-12.13-62.58-12.39-79.3-.34-9.41 5.85-28.49 67.9601-28.49 62.11 0 68.29 19.08 67.96 28.49-.25 16.72-9.76 74.3-12.39 79.3-2.66 5.07-16.78 19.56-27.83 25.13 0 0-4-4.23-6.44-7.96-3.1 3.65-19.11 16.45-21.3 16.45z" fill="#1ebca1"/><path d="m100.055 132.92c-20.7301 0-33.9601-10.95-33.9601-10.95l1.91-26.67-21.75-1.94-3.91-31.55h115.4301l-3.91 31.55-21.75 1.94 1.91 26.67s-13.23 10.95-33.96 10.95z" fill="#183134"/><path d="m121.535 75.79 78.52-27.18c-4.67-27.94-29.16-48.61-29.16-48.61v30.78l-14.54 3.75-9.11-10.97-7.8 15.34-39.38 10.16-39.3801-10.16-7.8-15.34-9.11 10.97-14.54-3.75v-30.78s-24.50997 20.67-29.1799684 48.61l78.5199684 27.18-2.8 37.39c6.7 1.7 13.75 3.39 24.2801 3.39 10.53 0 17.57-1.69 24.27-3.39l-2.8-37.39z" fill="#4ff8d2"/></svg>
|
||||
|
After Width: | Height: | Size: 972 B |
@@ -77,7 +77,11 @@ const TechIcon = ({
|
||||
icon,
|
||||
name,
|
||||
className,
|
||||
}: { icon: string; name: string; className?: string }) => {
|
||||
}: {
|
||||
icon: string;
|
||||
name: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
if (icon.startsWith("/icon/")) {
|
||||
return (
|
||||
<Image
|
||||
@@ -154,6 +158,7 @@ const StackArchitect = () => {
|
||||
const isPWACompat = hasPWACompatibleFrontend(nextStack.frontend);
|
||||
const isNative = hasNativeFrontend(nextStack.frontend);
|
||||
|
||||
// Database/ORM/Auth/DB Setup auto-fix
|
||||
if (nextStack.database === "none") {
|
||||
if (nextStack.orm !== "none") {
|
||||
nextStack.orm = "none";
|
||||
@@ -167,13 +172,11 @@ const StackArchitect = () => {
|
||||
nextStack.dbSetup = "none";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.database === "mongodb") {
|
||||
if (nextStack.orm !== "prisma") {
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextStack.database === "mongodb" && nextStack.orm !== "prisma") {
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.dbSetup === "turso") {
|
||||
if (nextStack.database !== "sqlite") {
|
||||
nextStack.database = "sqlite";
|
||||
@@ -183,7 +186,8 @@ const StackArchitect = () => {
|
||||
nextStack.orm = "drizzle";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "prisma-postgres") {
|
||||
}
|
||||
if (nextStack.dbSetup === "prisma-postgres") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
@@ -192,7 +196,8 @@ const StackArchitect = () => {
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "mongodb-atlas") {
|
||||
}
|
||||
if (nextStack.dbSetup === "mongodb-atlas") {
|
||||
if (nextStack.database !== "mongodb") {
|
||||
nextStack.database = "mongodb";
|
||||
changed = true;
|
||||
@@ -201,29 +206,26 @@ const StackArchitect = () => {
|
||||
nextStack.orm = "prisma";
|
||||
changed = true;
|
||||
}
|
||||
} else if (nextStack.dbSetup === "neon") {
|
||||
if (nextStack.database !== "postgres") {
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (nextStack.dbSetup === "neon" && nextStack.database !== "postgres") {
|
||||
nextStack.database = "postgres";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// API auto-fix for Native
|
||||
if (isNative && nextStack.api !== "trpc") {
|
||||
nextStack.api = "trpc";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Addons auto-fix
|
||||
const incompatibleAddons: string[] = [];
|
||||
if (!isPWACompat) {
|
||||
incompatibleAddons.push("pwa", "tauri");
|
||||
}
|
||||
if (!isPWACompat) incompatibleAddons.push("pwa", "tauri");
|
||||
const originalAddonsLength = nextStack.addons.length;
|
||||
nextStack.addons = nextStack.addons.filter(
|
||||
(addon) => !incompatibleAddons.includes(addon),
|
||||
);
|
||||
if (nextStack.addons.length !== originalAddonsLength) {
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.addons.length !== originalAddonsLength) changed = true;
|
||||
if (
|
||||
nextStack.addons.includes("husky") &&
|
||||
!nextStack.addons.includes("biome")
|
||||
@@ -233,24 +235,17 @@ const StackArchitect = () => {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// Examples auto-fix
|
||||
const incompatibleExamples: string[] = [];
|
||||
if (!isWeb) {
|
||||
incompatibleExamples.push("todo", "ai");
|
||||
}
|
||||
if (nextStack.database === "none") {
|
||||
incompatibleExamples.push("todo");
|
||||
}
|
||||
if (nextStack.backendFramework === "elysia") {
|
||||
if (!isWeb) incompatibleExamples.push("todo", "ai");
|
||||
if (nextStack.database === "none") incompatibleExamples.push("todo");
|
||||
if (nextStack.backendFramework === "elysia")
|
||||
incompatibleExamples.push("ai");
|
||||
}
|
||||
|
||||
const originalExamplesLength = nextStack.examples.length;
|
||||
nextStack.examples = nextStack.examples.filter(
|
||||
(ex) => !incompatibleExamples.includes(ex),
|
||||
);
|
||||
if (nextStack.examples.length !== originalExamplesLength) {
|
||||
changed = true;
|
||||
}
|
||||
if (nextStack.examples.length !== originalExamplesLength) changed = true;
|
||||
|
||||
return changed ? nextStack : currentStack;
|
||||
});
|
||||
@@ -368,7 +363,9 @@ const StackArchitect = () => {
|
||||
}
|
||||
}
|
||||
|
||||
return `${base} ${projectName}${flags.length > 0 ? ` ${flags.join(" ")}` : ""}`;
|
||||
return `${base} ${projectName}${
|
||||
flags.length > 0 ? ` ${flags.join(" ")}` : ""
|
||||
}`;
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -386,7 +383,7 @@ const StackArchitect = () => {
|
||||
|
||||
if (isNative && stack.frontend.length > 1) {
|
||||
notes.frontend.notes.push(
|
||||
"React Native requires the tRPC API when used with other frontends. oRPC will be disabled.",
|
||||
"React Native requires the tRPC API when used with other frontends. oRPC will be disabled. (temporarily)",
|
||||
);
|
||||
if (stack.api !== "trpc") notes.frontend.hasIssue = true;
|
||||
}
|
||||
@@ -963,7 +960,9 @@ const StackArchitect = () => {
|
||||
.map((tech) => (
|
||||
<span
|
||||
key={`${category}-${tech.id}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(category)}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(
|
||||
category,
|
||||
)}`}
|
||||
>
|
||||
<TechIcon
|
||||
icon={tech.icon}
|
||||
@@ -995,7 +994,9 @@ const StackArchitect = () => {
|
||||
return (
|
||||
<span
|
||||
key={`${category}-${tech.id}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(category)}`}
|
||||
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(
|
||||
category,
|
||||
)}`}
|
||||
>
|
||||
<TechIcon
|
||||
icon={tech.icon}
|
||||
@@ -1064,10 +1065,18 @@ const StackArchitect = () => {
|
||||
|
||||
{notesInfo?.notes && notesInfo.notes.length > 0 && (
|
||||
<div
|
||||
className={`mb-4 rounded-md border p-3 ${notesInfo.hasIssue ? "border-orange-200 bg-orange-50 dark:border-orange-800 dark:bg-orange-900/20" : "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20"}`}
|
||||
className={`mb-4 rounded-md border p-3 ${
|
||||
notesInfo.hasIssue
|
||||
? "border-orange-200 bg-orange-50 dark:border-orange-800 dark:bg-orange-900/20"
|
||||
: "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20"
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
className={`mb-1 flex items-center gap-2 font-medium text-xs sm:text-sm ${notesInfo.hasIssue ? "text-orange-800 dark:text-orange-300" : "text-blue-800 dark:text-blue-300"}`}
|
||||
className={`mb-1 flex items-center gap-2 font-medium text-xs sm:text-sm ${
|
||||
notesInfo.hasIssue
|
||||
? "text-orange-800 dark:text-orange-300"
|
||||
: "text-blue-800 dark:text-blue-300"
|
||||
}`}
|
||||
>
|
||||
<InfoIcon className="h-4 w-4 flex-shrink-0" />
|
||||
<span>
|
||||
@@ -1077,7 +1086,11 @@ const StackArchitect = () => {
|
||||
</span>
|
||||
</div>
|
||||
<ul
|
||||
className={`list-inside list-disc space-y-1 text-xs ${notesInfo.hasIssue ? "text-orange-700 dark:text-orange-400" : "text-blue-700 dark:text-blue-400"}`}
|
||||
className={`list-inside list-disc space-y-1 text-xs ${
|
||||
notesInfo.hasIssue
|
||||
? "text-orange-700 dark:text-orange-400"
|
||||
: "text-blue-700 dark:text-blue-400"
|
||||
}`}
|
||||
>
|
||||
{notesInfo.notes.map((note, index) => (
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
|
||||
@@ -1108,7 +1121,7 @@ const StackArchitect = () => {
|
||||
categoryKey as keyof typeof TECH_OPTIONS,
|
||||
tech.id,
|
||||
);
|
||||
const isDisabled = !!disabledReason;
|
||||
const isDisabled = !!disabledReason && !isSelected;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
@@ -1120,7 +1133,11 @@ const StackArchitect = () => {
|
||||
} ${
|
||||
isSelected
|
||||
? "border-blue-400 bg-blue-100 ring-1 ring-blue-300 dark:border-blue-600 dark:bg-blue-900/40 dark:ring-blue-700"
|
||||
: `border-gray-300 dark:border-gray-700 ${!isDisabled ? "hover:border-gray-400 hover:bg-gray-200/50 dark:hover:border-gray-600 dark:hover:bg-gray-800/50" : ""}`
|
||||
: `border-gray-300 dark:border-gray-700 ${
|
||||
!isDisabled
|
||||
? "hover:border-gray-400 hover:bg-gray-200/50 dark:hover:border-gray-600 dark:hover:bg-gray-800/50"
|
||||
: ""
|
||||
}`
|
||||
}`}
|
||||
title={
|
||||
isDisabled
|
||||
|
||||
@@ -35,8 +35,9 @@ export const TECH_OPTIONS = {
|
||||
},
|
||||
{
|
||||
id: "tanstack-start",
|
||||
name: "TanStack Start",
|
||||
description: "Quick starter template from TanStack",
|
||||
name: "TanStack Start (beta)",
|
||||
description:
|
||||
"Full-stack React and Solid framework powered by TanStack Router",
|
||||
icon: "/icon/tanstack.svg",
|
||||
color: "from-purple-400 to-purple-600",
|
||||
default: false,
|
||||
@@ -61,7 +62,7 @@ export const TECH_OPTIONS = {
|
||||
id: "none",
|
||||
name: "No Frontend",
|
||||
description: "API-only backend",
|
||||
icon: "⚙️", // Keep emoji for missing icon
|
||||
icon: "⚙️",
|
||||
color: "from-gray-400 to-gray-600",
|
||||
default: false,
|
||||
},
|
||||
@@ -181,7 +182,7 @@ export const TECH_OPTIONS = {
|
||||
id: "turso",
|
||||
name: "Turso",
|
||||
description: "SQLite cloud database powered by libSQL",
|
||||
icon: "/icon/sqlite.svg",
|
||||
icon: "/icon/turso.svg",
|
||||
color: "from-pink-400 to-pink-600",
|
||||
},
|
||||
{
|
||||
@@ -195,7 +196,7 @@ export const TECH_OPTIONS = {
|
||||
id: "prisma-postgres",
|
||||
name: "Prisma PostgreSQL",
|
||||
description: "Set up PostgreSQL with Prisma",
|
||||
icon: "/icon/postgres.svg",
|
||||
icon: "/icon/prisma.svg",
|
||||
color: "from-indigo-400 to-indigo-600",
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user