jubair-p 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # 🖥️ Terminal Portfolio
2
+
3
+ An interactive CLI portfolio that runs directly in the terminal.
4
+
5
+ > Anyone can run it instantly with: `npx your-npm-username`
6
+
7
+ ---
8
+
9
+ ## 🚀 Quick Start (run locally)
10
+
11
+ ```bash
12
+ # 1. Clone or download this project
13
+ cd my-portfolio
14
+
15
+ # 2. Run it
16
+ node index.js
17
+ ```
18
+
19
+ ---
20
+
21
+ ## ✏️ Customize Your Info
22
+
23
+ Open `lib/data.js` and fill in **your own** details:
24
+
25
+ | Section | What to edit |
26
+ |--------------|-------------------------------------|
27
+ | `about` | Your name, location, intro |
28
+ | `experience` | Your jobs / internships |
29
+ | `projects` | Your GitHub projects |
30
+ | `skills` | Your tech stack |
31
+ | `education` | Your degree, courses, certs |
32
+ | `contact` | Email, GitHub, LinkedIn, website |
33
+
34
+ ---
35
+
36
+ ## 📦 Publish to npm (so anyone can `npx` you)
37
+
38
+ ### Step 1 — Create an npm account
39
+ Go to https://www.npmjs.com/signup and create a free account.
40
+
41
+ ### Step 2 — Update package.json
42
+ Replace `your-npm-username` in **both** the `"name"` and `"bin"` fields with your actual npm username:
43
+
44
+ ```json
45
+ {
46
+ "name": "km-yourname",
47
+ "bin": {
48
+ "km-yourname": "./index.js"
49
+ }
50
+ }
51
+ ```
52
+
53
+ > **Tip:** npm package names must be unique. Use a prefix like your initials: `km-musthaq`, `jd-john`, etc.
54
+
55
+ ### Step 3 — Login to npm in your terminal
56
+ ```bash
57
+ npm login
58
+ ```
59
+
60
+ ### Step 4 — Publish!
61
+ ```bash
62
+ npm publish
63
+ ```
64
+
65
+ ### Step 5 — Test it works
66
+ ```bash
67
+ npx your-package-name
68
+ ```
69
+
70
+ ---
71
+
72
+ ## 🔄 Updating Your Portfolio Later
73
+
74
+ When you make changes, bump the version in `package.json` then republish:
75
+
76
+ ```bash
77
+ # Change "version": "1.0.0" to "1.0.1" in package.json, then:
78
+ npm publish
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 📁 Project Structure
84
+
85
+ ```
86
+ my-portfolio/
87
+ ├── index.js ← Main entry point (command router + display)
88
+ ├── lib/
89
+ │ ├── data.js ← ✏️ YOUR INFO GOES HERE
90
+ │ └── utils.js ← Colors, boxes, gradients (no dependencies!)
91
+ ├── package.json ← npm config
92
+ └── README.md ← This file
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 💡 Available Commands (in the portfolio)
98
+
99
+ | Command | Description |
100
+ |--------------|------------------------------|
101
+ | `help` | Show all commands |
102
+ | `about` | Who you are |
103
+ | `experience` | Work history |
104
+ | `projects` | Things you've built |
105
+ | `skills` | Your tech stack |
106
+ | `education` | Degrees & certifications |
107
+ | `contact` | How to reach you |
108
+ | `hire` | Why someone should hire you |
109
+ | `clear` | Clear the screen |
110
+ | `exit` | Quit |
111
+
112
+ ---
113
+
114
+ Built with ❤️ using pure Node.js — zero external dependencies!
@@ -0,0 +1,23 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores(['dist']),
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs.flat.recommended,
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ ecmaVersion: 2020,
20
+ globals: globals.browser,
21
+ },
22
+ },
23
+ ])
package/index.html ADDED
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>jubi-portfolio</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
package/index.js ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+
3
+ import readline from "readline";
4
+ import { createColors, createGradient, createBox } from "./lib/utils.js";
5
+ import { about, projects, skills, education, contact, experience } from "./lib/data.js";
6
+
7
+ const c = createColors();
8
+ const gradient = createGradient();
9
+
10
+ // ─── ASCII Banner ─────────────────────────────────────────────────────────────
11
+ function showBanner() {
12
+ console.clear();
13
+ console.log(gradient(`
14
+ ██╗██╗ ██╗██████╗ █████╗ ██╗██████╗ ██████╗
15
+ ██║██║ ██║██╔══██╗██╔══██╗██║██╔══██╗ ██╔══██╗
16
+ ██║██║ ██║██████╔╝███████║██║██████╔╝ ██████╔╝
17
+ ██ ██║██║ ██║██╔══██╗██╔══██║██║██╔══██╗ ██╔═══╝
18
+ ╚████╔╝╚██████╔╝██████╔╝██║ ██║██║██║ ██║ ██║
19
+ ╚═══╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝
20
+ `));
21
+ console.log(c.dim(" ─────────────────────────────────────────────────────────────"));
22
+ console.log(c.cyan(" 📱 Flutter Developer | Cross-Platform Mobile Apps"));
23
+ console.log(c.dim(" Type ") + c.yellow("help") + c.dim(" to see available commands.\n"));
24
+ }
25
+
26
+ // ─── Help ─────────────────────────────────────────────────────────────────────
27
+ function showHelp() {
28
+ const commands = [
29
+ ["about", "Who I am"],
30
+ ["experience", "My work experience"],
31
+ ["projects", "Apps I've built & published"],
32
+ ["skills", "My tech stack"],
33
+ ["education", "Academic background & certifications"],
34
+ ["contact", "Get in touch"],
35
+ ["hire", "Why you should hire me"],
36
+ ["clear", "Clear the terminal"],
37
+ ["help", "Show this menu"],
38
+ ["exit", "Quit"],
39
+ ];
40
+ console.log("\n" + createBox("Available Commands", commands.map(([cmd, desc]) =>
41
+ ` ${c.yellow(cmd.padEnd(14))} ${c.dim("→")} ${c.white(desc)}`
42
+ ).join("\n")));
43
+ }
44
+
45
+ // ─── Hire ─────────────────────────────────────────────────────────────────────
46
+ function showHire() {
47
+ console.log("\n" + createBox("💼 Why Hire Me?", [
48
+ c.green(" I'm open to exciting new Flutter opportunities!"),
49
+ "",
50
+ c.white(" What I bring:"),
51
+ c.dim(" ✔ 2+ years of Flutter production app experience"),
52
+ c.dim(" ✔ Published apps on both Play Store & App Store"),
53
+ c.dim(" ✔ Strong knowledge of state management (Bloc, Provider, GetX, Riverpod)"),
54
+ c.dim(" ✔ Firebase, REST APIs, payment gateway integrations"),
55
+ c.dim(" ✔ Clean architecture & collaborative team player"),
56
+ "",
57
+ c.cyan(` 📧 ${contact.email}`),
58
+ c.cyan(` 📱 ${contact.phone}`),
59
+ ].join("\n")));
60
+ }
61
+
62
+ // ─── Command Router ───────────────────────────────────────────────────────────
63
+ function handleCommand(input) {
64
+ const cmd = input.trim().toLowerCase();
65
+ switch (cmd) {
66
+ case "help": showHelp(); break;
67
+ case "about": printList("👤 About Me", about); break;
68
+ case "experience": printCards("💼 Experience", experience); break;
69
+ case "projects": printCards("🚀 Projects", projects); break;
70
+ case "skills": printCards("🛠️ Skills", skills); break;
71
+ case "education": printCards("🎓 Education", education); break;
72
+ case "contact": printContact(); break;
73
+ case "hire": showHire(); break;
74
+ case "clear": showBanner(); break;
75
+ case "": break;
76
+ case "exit":
77
+ case "quit":
78
+ console.log("\n" + c.cyan(" Thanks for visiting! Have a great day 👋\n"));
79
+ process.exit(0);
80
+ default:
81
+ console.log(c.red(`\n ✖ Unknown command: "${cmd}". Type ${c.yellow("help")} for commands.\n`));
82
+ }
83
+ }
84
+
85
+ function printList(title, arr) {
86
+ const lines = arr.map(line => ` ${line}`).join("\n");
87
+ console.log("\n" + createBox(title, lines));
88
+ }
89
+
90
+ function printContact() {
91
+ const lines = [
92
+ ` 📧 Email : ${c.cyan(contact.email)}`,
93
+ ` 📱 Phone : ${c.cyan(contact.phone)}`,
94
+ ` 🐙 GitHub : ${c.cyan(contact.github)}`,
95
+ ` 💼 LinkedIn: ${c.cyan(contact.linkedin)}`,
96
+ ` 📍 Location: ${c.cyan(contact.location)}`,
97
+ ].join("\n");
98
+ console.log("\n" + createBox("📬 Contact", lines));
99
+ }
100
+
101
+ function printCards(title, items) {
102
+ const lines = items.map(item => {
103
+ const out = [];
104
+ if (item.title) out.push(` ${c.yellow("▸")} ${c.bold(item.title)}`);
105
+ if (item.role) out.push(` ${c.green(item.role)}`);
106
+ if (item.period) out.push(` ${c.dim(item.period)}`);
107
+ if (item.desc) out.push(` ${c.white(item.desc)}`);
108
+ if (item.tech) out.push(` ${c.dim("Tech:")} ${c.cyan(item.tech)}`);
109
+ if (item.link) out.push(` ${c.dim("Link:")} ${c.cyan(item.link)}`);
110
+ if (item.items) item.items.forEach(i => out.push(` ${c.dim("•")} ${c.white(i)}`));
111
+ return out.join("\n");
112
+ }).join("\n\n");
113
+ console.log("\n" + createBox(title, lines));
114
+ }
115
+
116
+ // ─── Start ────────────────────────────────────────────────────────────────────
117
+ showBanner();
118
+ showHelp();
119
+
120
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
121
+
122
+ function prompt() {
123
+ rl.question(c.green("\n portfolio") + c.dim("$ "), (answer) => {
124
+ handleCommand(answer);
125
+ prompt();
126
+ });
127
+ }
128
+
129
+ rl.on("close", () => {
130
+ console.log("\n" + c.cyan(" Goodbye! 👋\n"));
131
+ process.exit(0);
132
+ });
133
+
134
+ prompt();
package/lib/data.js ADDED
@@ -0,0 +1,145 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // 🎯 JUBAIR P — Terminal Portfolio Data
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+
5
+ // ─── About ───────────────────────────────────────────────────────────────────
6
+ export const about = [
7
+ "Hi! I'm Jubair P 👋",
8
+ "",
9
+ " I'm a Flutter Developer passionate about building",
10
+ " beautiful, high-performance cross-platform mobile apps",
11
+ " for both Android and iOS.",
12
+ "",
13
+ " 🌍 Based in: Pattambi, Palakkad, Kerala, India",
14
+ " 💼 Currently: Flutter Developer at Codeedex Technologies",
15
+ " 🎯 Interests: Mobile Development, UI/UX, Firebase, REST APIs",
16
+ ];
17
+
18
+ // ─── Experience ──────────────────────────────────────────────────────────────
19
+ export const experience = [
20
+ {
21
+ title: "Code51",
22
+ role: "Flutter Developer",
23
+ period: "Jan 2026 – Present | Mangalore",
24
+ desc: "Developing cross-platform mobile applications using Flutter and Dart. Integrating REST APIs and third-party services for enhanced functionality. Collaborating with cross-functional teams to deliver high-quality mobile solutions.",
25
+ tech: "Flutter, Dart, REST APIs",
26
+ },
27
+ {
28
+ title: "Codeedex Technologies",
29
+ role: "Flutter Developer",
30
+ period: "Mar 2025 – Jan 2026 | Perinthalmanna",
31
+ desc: "Developed cross-platform mobile apps for iOS & Android. Collaborated with designers and backend engineers. Handled app publishing via Google Play Console.",
32
+ tech: "Flutter, Dart, Firebase, REST APIs",
33
+ },
34
+ {
35
+ title: "Adacode Solutions",
36
+ role: "Flutter Developer",
37
+ period: "Jun 2024 – Sep 2024 | Kozhikode",
38
+ desc: "Spearheaded design and development of multiple cross-platform apps. Delivered end-to-end solutions meeting business requirements.",
39
+ tech: "Flutter, Dart, Firebase, Provider",
40
+ },
41
+ {
42
+ title: "Luminar Technolab",
43
+ role: "Android Flutter Developer (Internship)",
44
+ period: "Oct 2023 – Apr 2024 | Kozhikode",
45
+ desc: "Built cross-platform apps with Flutter & Dart. Integrated Firebase, REST APIs, SQLite, Hive. Applied state management and version control with GitHub.",
46
+ tech: "Flutter, Dart, Firebase, SQLite, Hive, GitHub",
47
+ },
48
+ ];
49
+
50
+ // ─── Projects ────────────────────────────────────────────────────────────────
51
+ export const projects = [
52
+ {
53
+ title: "Coffee Labs — Coffee E-Commerce App",
54
+ desc: "Published Flutter e-commerce app for a Saudi Arabia company. Features WhatsApp OTP auth, FCM push notifications, Tamara payment gateway (Buy Now Pay Later), and REST API integration.",
55
+ tech: "Flutter, Dart, GetX, Firebase, FCM, REST APIs",
56
+ link: "apps.apple.com/in/app/coffee-labs/id6752988420",
57
+ },
58
+ {
59
+ title: "Syopi — Fashion Store App",
60
+ desc: "Modern e-commerce fashion app published on both Play Store and App Store. Built with Flutter + Provider, integrated Node.js REST API backend.",
61
+ tech: "Flutter, Firebase, Provider, Node.js",
62
+ link: "play.google.com/store/apps/details?id=com.syopi.usernew",
63
+ },
64
+ {
65
+ title: "KeyRoute",
66
+ desc: "Vendor & User apps with Google Maps live tracking, secure payment UI, group bookings, and trip creation. Published on Google Play Store.",
67
+ tech: "Flutter, Firebase, Provider, Google Maps, REST APIs, MVVM",
68
+ link: "Available on Google Play Store",
69
+ },
70
+ {
71
+ title: "Adacode Student App",
72
+ desc: "E-learning app offering courses in Flutter, Data Science and more. Features YouTube player integration and Firebase backend.",
73
+ tech: "Flutter, Dart, Firebase, Provider",
74
+ link: "github.com/jubairp",
75
+ },
76
+ {
77
+ title: "Skill Free 2.0",
78
+ desc: "Mobile app for day labor workers — find daily jobs, flexible scheduling, no qualifications required. Rebuilt from academic project in Flutter.",
79
+ tech: "Flutter, Dart, Firebase, Provider",
80
+ link: "github.com/jubairp",
81
+ },
82
+ {
83
+ title: "Simple Calculator App",
84
+ desc: "Clean and efficient calculator app demonstrating core Flutter state management and UI design concepts.",
85
+ tech: "Flutter, Dart",
86
+ link: "github.com/jubairp",
87
+ },
88
+ ];
89
+
90
+ // ─── Skills ──────────────────────────────────────────────────────────────────
91
+ export const skills = [
92
+ {
93
+ title: "Programming Languages",
94
+ items: ["Dart", "Python", "HTML", "SQL"],
95
+ },
96
+ {
97
+ title: "Frameworks & Libraries",
98
+ items: ["Flutter", "Provider", "Bloc", "Riverpod", "GetX", "REST APIs"],
99
+ },
100
+ {
101
+ title: "Databases",
102
+ items: ["Firebase", "SQLite", "Hive", "Airtable"],
103
+ },
104
+ {
105
+ title: "Tools & Platforms",
106
+ items: ["GitHub", "VS Code", "Android Studio", "Figma", "Google Play Console"],
107
+ },
108
+ ];
109
+
110
+ // ─── Education ───────────────────────────────────────────────────────────────
111
+ export const education = [
112
+ {
113
+ title: "Bachelor of Computer Application (BCA)",
114
+ role: "Majlis Arts And Science College, Puramannur, Kerala",
115
+ period: "2020 – 2023",
116
+ desc: "Focused on computer science fundamentals, programming, and software development.",
117
+ },
118
+ {
119
+ title: "Plus Two — Biology Science",
120
+ role: "GJHSS Naduvattam",
121
+ period: "2018 – 2020",
122
+ desc: "",
123
+ },
124
+ {
125
+ title: "SSLC",
126
+ role: "GJHSS Naduvattam",
127
+ period: "2017 – 2018",
128
+ desc: "",
129
+ },
130
+ {
131
+ title: "Store Listing Certificate",
132
+ role: "Google Play Academy",
133
+ period: "2024",
134
+ desc: "Official certification for publishing and managing apps on Google Play Store.",
135
+ },
136
+ ];
137
+
138
+ // ─── Contact ─────────────────────────────────────────────────────────────────
139
+ export const contact = {
140
+ email: "jubijubairp@gmail.com",
141
+ phone: "+91 90722 20239",
142
+ github: "github.com/jubairp",
143
+ linkedin: "linkedin.com/in/jubairp",
144
+ location: "Pattambi, Palakkad, Kerala",
145
+ };
package/lib/utils.js ADDED
@@ -0,0 +1,59 @@
1
+ // ─── ANSI Color Helpers (no external packages needed) ────────────────────────
2
+
3
+ export function createColors() {
4
+ const esc = (code) => (str) => `\x1b[${code}m${str}\x1b[0m`;
5
+ return {
6
+ reset: esc("0"),
7
+ bold: esc("1"),
8
+ dim: esc("2"),
9
+ red: esc("31"),
10
+ green: esc("32"),
11
+ yellow: esc("33"),
12
+ blue: esc("34"),
13
+ magenta: esc("35"),
14
+ cyan: esc("36"),
15
+ white: esc("37"),
16
+ bgBlue: esc("44"),
17
+ };
18
+ }
19
+
20
+ // ─── Gradient Effect (cyan → blue using ANSI 256 colors) ─────────────────────
21
+ export function createGradient() {
22
+ const colors = [51, 45, 39, 33, 27, 21, 57, 93];
23
+ return (text) => {
24
+ const lines = text.split("\n");
25
+ return lines.map((line, i) => {
26
+ const colorCode = colors[i % colors.length];
27
+ return `\x1b[38;5;${colorCode}m${line}\x1b[0m`;
28
+ }).join("\n");
29
+ };
30
+ }
31
+
32
+ // ─── Box Drawing ──────────────────────────────────────────────────────────────
33
+ export function createBox(title, content) {
34
+ const c = createColors();
35
+ const lines = content.split("\n");
36
+
37
+ // Find the longest visible line (strip ANSI codes for measurement)
38
+ const stripAnsi = (str) => str.replace(/\x1b\[[0-9;]*m/g, "");
39
+ const maxLen = Math.max(
40
+ title.length + 4,
41
+ ...lines.map((l) => stripAnsi(l).length + 2)
42
+ );
43
+
44
+ const width = maxLen + 2;
45
+ const top = c.cyan(" ╭" + "─".repeat(2) + " " + c.bold(c.white(title)) + " " + c.cyan("─".repeat(Math.max(0, width - title.length - 5)) + "╮"));
46
+ const bottom = c.cyan(" ╰" + "─".repeat(width) + "╯");
47
+ const mid = lines.map((line) => {
48
+ const visible = stripAnsi(line);
49
+ const pad = width - visible.length - 1;
50
+ return c.cyan(" │") + " " + line + " ".repeat(Math.max(0, pad)) + c.cyan("│");
51
+ });
52
+
53
+ return [top, ...mid, bottom].join("\n");
54
+ }
55
+
56
+ export function createBanner() {
57
+ const c = createColors();
58
+ return (text) => c.cyan(text);
59
+ }
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "jubair-p",
3
+ "version": "1.0.0",
4
+ "description": "Interactive terminal portfolio — type 'npx jubair-p' to run!",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "jubair-p": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js"
12
+ },
13
+ "keywords": ["portfolio", "terminal", "cli", "interactive", "developer"],
14
+ "author": "Jubair P <jubair@example.com>",
15
+ "license": "MIT",
16
+ "engines": {
17
+ "node": ">=14.0.0"
18
+ }
19
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/src/App.css ADDED
@@ -0,0 +1,42 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+
21
+ @keyframes logo-spin {
22
+ from {
23
+ transform: rotate(0deg);
24
+ }
25
+ to {
26
+ transform: rotate(360deg);
27
+ }
28
+ }
29
+
30
+ @media (prefers-reduced-motion: no-preference) {
31
+ a:nth-of-type(2) .logo {
32
+ animation: logo-spin infinite 20s linear;
33
+ }
34
+ }
35
+
36
+ .card {
37
+ padding: 2em;
38
+ }
39
+
40
+ .read-the-docs {
41
+ color: #888;
42
+ }
package/src/App.tsx ADDED
@@ -0,0 +1,35 @@
1
+ import { useState } from 'react'
2
+ import reactLogo from './assets/react.svg'
3
+ import viteLogo from '/vite.svg'
4
+ import './App.css'
5
+
6
+ function App() {
7
+ const [count, setCount] = useState(0)
8
+
9
+ return (
10
+ <>
11
+ <div>
12
+ <a href="https://vite.dev" target="_blank">
13
+ <img src={viteLogo} className="logo" alt="Vite logo" />
14
+ </a>
15
+ <a href="https://react.dev" target="_blank">
16
+ <img src={reactLogo} className="logo react" alt="React logo" />
17
+ </a>
18
+ </div>
19
+ <h1>Vite + React</h1>
20
+ <div className="card">
21
+ <button onClick={() => setCount((count) => count + 1)}>
22
+ count is {count}
23
+ </button>
24
+ <p>
25
+ Edit <code>src/App.tsx</code> and save to test HMR
26
+ </p>
27
+ </div>
28
+ <p className="read-the-docs">
29
+ Click on the Vite and React logos to learn more
30
+ </p>
31
+ </>
32
+ )
33
+ }
34
+
35
+ export default App
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
package/src/index.css ADDED
@@ -0,0 +1,68 @@
1
+ :root {
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ a {
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
+ }
21
+ a:hover {
22
+ color: #535bf2;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ display: flex;
28
+ place-items: center;
29
+ min-width: 320px;
30
+ min-height: 100vh;
31
+ }
32
+
33
+ h1 {
34
+ font-size: 3.2em;
35
+ line-height: 1.1;
36
+ }
37
+
38
+ button {
39
+ border-radius: 8px;
40
+ border: 1px solid transparent;
41
+ padding: 0.6em 1.2em;
42
+ font-size: 1em;
43
+ font-weight: 500;
44
+ font-family: inherit;
45
+ background-color: #1a1a1a;
46
+ cursor: pointer;
47
+ transition: border-color 0.25s;
48
+ }
49
+ button:hover {
50
+ border-color: #646cff;
51
+ }
52
+ button:focus,
53
+ button:focus-visible {
54
+ outline: 4px auto -webkit-focus-ring-color;
55
+ }
56
+
57
+ @media (prefers-color-scheme: light) {
58
+ :root {
59
+ color: #213547;
60
+ background-color: #ffffff;
61
+ }
62
+ a:hover {
63
+ color: #747bff;
64
+ }
65
+ button {
66
+ background-color: #f9f9f9;
67
+ }
68
+ }
package/src/main.tsx ADDED
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ },
27
+ "include": ["src"]
28
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react-swc'
3
+
4
+ // https://vite.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ })