diff --git a/package.json b/package.json index c8b3664..e4ff9e6 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,14 @@ "@radix-ui/react-collapsible": "^1.1.1", "@radix-ui/react-dialog": "^1.1.2", "@radix-ui/react-dropdown-menu": "^2.1.2", + "@radix-ui/react-scroll-area": "^1.2.1", "@radix-ui/react-separator": "^1.1.0", "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-tabs": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.4", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", + "devicons-react": "^1.3.0", "lucide-react": "^0.460.0", "next": "15.0.3", "next-themes": "^0.4.3", diff --git a/prisma/seed.ts b/prisma/seed.ts index f879f66..477f461 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -5,7 +5,7 @@ async function main() { data: [ { title: "Hello World in JavaScript", - language: "JavaScript", + language: "javascript", code: `console.log("Hello, World!"); function greet(name) { @@ -16,7 +16,7 @@ console.log(greet("Prisma"));`, }, { title: "Hello World in Python", - language: "Python", + language: "python", code: `print("Hello, World!") def greet(name): @@ -26,7 +26,7 @@ print(greet("Prisma"))`, }, { title: "Hello World in Java", - language: "Java", + language: "java", code: `public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); @@ -39,6 +39,102 @@ print(greet("Prisma"))`, public static void main(String[] args) { System.out.println(greet("Prisma")); } +}`, + }, + { + title: "Hello World in C", + language: "c", + code: `#include + +void greet(char* name) { + printf("Hello, %s!\n", name); +} + +int main() { + printf("Hello, World!\n"); + greet("Prisma"); + return 0; +}`, + }, + { + title: "Hello World in C++", + language: "cpp", + code: `#include + +void greet(std::string name) { + std::cout << "Hello, " << name << "!" << std::endl; +} + +int main() { + std::cout << "Hello, World!" << std::endl; + greet("Prisma"); + return 0; +}`, + }, + { + title: "Hello World in C#", + language: "csharp", + code: `using System; + +class HelloWorld { + static void Main() { + Console.WriteLine("Hello, World!"); + greet("Prisma"); + } + + static void greet(string name) { + Console.WriteLine("Hello, " + name + "!"); + } +}`, + }, + { + title: "Hello World in Go", + language: "go", + code: `package main + +import "fmt" + +func greet(name string) { + fmt.Printf("Hello, %s!\n", name) +} + +func main() { + fmt.Println("Hello, World!") + greet("Prisma") +}`, + }, + { + title: "Hello World in Ruby", + language: "ruby", + code: `puts "Hello, World!" + +def greet(name) + puts "Hello, #{name}!" +end + +greet("Prisma")`, + }, + { + title: "Hello World in Swift", + language: "swift", + code: `print("Hello, World!") + +func greet(_ name: String) { + print("Hello, \(name)!") +} + +greet("Prisma")`, + }, + { + title: "Hello World in Kotlin", + language: "kotlin", + code: `fun main() { + println("Hello, World!") + greet("Prisma") +} + +fun greet(name: String) { + println("Hello, $name!") }`, }, ], diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx index ba214c2..5f47a6c 100644 --- a/src/app/dashboard/layout.tsx +++ b/src/app/dashboard/layout.tsx @@ -19,14 +19,14 @@ export default async function RootLayout({ -
+
- {children} +
{children}
); diff --git a/src/app/dashboard/snippets/components/snippet-card.tsx b/src/app/dashboard/snippets/components/snippet-card.tsx new file mode 100644 index 0000000..6352503 --- /dev/null +++ b/src/app/dashboard/snippets/components/snippet-card.tsx @@ -0,0 +1,106 @@ +import { + CsharpOriginal, + JavaOriginal, + PythonOriginal, + JavascriptOriginal, + KotlinOriginal, + COriginal, + GoOriginal, + RubyOriginal, + SwiftOriginal, + CplusplusOriginal, +} from "devicons-react"; +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { cn } from "@/lib/utils"; +import { Snippet } from "@prisma/client"; +import { Badge } from "@/components/ui/badge"; +import { ScrollArea } from "@/components/ui/scroll-area"; + +const colors = { + green: "bg-green-50", + gray: "bg-gray-50", + red: "bg-red-50", + yellow: "bg-yellow-50", + purple: "bg-purple-50", + blue: "bg-blue-50", + orange: "bg-orange-50", +} as const; + +const languageIcons = { + c: { icon: COriginal, color: colors.green }, + cpp: { icon: CplusplusOriginal, color: colors.gray }, + java: { icon: JavaOriginal, color: colors.red }, + python: { icon: PythonOriginal, color: colors.yellow }, + javascript: { icon: JavascriptOriginal, color: colors.yellow }, + csharp: { icon: CsharpOriginal, color: colors.purple }, + go: { icon: GoOriginal, color: colors.blue }, + ruby: { icon: RubyOriginal, color: colors.red }, + swift: { icon: SwiftOriginal, color: colors.orange }, + kotlin: { icon: KotlinOriginal, color: colors.blue }, +} as const; + +type Language = keyof typeof languageIcons; + +interface SnippetCardProps extends React.ComponentProps { + snippet: Snippet; +} + +export function SnippetCard({ + snippet, + className, + ...props +}: SnippetCardProps) { + const languageInfo = languageIcons[snippet.language as Language]; + const createdAt = new Date(snippet.createdAt); + const updatedAt = new Date(snippet.updatedAt); + const isUpdated = createdAt.getTime() !== updatedAt.getTime(); + + const renderLanguageBadge = () => ( + +
+ {languageInfo?.icon && } + {snippet.language} +
+
+ ); + + const renderTimestamp = () => ( + + {isUpdated ? "updatedAt: " : "createdAt: "} + {isUpdated ? updatedAt.toLocaleString() : createdAt.toLocaleString()} + + ); + + return ( + + + + {snippet.title} + {renderLanguageBadge()} + + + + +
+            {snippet.code}
+          
+
+
+ + {renderTimestamp()} + +
+ ); +} diff --git a/src/app/dashboard/snippets/page.tsx b/src/app/dashboard/snippets/page.tsx new file mode 100644 index 0000000..1271437 --- /dev/null +++ b/src/app/dashboard/snippets/page.tsx @@ -0,0 +1,35 @@ +import prisma from "@/lib/prisma"; +import { PlusCircle } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Separator } from "@/components/ui/separator"; +import { SnippetCard } from "./components/snippet-card"; + +export default async function SnippetsPage() { + const snippets = await prisma.snippet.findMany(); + const renderedSnippets = snippets.map((snippet) => { + return ; + }); + + return ( +
+
+
+

Snippets

+

+ Top picks for you. Updated daily. +

+
+
+ +
+
+ +
+ {renderedSnippets} +
+
+ ); +} diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 0000000..e87d62b --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..cabfbfc --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000..0b4a48d --- /dev/null +++ b/src/components/ui/scroll-area.tsx @@ -0,0 +1,48 @@ +"use client" + +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)) +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)) +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + +export { ScrollArea, ScrollBar } diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 0000000..0f4caeb --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,55 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent }