Skip to content

Commit 122091b

Browse files
committed
prototype done
1 parent 64e445a commit 122091b

18 files changed

+1668
-85
lines changed

app/globals.css

+73
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,23 @@ body {
1010
width: 100%;;
1111

1212
}
13+
14+
.code-title {
15+
border-top-left-radius: 0.5rem;
16+
border-top-right-radius: 0.5rem;
17+
border: 2px solid rgba(249, 249, 249, 0.08);
18+
19+
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
20+
}
21+
22+
.ace-editor-container {
23+
width: 100% !important;
24+
}
25+
1326
.ace_scrollbar {
1427
display: none !important;
1528
}
29+
1630
.ace_editor {
1731
background-color: rgba(0, 0, 0, 0.5);
1832
border-bottom-left-radius: 0.5rem;
@@ -26,6 +40,7 @@ width: 100%;;
2640
font-size: 17px !important;
2741
line-height: 1.5rem !important;
2842
}
43+
2944
.ace_content {
3045
width: 100% !important;
3146
top: 12px !important;
@@ -35,3 +50,61 @@ width: 100%;;
3550
.ace_scroller {
3651
width: 100% !important;
3752
}
53+
54+
.dropdown-title {
55+
padding: 0.25rem 0.3rem 0.3rem 0.5rem;
56+
height: 37px;
57+
border-radius: 3px;
58+
border: 1px solid rgba(249, 249, 249, 0.08);
59+
60+
font-size: 0.9rem;
61+
display: flex;
62+
align-items: center;
63+
justify-content: space-between;
64+
cursor: pointer;
65+
}
66+
67+
.dropdown-menu {
68+
padding: 0.25rem 0 0.4rem 0.5rem;
69+
70+
71+
background-color: #191919;
72+
border: 1px solid #3c3c3c;
73+
border-radius: 3px;
74+
}
75+
76+
.handle {
77+
transition: all 0.4s ease-in-out;
78+
pointer-events: none;
79+
}
80+
81+
.handle-top,
82+
.handle-bottom {
83+
transform: translateX(-50%) scale(1);
84+
transition: all 0.4s ease-in-out;
85+
z-index: 100;
86+
pointer-events: none;
87+
}
88+
89+
.resize-container:hover .handle-left {
90+
transform: translateY(-50%) scale(1.3);
91+
background: rgb(248 250 252);
92+
transition: all 0.4s ease-in-out;
93+
}
94+
.resize-container:hover .handle-right {
95+
transform: translateY(-50%) scale(1.3);
96+
background: rgb(248 250 252);
97+
transition: all 0.4s ease-in-out;
98+
}
99+
100+
@layer utilities {
101+
/* Hide scrollbar for Chrome, Safari and Opera */
102+
.no-scrollbar::-webkit-scrollbar {
103+
display: none;
104+
}
105+
/* Hide scrollbar for IE, Edge and Firefox */
106+
.no-scrollbar {
107+
-ms-overflow-style: none; /* IE and Edge */
108+
scrollbar-width: none; /* Firefox */
109+
}
110+
}

app/page.tsx

+88-9
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,99 @@
11
"use client"
22
import Image from "next/image";
33
import Canvas from '../components/Canvas';
4-
import { Languages } from "next/dist/lib/metadata/types/alternative-urls-types";
5-
import { useState } from "react";
4+
import { useState, useRef } from "react";
65
import SelectLanguage from "@/components/SelectLanguage";
7-
import { languages } from "@/utils/utility";
6+
import SelectTheme from "@/components/SelectTheme";
7+
import SelectBackground from "@/components/SelectBackground";
8+
import { languages, themes, backgrounds } from "@/utils/utility";
9+
import SelectPadding from "@/components/SelectPadding";
10+
import html2canvas from "html2canvas";
11+
import { Download } from "lucide-react";
12+
13+
814
export default function Home() {
9-
const [language , setlanguage] = useState(languages[0].name);
15+
const [language , setLanguage] = useState(languages[0].name);
16+
const [theme, setTheme] = useState(themes[0]);
17+
const [background, setBackground] = useState(backgrounds[0]);
18+
const [activeIcon, setActiveIcon] = useState(languages[0].icon);
19+
const [paddings, setPaddings] = useState(["1rem", "2rem", "3rem", "4rem"]);
20+
const [currentPadding, setCurrentPadding] = useState(paddings[2]);
21+
const editorRef = useRef(null);
22+
const exportPng = async () => {
23+
const editorElem = editorRef.current;
24+
25+
if (editorElem) {
26+
27+
const handleElems = document.querySelectorAll(".handle") as any;
28+
const cursorElem = document.querySelector(".ace_cursor") as any;
29+
const codetitle = document.querySelector(".code-title") as any;
30+
const codeEditor = document.querySelector(".ace_editor") as any;
31+
32+
handleElems.forEach((elem: any) => {
33+
elem.style.display = "none";
34+
});
35+
cursorElem.style.display = "none";
36+
codetitle.style.boxShadow = "none";
37+
codeEditor.style.boxShadow = "none";
38+
39+
const canvas = await html2canvas(editorElem);
40+
const image = canvas
41+
.toDataURL("image/png")
42+
.replace("image/png", "image/octet-stream");
43+
44+
const link = document.createElement("a");
45+
link.download = "code.png";
46+
link.href = image;
47+
link.click();
48+
49+
50+
handleElems.forEach((elem: any) => {
51+
elem.style.display = "block";
52+
});
53+
cursorElem.style.display = "block";
54+
codetitle.style.boxShadow = "0 3px 10px rgba(0, 0, 0, 0.2)";
55+
codeEditor.style.boxShadow = "2px 3px 10px rgba(0, 0, 0, 0.2)";
56+
}
57+
};
1058

1159
return (
12-
<main className="flex w-full ">
13-
<div className="w-[22%] bg-[#191919] text-white">
14-
<SelectLanguage />
60+
<main className="flex w-full h-[100vh] pl-4 pt-2 items-center ">
61+
<div className="w-[22%] overflow-y-auto no-scrollbar p-5 text-white fixed h-[520px] z-10 bg-[#191919] rounded border border-[#3C3C3C] shadow-md">
62+
<h2 className="font-black pb-2 text-4xl">CodeCanvas</h2>
63+
<SelectLanguage language={language}
64+
setLanguage={setLanguage}
65+
seActiveIcon={setActiveIcon}/>
66+
<SelectTheme theme={theme} setTheme={setTheme}/>
67+
<SelectBackground
68+
background={background}
69+
setBackground={setBackground}
70+
/>
71+
72+
<SelectPadding
73+
paddings={paddings}
74+
currentPadding={currentPadding}
75+
setCurrentPadding={setCurrentPadding}
76+
/>
77+
<div className="export-btn self-center ml-auto pt-4">
78+
<button
79+
className="flex items-center gap-3 py-2 px-3 bg-blue-400 rounded-md text-sm text-blue-400
80+
font-medium bg-opacity-10 hover:bg-opacity-80 hover:text-slate-50 ease-in-out transition-all
81+
duration-300"
82+
onClick={exportPng}
83+
>
84+
<Download />
85+
Export PNG
86+
</button>
87+
</div>
1588
</div>
16-
<div className="w-[78%] ">
17-
<Canvas language={language}/>
89+
<div className="w-[78%] ml-[22%] code-editor-ref w-full flex justify-center" ref={editorRef}
90+
>
91+
<Canvas language={language}
92+
theme={theme}
93+
background={background}
94+
icon={activeIcon}
95+
currentPadding={currentPadding} />
96+
1897
</div>
1998
</main>
2099

components/Canvas.tsx

+39-30
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,40 @@ import "ace-builds/src-noconflict/mode-css";
1111
import "ace-builds/src-noconflict/mode-python";
1212
import "ace-builds/src-noconflict/mode-java";
1313
import "ace-builds/src-noconflict/mode-typescript";
14-
interface CanvasProps {
15-
language: string;
16-
theme: string;
17-
icon: string;
18-
background?: string;
19-
currentPadding?: string;
2014

15+
16+
import { getExtension, initialCode } from "@/utils/utility";
17+
interface CanvasProps {
18+
language: string;
19+
theme: string;
20+
icon: string;
21+
background?: string;
22+
currentPadding?: string;
2123
}
22-
function Canvas({
23-
24-
theme,
25-
language,
26-
icon,
27-
background,
28-
currentPadding,
29-
}: CanvasProps) {
3024

31-
const [width, setWidth] = React.useState(1000);
32-
const [height, setHeight] = React.useState<number | null>(500);
33-
const [title, setTitle] = React.useState("App");
34-
25+
function Canvas({
26+
language,
27+
theme,
28+
icon,
29+
background,
30+
currentPadding,
31+
}: CanvasProps) {
32+
const [width, setWidth] = React.useState(1000);
33+
const [height, setHeight] = React.useState<number | null>(500);
34+
const [title, setTitle] = React.useState("App");
35+
const [code, setCode] = React.useState(initialCode);
3536

3637
const [extension, setExtension] = React.useState(".js");
3738

39+
useEffect(() => {
40+
setExtension(getExtension(language));
41+
}, [language]);
3842

39-
43+
const handleCodeChange = (newCode: string) => {
44+
setCode(newCode);
45+
};
4046

4147
const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
42-
// Extract the title without the extension
4348
const newTitle = e.target.value.split(".")[0];
4449
setTitle(newTitle);
4550
};
@@ -61,23 +66,28 @@ function Canvas({
6166
}, []);
6267

6368
return (
64-
<Resizable minHeight={466} minWidth={510} maxHeight={1000} defaultSize={{
69+
<Resizable
70+
minHeight={466}
71+
minWidth={510}
72+
maxWidth={900}
73+
defaultSize={{
6574
width: width,
6675
height: height || 500,
6776
}}
6877
onResize={handleResize}
6978
className="resize-container relative"
7079
style={{
7180
background: background,
72-
}}>
73-
<div
81+
}}
82+
>
83+
<div
7484
className="code-block"
7585
style={{
7686
padding: currentPadding,
7787
}}
7888
>
79-
80-
<div className="handle handle-top absolute left-1/2 translate-x-[-50%] top-[-4px] w-2 h-2
89+
<div
90+
className="handle handle-top absolute left-1/2 translate-x-[-50%] top-[-4px] w-2 h-2
8191
rounded-full bg-slate-300 hover:bg-slate-50"
8292
></div>
8393
<div
@@ -125,7 +135,7 @@ function Canvas({
125135
</div>
126136
</div>
127137
<AceEditor
128-
value={"hello"}
138+
value={code}
129139
name="UNIQUE_ID_OF_DIV"
130140
fontSize={16}
131141
theme={theme}
@@ -137,11 +147,10 @@ function Canvas({
137147
highlightActiveLine={false}
138148
editorProps={{ $blockScrolling: true }}
139149
className="ace-editor-container"
140-
150+
onChange={handleCodeChange}
141151
/>
142152
</div>
143153
</Resizable>
144-
)
154+
);
145155
}
146-
147-
export default Canvas
156+
export default Canvas;

components/Footer.tsx

Whitespace-only changes.

components/SelectBackground.tsx

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"use client";
2+
import React from "react";
3+
import { ChevronDown } from "lucide-react";
4+
import { backgrounds } from "@/utils/utility";
5+
import OutsideClickHandler from "react-outside-click-handler";
6+
7+
interface SelectBackgroundProps {
8+
background: string;
9+
setBackground: (background: string) => void;
10+
}
11+
12+
function SelectBackground({
13+
background,
14+
setBackground,
15+
}: SelectBackgroundProps) {
16+
const [showDropdown, setShowDropdown] = React.useState(false);
17+
18+
const toggleDropdown = () => {
19+
setShowDropdown(!showDropdown);
20+
};
21+
22+
const handleBackgroundChange = (newBackground: string) => {
23+
setBackground(newBackground);
24+
};
25+
26+
return (
27+
<OutsideClickHandler onOutsideClick={() => setShowDropdown(false)}>
28+
<div className="bg-selector relative" onClick={toggleDropdown}>
29+
<p className="py-[10px] text-sm font-medium">Theme Selector</p>
30+
<div className="dropdown-title w-[62px]">
31+
<div
32+
className="rounded-full w-[20px] h-[20px]"
33+
style={{
34+
background: background,
35+
}}
36+
></div>
37+
<ChevronDown />
38+
</div>
39+
{showDropdown && (
40+
<div className="dropdown-menu top-[74px] w-full rounded-full flex flex-wrap h-full gap-1">
41+
{backgrounds.map((bg, i) => {
42+
return (
43+
<div
44+
key={i}
45+
onClick={() => handleBackgroundChange(bg)}
46+
className="w-[20px] h-[20px] rounded-full"
47+
style={{ background: bg }}
48+
></div>
49+
);
50+
})}
51+
</div>
52+
)}
53+
</div>
54+
</OutsideClickHandler>
55+
);
56+
}
57+
58+
export default SelectBackground;

0 commit comments

Comments
 (0)