Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
bac70bb
mark old files
serafimcloud Apr 2, 2025
197bdf6
init
serafimcloud Apr 2, 2025
bf0453f
landing
serafimcloud Apr 2, 2025
84bd495
better landing
serafimcloud Apr 2, 2025
7135de9
refactor
serafimcloud Apr 2, 2025
65dfd04
sidebar
serafimcloud Apr 2, 2025
c28d73f
studio/components
serafimcloud Apr 2, 2025
95b1b11
fix
serafimcloud Apr 2, 2025
abd0194
fixes
serafimcloud Apr 2, 2025
8778784
init pre processing
serafimcloud Apr 2, 2025
269b64d
final pre-processing
serafimcloud Apr 2, 2025
26b1550
envs
serafimcloud Apr 3, 2025
fffa662
sandpack code edit
serafimcloud Apr 3, 2025
d2516a8
files
serafimcloud Apr 3, 2025
728ad80
fix view
serafimcloud Apr 3, 2025
9723244
fix editor
serafimcloud Apr 3, 2025
0d5a186
refactor
serafimcloud Apr 3, 2025
05c67c3
fix
serafimcloud Apr 3, 2025
dbf4475
all files
serafimcloud Apr 3, 2025
5201f16
resolve shadcn deps
serafimcloud Apr 3, 2025
b76509f
merge styles
serafimcloud Apr 3, 2025
1c402c1
custom file tree
serafimcloud Apr 3, 2025
58a6007
unknown files init
serafimcloud Apr 4, 2025
cf53610
refactor
serafimcloud Apr 4, 2025
33cc902
debuh
serafimcloud Apr 4, 2025
b4d0dc7
refactor
serafimcloud Apr 4, 2025
4548726
refactor
serafimcloud Apr 4, 2025
1235d70
reacotr
serafimcloud Apr 4, 2025
26560bb
refactor
serafimcloud Apr 4, 2025
1075235
atoms
serafimcloud Apr 4, 2025
c4ec33b
refactor
serafimcloud Apr 4, 2025
0f16241
show shadcn component loading
serafimcloud Apr 4, 2025
119e585
join styles
serafimcloud Apr 5, 2025
81ba205
refactor + disable styles merge
serafimcloud Apr 6, 2025
7baf88d
init request styles
serafimcloud Apr 6, 2025
3152789
refactor and atom based state of action reqires
serafimcloud Apr 6, 2025
37af589
request unknown code
serafimcloud Apr 6, 2025
816b27b
try
serafimcloud Apr 6, 2025
c55d7c4
auto resolve file on edit
serafimcloud Apr 6, 2025
ea0b009
req panel craft
serafimcloud Apr 7, 2025
029d8ff
Update use-editor-dialog.ts
serafimcloud Apr 7, 2025
869e555
preview wo styles
serafimcloud Apr 7, 2025
933ab32
compile css
serafimcloud Apr 7, 2025
bde9edc
move to separate file
serafimcloud Apr 7, 2025
a7d3820
refactor - req panel
serafimcloud Apr 7, 2025
40ec461
refactor: remove murge styles
serafimcloud Apr 7, 2025
2e33f9d
refactor - remane
serafimcloud Apr 7, 2025
37a2366
refactor: addToTree
serafimcloud Apr 7, 2025
d2dd677
refactor: FileTreeNode
serafimcloud Apr 7, 2025
1a89369
refactor: missing_import → unresolved_dependencies
serafimcloud Apr 7, 2025
e9201f1
refactor: isUnknownComponent → isUnresolvedDependency
serafimcloud Apr 7, 2025
2c5dba4
refactor: remove unused file
serafimcloud Apr 7, 2025
69ec4b3
remove unused file
serafimcloud Apr 7, 2025
5562de8
refactor - move dump file separate
serafimcloud Apr 7, 2025
41214a4
refactor: separate hooks
serafimcloud Apr 7, 2025
16d7836
refactor: hooks
serafimcloud Apr 7, 2025
5428605
refactor: use-dependencies
serafimcloud Apr 7, 2025
6e38377
refactor: use compiler
serafimcloud Apr 7, 2025
2a10e90
remove unused staff
serafimcloud Apr 7, 2025
25f52cd
NonShadcnComponent → UnresolvedDependency
serafimcloud Apr 7, 2025
29ac11f
remove unused logic
serafimcloud Apr 7, 2025
570f56d
refactor context
serafimcloud Apr 7, 2025
f081a95
init: sandpack new editor
bunasQ Apr 15, 2025
7e340bd
sandpack doesn't work =(
bunasQ Apr 17, 2025
693d5ff
we vibing
bunasQ Apr 17, 2025
de09e0a
init: code editor & integration with file system
bunasQ Apr 21, 2025
dde838f
refactor: update file handling and selection logic
bunasQ Apr 21, 2025
7f2a009
some state
bunasQ Apr 22, 2025
5220a34
add: codesandbox sdk
bunasQ Apr 23, 2025
35ab643
split the logic
bunasQ Apr 23, 2025
e13f731
add: csb sdk
bunasQ Apr 23, 2025
56247c3
update fs
bunasQ Apr 23, 2025
c933949
clean up
bunasQ Apr 23, 2025
9666f58
add: create folders & add for each folders
bunasQ Apr 24, 2025
0d5e76b
add more
bunasQ Apr 24, 2025
de186a8
add: reconnect on close
bunasQ Apr 24, 2025
163f99d
feat: integrate monaco-jsx-highlighter for enhanced JSX support in Ed…
bunasQ Apr 24, 2025
1acbf08
advanced view & open directories
bunasQ Apr 24, 2025
8c53f11
refactor: simplify PublishPage by removing preview toggle and integra…
bunasQ Apr 24, 2025
035ebbf
add: nice resizable
bunasQ Apr 24, 2025
405d44c
refactor: enhance sandbox initialization logic to manage loading stat…
bunasQ Apr 24, 2025
5188c2c
chore: enable noUnusedLocals and noUnusedParameters in TypeScript com…
bunasQ Apr 24, 2025
021a79d
refactor: streamline sandbox initialization by removing redundant par…
bunasQ Apr 24, 2025
9a4f029
advanced view styles
bunasQ Apr 24, 2025
4057133
fix: set default selected file entry in PublishPage and improve expan…
bunasQ Apr 24, 2025
24fd421
refactor
bunasQ Apr 24, 2025
3421405
add: dependecy resolve
bunasQ Apr 24, 2025
067ca65
type $hi
bunasQ Apr 25, 2025
fac96af
🍻🍻🍻🍻 PREVIEW PORTS 🍻🍻🍻🍻
bunasQ Apr 26, 2025
8aada15
🔥 add sandbox sdk routes inside next app🔥
bunasQ Apr 26, 2025
26ed056
add mock publishing
bunasQ Apr 26, 2025
a8ff291
add preview of sandboxes
bunasQ Apr 26, 2025
1bbf3d7
give hash back
bunasQ Apr 26, 2025
772a9b7
HIDE ACTIONS FOR NOW
bunasQ Apr 26, 2025
619f8bb
updates
bunasQ Apr 28, 2025
35a1814
rm unused
bunasQ Apr 28, 2025
2599553
Implement registry generation feature in PublishPage and update Publi…
bunasQ Apr 28, 2025
4d6ae60
rework sandpack timeouts
bunasQ Apr 29, 2025
bddddee
Merge branch 'main' into new-publishing-refac
bunasQ Apr 29, 2025
3f5e16a
resolve dependencies erors for codemirror
bunasQ Apr 29, 2025
15f089f
code migration
bunasQ Apr 30, 2025
2d72e9a
delete unused
bunasQ Apr 30, 2025
5968aec
commented out pricing
bunasQ Apr 30, 2025
dba982a
refactor: clean up commented code in component form
bunasQ Apr 30, 2025
20d3348
rm license selection
bunasQ Apr 30, 2025
b3b3f4d
rm website field
bunasQ Apr 30, 2025
01c0737
migrated
bunasQ Apr 30, 2025
c220cf8
update: generate registry
bunasQ Apr 30, 2025
90e2e85
add some publishing logic
bunasQ Apr 30, 2025
9b3bb7f
renname & update imports
bunasQ Apr 30, 2025
ba835a0
refactor: simplify useSubmitComponent and update submit logic
bunasQ Apr 30, 2025
04d15fa
upload with preview
bunasQ May 1, 2025
079f8a0
add some stuff
bunasQ May 1, 2025
e550702
feat: add onSuccess callback to publish logic and improve file system…
bunasQ May 1, 2025
522eb88
table and sidebar
serafimcloud May 1, 2025
13890b0
create button
serafimcloud May 1, 2025
69cccc7
error and loading
serafimcloud May 1, 2025
612546b
Rename files to follow Next.js standards
serafimcloud May 1, 2025
cd6aa34
craft header
serafimcloud May 1, 2025
06a325d
edit
serafimcloud May 1, 2025
4328b16
update
bunasQ May 1, 2025
1973a99
add client side validation
bunasQ May 1, 2025
8626e50
fix: studio auth hotfix
serafimcloud May 2, 2025
4bbe55a
feat: show all files button
serafimcloud May 2, 2025
4ab32c7
craft: file tree
serafimcloud May 2, 2025
3ba8792
craft: header
serafimcloud May 2, 2025
db121ed
refactor: remove console logs, simplify component info checks, and cl…
bunasQ May 2, 2025
f2fd247
unique slug auto prefill
bunasQ May 2, 2025
ab617b5
Merge branch 'new-publishing-refac' of github.com:serafimcloud/21st i…
bunasQ May 2, 2025
0ab2aa8
feat: add component name update functionality and improve registry ge…
bunasQ May 2, 2025
cc3dc97
fixes
serafimcloud May 2, 2025
1c74a8d
fix demo name
serafimcloud May 2, 2025
3dc7db1
fix
serafimcloud May 2, 2025
bf681f6
feat: implement initial UI file selection logic in PublishPageContent
bunasQ May 2, 2025
d1e6ff6
Merge branch 'new-publishing-refac' of https://github.com/serafimclou…
serafimcloud May 2, 2025
72b9f40
feat: sandbox header
serafimcloud May 2, 2025
470614d
server side header
serafimcloud May 2, 2025
863f65a
loadings
serafimcloud May 2, 2025
a95823b
new template
bunasQ May 5, 2025
61f6b60
restore previous functionality
bunasQ May 5, 2025
7537a04
refactor: remove default demo name handling from DemoDetailsForm
bunasQ May 5, 2025
85330b5
single table
bunasQ May 5, 2025
6cefef5
feat: enhance DemosTable interactivity and dynamic column handling
bunasQ May 5, 2025
e85a9ed
update pre-fetch logic
bunasQ May 5, 2025
ea4b303
feat: add user authentication and redirect logic in publish page
bunasQ May 5, 2025
4396a76
fix errors
bunasQ May 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/web/app/[username]/[component_slug]/page.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import { BookmarkButton } from "@/components/ui/bookmark-button"
import { ThemeToggle } from "../../../components/ui/theme-toggle"
import { ComponentPagePreview } from "../../../components/features/component-page/component-preview"
import { EditComponentDialog } from "../../../components/ui/edit-component-dialog"
import { usePublishAs } from "../../../components/features/publish/hooks/use-publish-as"
import { usePublishAs } from "../../../components/features/publish-old/hooks/use-publish-as"
import { Icons } from "@/components/icons"
import { CopyPromptDialog } from "@/components/ui/copy-prompt-dialog"

Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/admin/submissions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { FC } from "react"
import { motion } from "motion/react"
import { useIsAdmin } from "@/components/features/publish/hooks/use-is-admin"
import { useIsAdmin } from "@/components/features/publish-old/hooks/use-is-admin"
import AdminHeader from "@/components/features/admin/AdminHeader"
import SubmissionCard from "@/components/features/admin/SubmissionCard"
import ManageSubmissionModal from "@/components/features/admin/ManageSubmissionModal"
Expand Down
57 changes: 57 additions & 0 deletions apps/web/app/api/sandbox/connect/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { auth } from "@clerk/nextjs/server"
import { NextResponse } from "next/server"
import { supabaseWithAdminAccess } from "@/lib/supabase"
import {
codesandboxSdk,
DEFAULT_HIBERNATION_TIMEOUT,
} from "@/lib/codesandbox-sdk"
import ShortUUID from "short-uuid"

