mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
fix(web): improve builder responsiveness and add npm icon
This commit is contained in:
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill="#cb3837" d="M2 38.5h124v43.71H64v7.29H36.44v-7.29H2Zm6.89 36.43h13.78V53.07h6.89v21.86h6.89V45.79H8.89Zm34.44-29.14v36.42h13.78v-7.28h13.78V45.79Zm13.78 7.29H64v14.56h-6.89Zm20.67-7.29v29.14h13.78V53.07h6.89v21.86h6.89V53.07h6.89v21.86h6.89V45.79Z"/></svg>
|
<svg viewBox="268.5 268.5 1962.9 1962.9" xmlns="http://www.w3.org/2000/svg" width="2500" height="2500"><path d="M1241.5 268.5h-973v1962.9h972.9V763.5h495v1467.9h495V268.5z"/></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 181 B |
@@ -87,27 +87,11 @@ export default function SponsorsSection() {
|
|||||||
[{loadingSponsors ? "LOADING..." : sponsors.length} RECORDS]
|
[{loadingSponsors ? "LOADING..." : sponsors.length} RECORDS]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-8 rounded border border-border p-4">
|
|
||||||
<div className="flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-foreground">
|
|
||||||
Amazing organizations and individuals supporting this project
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-muted-foreground">
|
|
||||||
Your support helps maintain and improve Better-T-Stack
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{loadingSponsors ? (
|
{loadingSponsors ? (
|
||||||
<div className="rounded border border-border p-8">
|
<div className="rounded border border-border p-8">
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
|
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
|
||||||
<span className=" text-muted-foreground">LOADING_SPONSORS.EXE</span>
|
<span className=" text-muted-foreground">LOADING_SPONSORS.SH</span>
|
||||||
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
|
<div className="h-2 w-2 animate-pulse rounded-full bg-primary" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -143,7 +127,7 @@ export default function SponsorsSection() {
|
|||||||
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
|
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
|
||||||
>
|
>
|
||||||
<Heart className="h-4 w-4" />
|
<Heart className="h-4 w-4" />
|
||||||
<span>BECOME_SPONSOR.EXE</span>
|
<span>BECOME_SPONSOR.SH</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -151,15 +135,15 @@ export default function SponsorsSection() {
|
|||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
{currentSponsors.length > 0 && (
|
{currentSponsors.length > 0 && (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-2">
|
{/* <div className="flex items-center gap-2">
|
||||||
<span className="text-primary text-sm">▶</span>
|
<span className="text-primary text-sm">▶</span>
|
||||||
<span className="font-semibold text-foreground text-sm">
|
<span className="font-semibold text-foreground text-sm">
|
||||||
ACTIVE_SPONSORS.EXE
|
ACTIVE_SPONSORS.SH
|
||||||
</span>
|
</span>
|
||||||
<span className="text-muted-foreground text-xs">
|
<span className="text-muted-foreground text-xs">
|
||||||
({currentSponsors.length})
|
({currentSponsors.length})
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div> */}
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||||
{currentSponsors.map((entry, index) => {
|
{currentSponsors.map((entry, index) => {
|
||||||
const since = new Date(entry.createdAt).toLocaleDateString(
|
const since = new Date(entry.createdAt).toLocaleDateString(
|
||||||
@@ -378,7 +362,7 @@ export default function SponsorsSection() {
|
|||||||
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
|
className="flex items-center justify-center gap-2 text-primary transition-colors hover:text-accent"
|
||||||
>
|
>
|
||||||
<Heart className="h-4 w-4" />
|
<Heart className="h-4 w-4" />
|
||||||
<span>SUPPORT_PROJECT.EXE</span>
|
<span>SUPPORT_PROJECT.SH</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1449,157 +1449,162 @@ const StackBuilder = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<div
|
<div className="grid w-full grid-cols-1 overflow-hidden border-border text-foreground sm:grid-cols-[auto_1fr]">
|
||||||
className={cn(
|
<div className="flex w-full flex-col border-border border-r sm:max-w-3xs md:max-w-xs lg:max-w-sm">
|
||||||
"grid grid-cols-1 overflow-hidden border-border text-foreground",
|
<ScrollArea className="flex-1">
|
||||||
)}
|
<div className="grid h-full grid-rows-[auto_1fr] justify-between p-3 sm:p-4 md:h-[calc(100vh-64px)]">
|
||||||
>
|
<div className="flex flex-col space-y-3 sm:space-y-4">
|
||||||
<div className="grid grid-cols-1 overflow-hidden sm:grid-cols-[auto_1fr]">
|
<label className="flex flex-col">
|
||||||
<div className="flex h-full max-w-full flex-col justify-between border-border border-r p-4 sm:max-w-3xs md:max-w-xs lg:max-w-sm">
|
<span className="mb-1 text-muted-foreground text-xs">
|
||||||
<div className="flex flex-col space-y-4">
|
Project Name:
|
||||||
<label className="flex flex-col">
|
</span>
|
||||||
<span className="mb-1 text-muted-foreground text-xs">
|
<input
|
||||||
Project Name:
|
type="text"
|
||||||
</span>
|
value={stack.projectName || ""}
|
||||||
<input
|
onChange={(e) => {
|
||||||
type="text"
|
const newValue = e.target.value;
|
||||||
value={stack.projectName || ""}
|
setStack({ projectName: newValue });
|
||||||
onChange={(e) => {
|
}}
|
||||||
const newValue = e.target.value;
|
|
||||||
setStack({ projectName: newValue });
|
|
||||||
}}
|
|
||||||
className={cn(
|
|
||||||
"w-full rounded border px-2 py-1 text-sm focus:outline-none",
|
|
||||||
projectNameError
|
|
||||||
? "border-destructive bg-destructive/10 text-destructive-foreground"
|
|
||||||
: "border-border focus:border-primary",
|
|
||||||
)}
|
|
||||||
placeholder="my-better-t-app"
|
|
||||||
/>
|
|
||||||
{projectNameError && (
|
|
||||||
<p className="mt-1 text-destructive text-xs">
|
|
||||||
{projectNameError}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={resetStack}
|
|
||||||
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
|
||||||
title="Reset to defaults"
|
|
||||||
>
|
|
||||||
<RefreshCw className="h-3 w-3" />
|
|
||||||
Reset
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={getRandomStack}
|
|
||||||
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
|
||||||
title="Generate a random stack"
|
|
||||||
>
|
|
||||||
<Shuffle className="h-3 w-3" />
|
|
||||||
Random
|
|
||||||
</button>
|
|
||||||
{lastSavedStack && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={loadSavedStack}
|
|
||||||
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
|
||||||
title="Load saved preferences"
|
|
||||||
>
|
|
||||||
<Settings className="h-3 w-3" />
|
|
||||||
Load Saved
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={saveCurrentStack}
|
|
||||||
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
|
||||||
title="Save current preferences"
|
|
||||||
>
|
|
||||||
<Star className="h-3 w-3" />
|
|
||||||
<span>Save</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={shareToTwitter}
|
|
||||||
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
|
||||||
title="Share to Twitter"
|
|
||||||
>
|
|
||||||
<Share2 className="h-3 w-3" />
|
|
||||||
Share
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="relative rounded border border-border p-2">
|
|
||||||
<div className="flex">
|
|
||||||
<span className="mr-2 select-none text-chart-4">$</span>
|
|
||||||
<code className="block break-all text-muted-foreground text-xs sm:text-sm">
|
|
||||||
{command}
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex justify-end">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={copyToClipboard}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-1 rounded px-2 py-1 text-xs transition-colors",
|
"w-full rounded border px-2 py-1 text-sm focus:outline-none",
|
||||||
copied
|
projectNameError
|
||||||
? "bg-muted text-chart-4"
|
? "border-destructive bg-destructive/10 text-destructive-foreground"
|
||||||
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
: "border-border focus:border-primary",
|
||||||
)}
|
)}
|
||||||
title={copied ? "Copied!" : "Copy command"}
|
placeholder="my-better-t-app"
|
||||||
>
|
/>
|
||||||
{copied ? (
|
{projectNameError && (
|
||||||
<>
|
<p className="mt-1 text-destructive text-xs">
|
||||||
<Check className="h-3 w-3 flex-shrink-0" />
|
{projectNameError}
|
||||||
<span>Copied</span>
|
</p>
|
||||||
</>
|
)}
|
||||||
) : (
|
</label>
|
||||||
<>
|
|
||||||
<ClipboardCopy className="h-3 w-3 flex-shrink-0" />
|
<div className="flex flex-wrap gap-1.5 sm:gap-2">
|
||||||
<span>Copy</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="mb-2 font-medium text-foreground text-sm">
|
|
||||||
Selected Stack
|
|
||||||
</h3>
|
|
||||||
<div className="flex flex-wrap gap-1.5">{selectedBadges}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-auto hidden border-border border-t pt-4 md:flex md:flex-col">
|
|
||||||
<h3 className="mb-2 font-medium text-foreground text-sm">
|
|
||||||
Quick Presets
|
|
||||||
</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-2">
|
|
||||||
{PRESET_TEMPLATES.map((preset) => (
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
key={preset.id}
|
onClick={resetStack}
|
||||||
onClick={() => applyPreset(preset.id)}
|
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
||||||
className="rounded border border-border p-2 text-left transition-colors hover:bg-muted"
|
title="Reset to defaults"
|
||||||
title={preset.description}
|
|
||||||
>
|
>
|
||||||
<div className="font-medium text-foreground text-sm">
|
<RefreshCw className="h-3 w-3" />
|
||||||
{preset.name}
|
<span className="">Reset</span>
|
||||||
</div>
|
|
||||||
<div className="text-muted-foreground text-xs">
|
|
||||||
{preset.description}
|
|
||||||
</div>
|
|
||||||
</button>
|
</button>
|
||||||
))}
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={getRandomStack}
|
||||||
|
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
||||||
|
title="Generate a random stack"
|
||||||
|
>
|
||||||
|
<Shuffle className="h-3 w-3" />
|
||||||
|
<span className="">Random</span>
|
||||||
|
</button>
|
||||||
|
{lastSavedStack && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={loadSavedStack}
|
||||||
|
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
||||||
|
title="Load saved preferences"
|
||||||
|
>
|
||||||
|
<Settings className="h-3 w-3" />
|
||||||
|
<span className="">Load</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={saveCurrentStack}
|
||||||
|
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
||||||
|
title="Save current preferences"
|
||||||
|
>
|
||||||
|
<Star className="h-3 w-3" />
|
||||||
|
<span className="">Save</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={shareToTwitter}
|
||||||
|
className="flex items-center gap-1 rounded border border-border px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
|
||||||
|
title="Share to Twitter"
|
||||||
|
>
|
||||||
|
<Share2 className="h-3 w-3" />
|
||||||
|
<span className="">Share</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative rounded border border-border p-2">
|
||||||
|
<div className="flex">
|
||||||
|
<span className="mr-2 select-none text-chart-4">$</span>
|
||||||
|
<code className="block break-all text-muted-foreground text-xs sm:text-sm">
|
||||||
|
{command}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 flex justify-end">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={copyToClipboard}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-1 rounded px-2 py-1 text-xs transition-colors",
|
||||||
|
copied
|
||||||
|
? "bg-muted text-chart-4"
|
||||||
|
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
||||||
|
)}
|
||||||
|
title={copied ? "Copied!" : "Copy command"}
|
||||||
|
>
|
||||||
|
{copied ? (
|
||||||
|
<>
|
||||||
|
<Check className="h-3 w-3 flex-shrink-0" />
|
||||||
|
<span className="">Copied</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ClipboardCopy className="h-3 w-3 flex-shrink-0" />
|
||||||
|
<span className="">Copy</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3 className="mb-2 font-medium text-foreground text-sm">
|
||||||
|
Selected Stack
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap gap-1.5">{selectedBadges}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-auto hidden border-border border-t pt-4 lg:flex lg:flex-col">
|
||||||
|
<h3 className="mb-2 font-medium text-foreground text-sm">
|
||||||
|
Quick Presets
|
||||||
|
</h3>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
{PRESET_TEMPLATES.map((preset) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
key={preset.id}
|
||||||
|
onClick={() => applyPreset(preset.id)}
|
||||||
|
className="rounded border border-border p-2 text-left transition-colors hover:bg-muted"
|
||||||
|
title={preset.description}
|
||||||
|
>
|
||||||
|
<div className="font-medium text-foreground text-sm">
|
||||||
|
{preset.name}
|
||||||
|
</div>
|
||||||
|
<div className="text-muted-foreground text-xs">
|
||||||
|
{preset.description}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ScrollArea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-1 flex-col overflow-hidden">
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
ref={contentRef}
|
ref={contentRef}
|
||||||
className="overflow-hidden scroll-smooth"
|
className="flex-1 overflow-hidden scroll-smooth"
|
||||||
>
|
>
|
||||||
<main className="p-4">
|
<main className="p-3 sm:p-4">
|
||||||
{CATEGORY_ORDER.map((categoryKey) => {
|
{CATEGORY_ORDER.map((categoryKey) => {
|
||||||
const categoryOptions =
|
const categoryOptions =
|
||||||
TECH_OPTIONS[categoryKey as keyof typeof TECH_OPTIONS] || [];
|
TECH_OPTIONS[categoryKey as keyof typeof TECH_OPTIONS] || [];
|
||||||
@@ -1618,11 +1623,11 @@ const StackBuilder = () => {
|
|||||||
}}
|
}}
|
||||||
key={categoryKey}
|
key={categoryKey}
|
||||||
id={`section-${categoryKey}`}
|
id={`section-${categoryKey}`}
|
||||||
className="mb-8 scroll-mt-4"
|
className="mb-6 scroll-mt-4 sm:mb-8"
|
||||||
>
|
>
|
||||||
<div className="mb-3 flex items-center border-border border-b pb-2 text-muted-foreground">
|
<div className="mb-3 flex items-center border-border border-b pb-2 text-muted-foreground">
|
||||||
<Terminal className="mr-2 h-5 w-5 flex-shrink-0" />
|
<Terminal className="mr-2 h-4 w-4 flex-shrink-0 sm:h-5 sm:w-5" />
|
||||||
<h2 className="font-semibold text-base text-foreground">
|
<h2 className="font-semibold text-foreground text-sm sm:text-base">
|
||||||
{categoryDisplayName}
|
{categoryDisplayName}
|
||||||
</h2>
|
</h2>
|
||||||
{compatibilityAnalysis.notes[categoryKey]?.hasIssue && (
|
{compatibilityAnalysis.notes[categoryKey]?.hasIssue && (
|
||||||
@@ -1643,7 +1648,7 @@ const StackBuilder = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-3 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4">
|
<div className="grid grid-cols-1 xs:grid-cols-2 gap-2 sm:gap-3 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4">
|
||||||
{filteredOptions.map((tech) => {
|
{filteredOptions.map((tech) => {
|
||||||
let isSelected = false;
|
let isSelected = false;
|
||||||
const category = categoryKey as keyof StackState;
|
const category = categoryKey as keyof StackState;
|
||||||
@@ -1673,7 +1678,7 @@ const StackBuilder = () => {
|
|||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<motion.div
|
<motion.div
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative cursor-pointer rounded border p-2 transition-all",
|
"relative cursor-pointer rounded border p-2 transition-all sm:p-3",
|
||||||
isSelected
|
isSelected
|
||||||
? "border-primary bg-primary/10"
|
? "border-primary bg-primary/10"
|
||||||
: isDisabled
|
: isDisabled
|
||||||
@@ -1697,12 +1702,12 @@ const StackBuilder = () => {
|
|||||||
<TechIcon
|
<TechIcon
|
||||||
icon={tech.icon}
|
icon={tech.icon}
|
||||||
name={tech.name}
|
name={tech.name}
|
||||||
className="mr-1.5 h-4 w-4"
|
className="mr-1.5 h-3 w-3 sm:h-4 sm:w-4"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
className={cn(
|
className={cn(
|
||||||
"font-medium text-sm",
|
"font-medium text-xs sm:text-sm",
|
||||||
isSelected
|
isSelected
|
||||||
? "text-primary"
|
? "text-primary"
|
||||||
: "text-foreground",
|
: "text-foreground",
|
||||||
|
|||||||
@@ -150,22 +150,6 @@ export default function Testimonials() {
|
|||||||
[{TWEET_IDS.length} ENTRIES]
|
[{TWEET_IDS.length} ENTRIES]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-8 rounded border border-border p-4">
|
|
||||||
<div className="flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-foreground">
|
|
||||||
Community feedback from X (Twitter)
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-muted-foreground">
|
|
||||||
Real developers sharing their experience
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="block sm:hidden">
|
<div className="block sm:hidden">
|
||||||
<motion.div
|
<motion.div
|
||||||
className="flex flex-col gap-4"
|
className="flex flex-col gap-4"
|
||||||
|
|||||||
@@ -953,7 +953,7 @@ export default function AnalyticsPage() {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Terminal className="h-5 w-5 text-primary" />
|
<Terminal className="h-5 w-5 text-primary" />
|
||||||
<span className="font-bold text-lg sm:text-xl">
|
<span className="font-bold text-lg sm:text-xl">
|
||||||
ANALYTICS_DASHBOARD.EXE
|
ANALYTICS_DASHBOARD.SH
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden h-px flex-1 bg-border sm:block" />
|
<div className="hidden h-px flex-1 bg-border sm:block" />
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export default function HomePage() {
|
|||||||
<div className="group cursor-pointer rounded border border-border p-4">
|
<div className="group cursor-pointer rounded border border-border p-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ChevronRight className="h-4 w-4 text-primary" />
|
<ChevronRight className="h-4 w-4 text-primary" />
|
||||||
<span className=" font-semibold">STACK_BUILDER.EXE</span>
|
<span className=" font-semibold">STACK_BUILDER.SH</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="mt-2 text-muted-foreground text-sm">
|
<p className="mt-2 text-muted-foreground text-sm">
|
||||||
[EXEC] Interactive configuration wizard
|
[EXEC] Interactive configuration wizard
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export default function ShowcaseItem({
|
|||||||
className="flex items-center gap-2 rounded border border-border bg-primary/10 px-3 py-2 text-primary text-sm transition-all hover:bg-primary/20 hover:text-primary"
|
className="flex items-center gap-2 rounded border border-border bg-primary/10 px-3 py-2 text-primary text-sm transition-all hover:bg-primary/20 hover:text-primary"
|
||||||
>
|
>
|
||||||
<Monitor className="h-3 w-3" />
|
<Monitor className="h-3 w-3" />
|
||||||
<span>LAUNCH_DEMO.EXE</span>
|
<span>LAUNCH_DEMO.SH</span>
|
||||||
<ExternalLink className="ml-auto h-3 w-3" />
|
<ExternalLink className="ml-auto h-3 w-3" />
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -66,6 +66,23 @@ const showcaseProjects = [
|
|||||||
liveUrl: "https://gl1.chat/?ref=better-t-stack",
|
liveUrl: "https://gl1.chat/?ref=better-t-stack",
|
||||||
tags: ["tRPC", "Drizzle", "Elysia", "Vite", "TanStack Router"],
|
tags: ["tRPC", "Drizzle", "Elysia", "Vite", "TanStack Router"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Transmogged",
|
||||||
|
description:
|
||||||
|
"Turn your video game characters into different styles worth showing off. Create profile pictures that impress you and your friends.",
|
||||||
|
imageUrl: "https://images.transmogged.com/transmogged-home.png",
|
||||||
|
liveUrl: "https://transmogged.com",
|
||||||
|
tags: [
|
||||||
|
"TanStack Router",
|
||||||
|
"Better Auth",
|
||||||
|
"Biome",
|
||||||
|
"bun",
|
||||||
|
"PostgreSQL",
|
||||||
|
"Drizzle",
|
||||||
|
"tRPC",
|
||||||
|
"Hono",
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ShowcasePage() {
|
export default function ShowcasePage() {
|
||||||
@@ -77,7 +94,7 @@ export default function ShowcasePage() {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Terminal className="h-4 w-4 text-primary" />
|
<Terminal className="h-4 w-4 text-primary" />
|
||||||
<span className="font-bold text-lg sm:text-xl">
|
<span className="font-bold text-lg sm:text-xl">
|
||||||
PROJECT_SHOWCASE.EXE
|
PROJECT_SHOWCASE.SH
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-px flex-1 bg-border" />
|
<div className="h-px flex-1 bg-border" />
|
||||||
@@ -85,27 +102,6 @@ export default function ShowcasePage() {
|
|||||||
[{showcaseProjects.length} PROJECTS FOUND]
|
[{showcaseProjects.length} PROJECTS FOUND]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-8 rounded border border-border p-4">
|
|
||||||
<div className="flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-foreground">
|
|
||||||
user@dev-machine:~/showcase$ ls -la
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-muted-foreground">
|
|
||||||
Discover amazing projects built with Better-T-Stack
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 flex items-center gap-2 text-sm">
|
|
||||||
<span className="text-primary">$</span>
|
|
||||||
<span className=" text-muted-foreground">
|
|
||||||
Real-world implementations showcasing stack capabilities
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-3">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
|
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import discordLogo from "@/public/icon/discord.svg";
|
import discordLogo from "@/public/icon/discord.svg";
|
||||||
|
import npmLogo from "@/public/icon/npm.svg";
|
||||||
import mainLogo from "@/public/logo.svg";
|
import mainLogo from "@/public/logo.svg";
|
||||||
|
|
||||||
export const logo = (
|
export const logo = (
|
||||||
@@ -45,13 +46,31 @@ export const baseOptions: BaseLayoutProps = {
|
|||||||
url: "/showcase",
|
url: "/showcase",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: (
|
text: "NPM",
|
||||||
|
icon: (
|
||||||
|
<Image
|
||||||
|
src={npmLogo}
|
||||||
|
alt="npm"
|
||||||
|
className="size-4 invert-0 dark:invert"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
label: "NPM",
|
||||||
|
type: "icon",
|
||||||
|
url: "https://www.npmjs.com/package/create-better-t-stack",
|
||||||
|
external: true,
|
||||||
|
secondary: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "Discord",
|
||||||
|
icon: (
|
||||||
<Image
|
<Image
|
||||||
src={discordLogo}
|
src={discordLogo}
|
||||||
alt="discord"
|
alt="discord"
|
||||||
className="size-5 invert-0 dark:invert"
|
className="size-5 invert-0 dark:invert"
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
label: "Discord",
|
||||||
|
type: "icon",
|
||||||
url: "https://discord.gg/ZYsbjpDaM5",
|
url: "https://discord.gg/ZYsbjpDaM5",
|
||||||
external: true,
|
external: true,
|
||||||
secondary: true,
|
secondary: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user