Skip to content

Commit 594c544

Browse files
Merge pull request #8 from nayna-G/feature1-pr
ft.added theme toggle
2 parents b9bf9d3 + 281a5e0 commit 594c544

File tree

2 files changed

+80
-70
lines changed

2 files changed

+80
-70
lines changed

src/app/globals.css

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,32 @@
33
:root {
44
--background: #ffffff;
55
--foreground: #171717;
6+
--card-bg: #f5f5f5;
7+
--button-bg: #e0e0e0;
8+
--button-text: #171717;
69
}
710

8-
@theme inline {
9-
--color-background: var(--background);
10-
--color-foreground: var(--foreground);
11-
--font-sans: var(--font-geist-sans);
12-
--font-mono: var(--font-geist-mono);
13-
}
14-
15-
@media (prefers-color-scheme: dark) {
16-
:root {
17-
--background: #0a0a0a;
18-
--foreground: #ededed;
19-
}
11+
[data-theme='dark'] {
12+
--background: #0d1117;
13+
--foreground: #ffffff;
14+
--card-bg: #161b22;
15+
--button-bg: #1f2937;
16+
--button-text: #ffffff;
2017
}
2118

2219
body {
2320
background: var(--background);
2421
color: var(--foreground);
2522
font-family: Arial, Helvetica, sans-serif;
23+
transition: background 0.3s ease, color 0.3s ease;
24+
}
25+
26+
textarea,
27+
label {
28+
background: var(--card-bg);
29+
transition: background 0.3s ease, color 0.3s ease;
30+
}
31+
32+
button {
33+
transition: background 0.3s ease, color 0.3s ease;
2634
}

src/app/page.tsx

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,27 @@ export default function ScriptGenerator() {
3434
const [selectedTools, setSelectedTools] = useState<string[]>([]);
3535
const [loading, setLoading] = useState(true);
3636

37-
// Load and parse JSON data on mount
37+
// Theme
38+
const [theme, setTheme] = useState<"light" | "dark">("dark");
3839
useEffect(() => {
39-
const fetchAndParse = async () => {
40-
try {
41-
const res = await fetch("./tools.json");
42-
if (!res.ok) {
43-
throw new Error('Failed to fetch JSON file');
44-
}
40+
document.documentElement.setAttribute("data-theme", theme);
41+
}, [theme]);
4542

43+
// Fetch tools
44+
useEffect(() => {
45+
const fetchTools = async () => {
46+
try {
47+
const res = await fetch("./tools.json");
48+
if (!res.ok) throw new Error("Failed to fetch JSON");
4649
const data: ToolCategory[] = await res.json();
4750
setToolsData(data);
48-
} catch (error) {
49-
console.error("Failed to load JSON data", error);
50-
alert('Failed to load tool data. Please try again later.');
51+
} catch {
52+
alert("Failed to load tool data.");
5153
} finally {
5254
setLoading(false);
5355
}
5456
};
55-
56-
fetchAndParse();
57+
fetchTools();
5758
}, []);
5859

5960
const handleToolSelect = (toolName: string) => {
@@ -62,66 +63,69 @@ export default function ScriptGenerator() {
6263
);
6364
};
6465

65-
const generateScript = (): string => {
66-
return toolsData
66+
const generateScript = () =>
67+
toolsData
6768
.flatMap((category) =>
6869
category.tools
6970
.filter((tool) => selectedTools.includes(tool.name) && tool.install[selectedPkg])
70-
.map((tool) => tool.install[selectedPkg] as string)
71+
.map((tool) => tool.install[selectedPkg]!)
7172
)
7273
.join("\n");
73-
};
7474

7575
const handleCopy = async () => {
7676
try {
7777
await navigator.clipboard.writeText(generateScript());
78-
alert("Script copied to clipboard!");
79-
} catch (err) {
80-
alert("Failed to copy script: " + err);
78+
alert("Script copied!");
79+
} catch {
80+
alert("Failed to copy");
8181
}
8282
};
8383

8484
const handleDownload = () => {
85-
const script = generateScript();
86-
const blob = new Blob([script], { type: "text/plain;charset=utf-8" });
87-
const url = URL.createObjectURL(blob);
85+
const blob = new Blob([generateScript()], { type: "text/plain" });
8886
const link = document.createElement("a");
89-
link.href = url;
87+
link.href = URL.createObjectURL(blob);
9088
link.download = "install_script.sh";
91-
document.body.appendChild(link);
9289
link.click();
93-
document.body.removeChild(link);
9490
};
9591

96-
// Loading UI
97-
if (loading) {
92+
if (loading)
9893
return (
99-
<div className="text-white font-sans text-center mt-20">
94+
<div className="text-[var(--foreground)] font-sans text-center mt-20">
10095
<div>Loading tools data...</div>
101-
<div className="spinner"></div> {/* Optionally add a spinner here */}
96+
<div className="spinner"></div>
10297
</div>
10398
);
104-
}
10599

106100
return (
107-
<div className="bg-[#0d1117] min-h-screen text-white font-sans">
101+
<div
102+
className="min-h-screen font-sans bg-[var(--background)] text-[var(--foreground)] transition-colors duration-300"
103+
data-theme={theme}
104+
>
108105
<div className="max-w-screen mx-auto px-4 py-10">
109-
<h1 className="relative flex items-center justify-center text-4xl sm:text-6xl font-extrabold mb-10 tracking-tight">
106+
{/* Header with Add + and theme toggle */}
107+
<h1 className="flex items-center justify-center text-4xl sm:text-6xl font-extrabold mb-10 relative tracking-tight">
110108
DevSetup
111-
<a
112-
href="https://forms.gle/cWfDnzvYo5dBuy7C7"
113-
target="_blank"
114-
rel="noopener noreferrer"
115-
className="absolute right-0 top-1/2 -translate-y-1/2 px-6 py-3 text-lg
116-
bg-gradient-to-r from-indigo-500 to-purple-600
117-
hover:from-indigo-600 hover:to-purple-700
118-
text-white font-semibold rounded-full shadow-lg
119-
transition duration-200"
120-
>
121-
Add New +
122-
</a>
123-
</h1>
109+
<div className="absolute right-0 top-1/2 -translate-y-1/2 flex gap-3">
110+
{/* Add New + button */}
111+
<a
112+
href="https://forms.gle/cWfDnzvYo5dBuy7C7"
113+
target="_blank"
114+
rel="noopener noreferrer"
115+
className="px-6 py-3 text-lg bg-gradient-to-r from-indigo-500 to-purple-600 hover:from-indigo-600 hover:to-purple-700 text-white font-semibold rounded-full shadow-lg transition duration-300"
116+
>
117+
Add New +
118+
</a>
124119

120+
{/* Theme Toggle button (exactly same size/style as Add +) */}
121+
<button
122+
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
123+
className="px-6 py-3 text-lg bg-gradient-to-r from-gray-500 to-gray-700 hover:from-gray-600 hover:to-gray-800 text-white font-semibold rounded-full shadow-lg transition duration-300"
124+
>
125+
{theme === "light" ? "🌞 Light" : "🌙 Dark"}
126+
</button>
127+
</div>
128+
</h1>
125129

126130
{/* OS Selector */}
127131
<div className="flex flex-wrap gap-3 justify-center sm:justify-start mb-6">
@@ -133,10 +137,10 @@ export default function ScriptGenerator() {
133137
setSelectedPkg(pkgManagers[os][0]);
134138
setSelectedTools([]);
135139
}}
136-
className={`px-4 py-2 rounded-xl text-sm font-semibold transition duration-200 ${
140+
className={`px-6 py-3 rounded-full text-sm font-semibold transition duration-200 ${
137141
selectedOS === os
138-
? "bg-indigo-600 text-white shadow-lg"
139-
: "bg-gray-800 hover:bg-gray-700 text-gray-300"
142+
? "bg-gradient-to-r from-indigo-500 to-purple-600 text-white shadow-lg"
143+
: "bg-[var(--button-bg)] text-[var(--button-text)] hover:bg-gray-700"
140144
}`}
141145
>
142146
{os.toUpperCase()}
@@ -153,10 +157,10 @@ export default function ScriptGenerator() {
153157
setSelectedPkg(pkg);
154158
setSelectedTools([]);
155159
}}
156-
className={`px-4 py-2 rounded-xl text-sm font-semibold transition duration-200 ${
160+
className={`px-6 py-3 rounded-full text-sm font-semibold transition duration-200 ${
157161
selectedPkg === pkg
158-
? "bg-green-600 text-white shadow-lg"
159-
: "bg-gray-800 hover:bg-gray-700 text-gray-300"
162+
? "bg-gradient-to-r from-green-500 to-green-600 text-white shadow-lg"
163+
: "bg-[var(--button-bg)] text-[var(--button-text)] hover:bg-gray-700"
160164
}`}
161165
>
162166
{pkg}
@@ -176,10 +180,8 @@ export default function ScriptGenerator() {
176180
return (
177181
<label
178182
key={index}
179-
className={`relative flex flex-col items-center justify-center bg-[#161b22] rounded-2xl p-4 transition cursor-pointer border border-transparent ${
180-
isAvailable
181-
? "hover:shadow-xl hover:border-indigo-500"
182-
: "opacity-40 cursor-not-allowed"
183+
className={`relative flex flex-col items-center justify-center rounded-2xl p-4 transition cursor-pointer border border-transparent bg-[var(--card-bg)] ${
184+
isAvailable? "hover:shadow-xl hover:border-indigo-500" : "opacity-50 cursor-not-allowed"
183185
}`}
184186
>
185187
<input
@@ -204,21 +206,21 @@ export default function ScriptGenerator() {
204206
readOnly
205207
value={generateScript()}
206208
rows={6}
207-
className="w-full bg-[#0d1117] text-gray-100 border border-gray-600 rounded-lg p-4 font-mono resize-none"
209+
className="w-full bg-[var(--card-bg)] text-[var(--foreground)] border border-gray-600 rounded-lg p-4 font-mono resize-none transition-colors duration-300"
208210
/>
209211
</div>
210212

211213
{/* Actions */}
212214
<div className="mt-6 flex flex-wrap gap-4">
213215
<button
214216
onClick={handleCopy}
215-
className="px-5 py-2.5 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-xl transition"
217+
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-full shadow-lg transition duration-300"
216218
>
217219
Copy to Clipboard
218220
</button>
219221
<button
220222
onClick={handleDownload}
221-
className="px-5 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-xl transition"
223+
className="px-6 py-3 bg-indigo-600 hover:bg-indigo-700 text-white font-semibold rounded-full shadow-lg transition duration-300"
222224
>
223225
Download Script
224226
</button>

0 commit comments

Comments
 (0)