export async function POST(request: Request) {
try {
const { userId } = await auth()
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}

const { shortSandboxId } = await request.json()

const sandboxId = ShortUUID().toUUID(shortSandboxId)

if (!sandboxId) {
return NextResponse.json(
{ error: "Sandbox ID is required" },
{ status: 400 },
)
}

const { data: sandbox, error } = await supabaseWithAdminAccess
.from("sandboxes")
.select("codesandbox_id, name, id, component_id")
.eq("id", sandboxId)
.eq("user_id", userId)
.single()

if (error || !sandbox) {
return NextResponse.json(
{ error: "Sandbox not found or access denied" },
{ status: 404 },
)
}

const startData = await codesandboxSdk.sandbox.start(
sandbox.codesandbox_id,
{
hibernationTimeoutSeconds: DEFAULT_HIBERNATION_TIMEOUT,
},
)

return NextResponse.json({ success: true, startData, sandbox })
} catch (error) {
console.error("Error connecting to sandbox:", error)
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
)
}
}
66 changes: 66 additions & 0 deletions apps/web/app/api/sandbox/edit/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { auth } from "@clerk/nextjs/server"
import { NextResponse } from "next/server"
import { supabaseWithAdminAccess } from "@/lib/supabase"
import ShortUUID from "short-uuid"

