Skip to content

Commit

Permalink
feat(GIST-41): added syntax highlighting (#12)
Browse files Browse the repository at this point in the history
* feat(GIST-41): added syntax highlighting

* fix(GIST-41): deleted higlight js
  • Loading branch information
Courtcircuits authored Oct 7, 2024
1 parent f7c1cda commit 165276b
Show file tree
Hide file tree
Showing 7 changed files with 954 additions and 84 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@reduxjs/toolkit": "^2.2.7",
"@tanstack/query-core": "5.21.4",
"@tanstack/react-query": "5.21.4",
"@uiw/react-textarea-code-editor": "^3.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"gsap": "^3.12.5",
Expand Down
615 changes: 612 additions & 3 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

138 changes: 102 additions & 36 deletions src/app/(gistLayout)/layout-ui.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
import { TeamListFeature } from '@/components/feature/team-list-feature'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/shadcn/avatar'
import { Button } from '@/components/shadcn/button'
import { Input } from '@/components/shadcn/input'
import { Textarea } from '@/components/shadcn/textarea'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/shadcn/tooltip'
import MenuButton from '@/components/ui/menu-button'
import { Modal } from '@/components/ui/modal'
import { ProfileDropdown } from '@/components/ui/profile-dropdown'
import Shortcut from '@/components/ui/shortcut'
import { FileCodeIcon, LucidePencil, Menu, PlusIcon } from 'lucide-react'
import { useState } from 'react'
import { TeamListFeature } from "@/components/feature/team-list-feature";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/shadcn/avatar";
import { Button } from "@/components/shadcn/button";
import { Codearea } from "@/components/shadcn/codearea";
import { Input } from "@/components/shadcn/input";
import { Textarea } from "@/components/shadcn/textarea";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/shadcn/tooltip";
import MenuButton from "@/components/ui/menu-button";
import { Modal } from "@/components/ui/modal";
import { ProfileDropdown } from "@/components/ui/profile-dropdown";
import Shortcut from "@/components/ui/shortcut";
import { getLanguage } from "@/lib/language";
import { FileCodeIcon, LucidePencil, Menu, PlusIcon } from "lucide-react";
import { useState } from "react";

interface GistLayoutProps {
username: string
avatar: string
children: React.ReactNode
onMyGistsClick: () => void
onCreateTeamClick: (name: string) => void
onCreateGistClick: (name: string, content: string) => void
username: string;
avatar: string;
children: React.ReactNode;
onMyGistsClick: () => void;
onCreateTeamClick: (name: string) => void;
onCreateGistClick: (name: string, content: string) => void;
}

export default function GistLayout({ avatar, children, username, onMyGistsClick, onCreateTeamClick, onCreateGistClick }: GistLayoutProps) {
const [gistName, setGistName] = useState('')
const [gistContent, setGistContent] = useState('')
const [teamName, setTeamName] = useState('')
export default function GistLayout({
avatar,
children,
username,
onMyGistsClick,
onCreateTeamClick,
onCreateGistClick,
}: GistLayoutProps) {
const [gistName, setGistName] = useState("");
const [gistContent, setGistContent] = useState("");
const [teamName, setTeamName] = useState("");

const language = getLanguage(gistName);

const handleCreateGistClick = () => {
onCreateGistClick(gistName, gistContent)
setGistName('')
setGistContent('')
}
onCreateGistClick(gistName, gistContent);
setGistName("");
setGistContent("");
};

return (
<div className="w-full h-screen flex flex-row p-2">
Expand All @@ -38,7 +58,9 @@ export default function GistLayout({ avatar, children, username, onMyGistsClick,
<div className="flex flex-row justify-start items-center gap-2">
<Avatar className="h-8 w-8 flex-shrink-0">
<AvatarImage src={avatar} />
<AvatarFallback className="bg-muted-foreground">{username.charAt(0).toUpperCase()}</AvatarFallback>
<AvatarFallback className="bg-muted-foreground">
{username.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
<ProfileDropdown username={username} />
</div>
Expand All @@ -49,18 +71,38 @@ export default function GistLayout({ avatar, children, username, onMyGistsClick,
<Modal
title="New Gist"
trigger={
<Button className="w-8 h-8 flex-shrink-0" size={'icon'} variant={'icon'}>
<Button
className="w-8 h-8 flex-shrink-0"
size={"icon"}
variant={"icon"}
>
<LucidePencil className="w-4 h-4" />
</Button>
}
content={
<div className="flex flex-col gap-3">
<Input className="border-0 bg-background p-0 h-min font-bold" placeholder="Gist name" value={gistName} onChange={(e) => setGistName(e.target.value)} />
<Textarea className="border-0 bg-background p-0 font-normal" placeholder="Write content..." value={gistContent} onChange={(e) => setGistContent(e.target.value)} />
<Input
className="border-0 bg-background p-0 h-min font-bold"
placeholder="Gist name"
value={gistName}
onChange={(e) => setGistName(e.target.value)}
/>
<Codearea
className="border-0 bg-background p-0 font-normal"
placeholder="Write content..."
value={gistContent}
language={language}
onChange={(e) => setGistContent(e.target.value)}
/>
</div>
}
footer={
<MenuButton variant="default" size="sm" onClick={handleCreateGistClick} className="">
<MenuButton
variant="default"
size="sm"
onClick={handleCreateGistClick}
className=""
>
Create
</MenuButton>
}
Expand All @@ -74,23 +116,47 @@ export default function GistLayout({ avatar, children, username, onMyGistsClick,
</TooltipProvider>
</div>
<div className="flex flex-col gap-2">
<MenuButton icon={<FileCodeIcon />} variant="menu" size="menu" letter="M" onClick={onMyGistsClick} href="/mygist" className="w-full">
<MenuButton
icon={<FileCodeIcon />}
variant="menu"
size="menu"
letter="M"
onClick={onMyGistsClick}
href="/mygist"
className="w-full"
>
My Gists
</MenuButton>
<Modal
trigger={
<MenuButton icon={<PlusIcon />} variant="menu" size="menu" letter="T" className="w-full">
<MenuButton
icon={<PlusIcon />}
variant="menu"
size="menu"
letter="T"
className="w-full"
>
Create team
</MenuButton>
}
title="Create Team"
content={
<div className="flex flex-col gap-3">
<Input className="border-0 bg-background p-0 h-min font-bold" placeholder="Team name" value={teamName} onChange={(e) => setTeamName(e.target.value)} />
<Input
className="border-0 bg-background p-0 h-min font-bold"
placeholder="Team name"
value={teamName}
onChange={(e) => setTeamName(e.target.value)}
/>
</div>
}
footer={
<MenuButton variant="default" size="sm" onClick={() => onCreateTeamClick(teamName)} className="">
<MenuButton
variant="default"
size="sm"
onClick={() => onCreateTeamClick(teamName)}
className=""
>
Create
</MenuButton>
}
Expand All @@ -100,5 +166,5 @@ export default function GistLayout({ avatar, children, username, onMyGistsClick,
</div>
{children}
</div>
)
);
}
32 changes: 32 additions & 0 deletions src/components/shadcn/codearea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { useEffect } from "react";
import CodeEditor from "@uiw/react-textarea-code-editor";
import { cn } from "@/lib/utils";

export interface CodeareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
className?: string;
language?: string;
}

const Codearea = ({ className, language, ...props }: CodeareaProps) => {
return (
<CodeEditor
value={props.value}
language={language}
onChange={props.onChange}
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
style={{
backgroundColor: "#0C0D0E",
fontFamily:
"ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace",
}}
/>
);
};

Codearea.displayName = "Codearea";

export { Codearea };
37 changes: 20 additions & 17 deletions src/components/shadcn/textarea.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import * as React from 'react'
import * as React from "react";

import { cn } from '@/lib/utils'
import { cn } from "@/lib/utils";

export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}

const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ className, ...props }, ref) => {
return (
<textarea
className={cn(
'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
ref={ref}
{...props}
/>
)
})
Textarea.displayName = 'Textarea'
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Textarea.displayName = "Textarea";

export { Textarea }
export { Textarea };
Loading

0 comments on commit 165276b

Please sign in to comment.