export async function PUT(request: Request) {
try {
const { userId } = await auth()
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}

const { shortSandboxId, ...updateData } = await request.json()

if (!shortSandboxId) {
return NextResponse.json(
{ error: "Sandbox ID is required" },
{ status: 400 },
)
}

if (Object.keys(updateData).length === 0) {
return NextResponse.json(
{ error: "No update data provided" },
{ status: 400 },
)
}

const sandboxId = ShortUUID().toUUID(shortSandboxId)

const { data: sandbox, error } = await supabaseWithAdminAccess
.from("sandboxes")
.select("id")
.eq("id", sandboxId)
.eq("user_id", userId)
.single()

if (error || !sandbox) {
return NextResponse.json(
{ error: "Sandbox not found or access denied" },
{ status: 404 },
)
}

const { error: updateError } = await supabaseWithAdminAccess
.from("sandboxes")
.update(updateData)
.eq("id", sandboxId)
.eq("user_id", userId)

if (updateError) {
return NextResponse.json(
{ error: "Failed to update sandbox" },
{ status: 500 },
)
}

return NextResponse.json({ success: true })
} catch (error) {
console.error("Error updating sandbox:", error)
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
)
}
}
61 changes: 61 additions & 0 deletions apps/web/app/api/sandbox/new/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { auth } from "@clerk/nextjs/server"
import { NextResponse } from "next/server"
import { supabaseWithAdminAccess } from "@/lib/supabase"
import ShortUUID from "short-uuid"
import {
DEFAULT_HIBERNATION_TIMEOUT,
DEFAULT_TEMPLATE,
TEMPLATES,
codesandboxSdk,
} from "@/lib/codesandbox-sdk"

export async function POST() {
try {
const { userId } = await auth()

console.log("userId", userId)

if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}

console.log("Creating CodeSandbox instance...")
const sandbox = await codesandboxSdk.sandbox.create({
template: TEMPLATES[DEFAULT_TEMPLATE],
hibernationTimeoutSeconds: DEFAULT_HIBERNATION_TIMEOUT,
privacy: "public", // Public visibility
})

const codesandboxId = sandbox.id
console.log(`CodeSandbox instance created: ${codesandboxId}`)

const now = new Date().toISOString()
const { data: dbSandbox, error: dbError } = await supabaseWithAdminAccess
.from("sandboxes")
.insert({
user_id: userId,
codesandbox_id: codesandboxId,
created_at: now,
updated_at: now,
})
.select()
.single()

if (dbError) {
console.error("Error storing sandbox:", dbError)
return new NextResponse("Failed to save sandbox data", { status: 500 })
}

console.log(`Sandbox created and stored with ID: ${dbSandbox.id}`)

const shortId = ShortUUID().fromUUID(dbSandbox.id)

return NextResponse.json({
success: true,
shortSandboxId: shortId,
})
} catch (error) {
console.error("Error creating sandbox:", error)
return new NextResponse("Internal Server Error", { status: 500 })
}
}
59 changes: 59 additions & 0 deletions apps/web/app/api/sandbox/publish/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { auth } from "@clerk/nextjs/server"
import { NextResponse } from "next/server"
import { supabaseWithAdminAccess } from "@/lib/supabase"
import ShortUUID from "short-uuid"

export async function POST(request: Request) {
try {
const { userId } = await auth()
if (!userId) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}

const { shortSandboxId } = await request.json()

const sandboxId = ShortUUID().toUUID(shortSandboxId)

if (!sandboxId) {
return NextResponse.json(
{ error: "Sandbox ID is required" },
{ status: 400 },
)
}

const { data: sandbox, error } = await supabaseWithAdminAccess
.from("sandboxes")
.select("codesandbox_id")
.eq("id", sandboxId)
.eq("user_id", userId)
.single()

if (error || !sandbox) {
return NextResponse.json(
{ error: "Sandbox not found or access denied" },
{ status: 404 },
)
}

const { error: updateError } = await supabaseWithAdminAccess
.from("sandboxes")
.update({ status: "on_review" })
.eq("id", sandboxId)
.eq("user_id", userId)

if (updateError) {
return NextResponse.json(
{ error: "Failed to update sandbox status" },
{ status: 500 },
)
}

return NextResponse.json({ success: true })
} catch (error) {
console.error("Error connecting to sandbox:", error)
return NextResponse.json(
{ error: "Internal Server Error" },
{ status: 500 },
)
}
}
120 changes: 120 additions & 0 deletions apps/web/app/api/studio/merge-styles/globals/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { OpenAI } from "openai"
import { NextResponse } from "next/server"

const openai = new OpenAI()

export async function POST(request: Request) {
try {
const { defaultGlobalCss, dependencyGlobalCss } = await request.json()

console.log("🔄 [Global CSS Merge] Request received:", {
defaultCssLength: defaultGlobalCss?.length,
dependencyCssCount: dependencyGlobalCss?.length,
dependencyCssSizes: dependencyGlobalCss?.map((css: string) => css.length),
})

// Only proceed if we have custom styles to merge
if (!dependencyGlobalCss?.length) {
console.log(
"⏩ [Global CSS Merge] No custom styles to merge, returning default",
)
return NextResponse.json({ globalCss: defaultGlobalCss })
}

const prompt = `You are a CSS expert. Please merge the following global CSS styles into a single optimized stylesheet.

Base Global CSS:
\`\`\`css
${defaultGlobalCss}
\`\`\`

${dependencyGlobalCss
.map(
(css: string, index: number) => `
Dependency ${index + 1} Global CSS:
\`\`\`css
${css}
\`\`\`
`,
)
.join("\n")}

Please provide a merged global.css that:
1. Combines all styles efficiently
2. Resolves any conflicts by using the most specific/latest definitions
3. Maintains all necessary functionality
4. Eliminates duplicates
5. Preserves cascade and specificity appropriately
6. Groups related styles together
7. Never shortens, simplifies, or omits any keyframe animations or complex selectors
8. Includes ALL original code without truncation or summarization
9. Preserves all vendor prefixes and browser-specific styles

Format the response as a JSON object with a 'globalCss' key containing the complete merged styles.`

console.log("📤 [Global CSS Merge] Sending request to OpenAI:", {
promptLength: prompt.length,
stylesToMerge: dependencyGlobalCss.length + 1, // +1 for default styles
})

const completion = await openai.chat.completions.create({
messages: [
{
role: "system",
content:
"You are a CSS expert who helps merge and optimize stylesheets. Always include all content completely without summarizing or truncating. Preserve all keyframes, animations, and complex styles fully.",
},
{
role: "user",
content: prompt,
},
],
model: "gpt-4o-mini",
response_format: { type: "json_object" },
})

if (!completion.choices[0]?.message.content) {
throw new Error("No content in OpenAI response")
}

const result = JSON.parse(completion.choices[0].message.content)

// Handle both string and object formats for globalCss
let logInfo = {
resultLength: result.globalCss
? typeof result.globalCss === "string"
? result.globalCss.length
: JSON.stringify(result.globalCss).length
: 0,
hasCss: !!result.globalCss,
firstFewLines: "",
}

// Add firstFewLines only if globalCss is a string
if (typeof result.globalCss === "string") {
logInfo.firstFewLines = result.globalCss
.split("\n")
.slice(0, 3)
.join("\n")
} else if (result.globalCss) {
// For object format, convert to string representation for logging
logInfo.firstFewLines =
JSON.stringify(result.globalCss).slice(0, 100) + "..."
}

console.log("📥 [Global CSS Merge] Received response from OpenAI:", logInfo)

// Ensure globalCss is always a string in the response
if (result.globalCss && typeof result.globalCss !== "string") {
result.globalCss = JSON.stringify(result.globalCss, null, 2)
}

return NextResponse.json(result)
} catch (error) {
console.error("❌ [Global CSS Merge] Error:", error)
return NextResponse.json(
{ error: "Failed to merge global CSS" },
{ status: 500 },
)
}
}
Loading