@vatvaghool/create-ipl-dashboard 0.1.12 → 0.1.13
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 +37 -7
- package/package.json +1 -1
- package/src/index.mjs +5 -4
- package/src/prompts.mjs +3 -11
- package/src/scaffold.mjs +40 -12
- package/template/scripts/seed-league.mjs +4 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Scaffold a full-featured IPL fantasy cricket dashboard in seconds.
|
|
|
6
6
|
npx @vatvaghool/create-ipl-dashboard my-league
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Follow the prompts to enter your
|
|
9
|
+
Follow the prompts to enter your fantasy league URL, collection name, and team names — the database is pre-configured, so you don't need to provide a MongoDB URI. You get a ready-to-run Next.js dashboard with standings charts, performance trackers, AI roasts, and more.
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
@@ -26,12 +26,14 @@ npx @vatvaghool/create-ipl-dashboard [project-name] [options]
|
|
|
26
26
|
|
|
27
27
|
| Prompt | Description |
|
|
28
28
|
|--------|-------------|
|
|
29
|
-
|
|
|
29
|
+
| Project name | Directory to scaffold into |
|
|
30
30
|
| League URL | The fantasy.iplt20.com league page URL |
|
|
31
|
-
|
|
|
32
|
-
| League name | Display name for your league
|
|
31
|
+
| Collection name | MongoDB collection to store this league's data (e.g. `ipl_2025_office_league`) |
|
|
32
|
+
| League name | Display name for your league |
|
|
33
33
|
| Teams | Team names (and optional owners) in your league |
|
|
34
34
|
|
|
35
|
+
The database connection (`MONGODB_URI`) is hardcoded — you only need to specify which collection each league should use.
|
|
36
|
+
|
|
35
37
|
If `--scrape` is provided, the CLI attempts to extract team names from the league page HTML. If that fails, it falls back to manual entry.
|
|
36
38
|
|
|
37
39
|
## Screenshots
|
|
@@ -71,7 +73,7 @@ A full Next.js 16 project with:
|
|
|
71
73
|
- **AI roasting** — generated commentary in multiple languages
|
|
72
74
|
- **Stock ticker** — fantasy stocks with sparklines
|
|
73
75
|
- **Live updates** — bookmarklet or Playwright scraper for live sync
|
|
74
|
-
- **MongoDB persistence** —
|
|
76
|
+
- **MongoDB persistence** — auto-configured database connection
|
|
75
77
|
|
|
76
78
|
## Quick start after scaffold
|
|
77
79
|
|
|
@@ -95,11 +97,39 @@ Open http://localhost:3000 to see your dashboard.
|
|
|
95
97
|
The CLI:
|
|
96
98
|
|
|
97
99
|
1. Copies a pre-built Next.js app template
|
|
98
|
-
2. Writes your `.env` with
|
|
100
|
+
2. Writes your `.env` with the pre-configured `MONGODB_URI`, `COLLECTION_NAME`, league URL, and league name
|
|
99
101
|
3. Generates `app/data/teams.ts` with your team roster
|
|
100
102
|
4. Generates `app/data/league.ts` with league metadata
|
|
101
103
|
5. Creates a placeholder `app/data/match-points.ts` (auto-populates as you sync)
|
|
102
104
|
6. Installs dependencies
|
|
103
|
-
7.
|
|
105
|
+
7. Runs `seed:league` to create a **document in your specified collection** in the pre-configured database, storing league metadata (name, URL, teams, timestamps)
|
|
106
|
+
|
|
107
|
+
Each league gets its own collection — run `create-ipl-dashboard` again with a different collection name to add another league.
|
|
104
108
|
|
|
105
109
|
The template includes all dashboard components, API endpoints, scrapers, and tests from the [ipl-dashboard](https://github.com/anomalyco/ipl-dashboard) project.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Next Steps
|
|
114
|
+
|
|
115
|
+
### Adding more leagues
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx @vatvaghool/create-ipl-dashboard another-league
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Provide a different collection name (e.g. `ipl_2025_friends_league`) and the new league will be stored in its own collection — data stays fully isolated.
|
|
122
|
+
|
|
123
|
+
### Viewing seeded data
|
|
124
|
+
|
|
125
|
+
Connect to the MongoDB instance with any MongoDB client. Each league appears as a separate collection containing a document with `type: "league"` and all the metadata (name, URL, teams, timestamps).
|
|
126
|
+
|
|
127
|
+
### Production deployment
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd my-league
|
|
131
|
+
npm run build
|
|
132
|
+
npx vercel --prod
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Set `IPL_POST_SECRET` in your Vercel dashboard. The `MONGODB_URI` and `COLLECTION_NAME` are already configured in the scaffolded `.env`.
|
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { mkdir } from "node:fs/promises";
|
|
6
|
-
import { getProjectName,
|
|
6
|
+
import { getProjectName, getLeagueUrl, getCollectionName, getLeagueName, getTeams, close } from "./prompts.mjs";
|
|
7
7
|
import { scaffoldProject } from "./scaffold.mjs";
|
|
8
8
|
import { scrapeTeamsFromUrl } from "./scraper.mjs";
|
|
9
9
|
|
|
10
|
+
const MONGODB_URI = "mongodb+srv://admin:admin@cricket.ptjjrub.mongodb.net/?appName=cricket";
|
|
11
|
+
|
|
10
12
|
function printHelp(exitCode) {
|
|
11
13
|
console.log(`
|
|
12
14
|
create-ipl-dashboard [project-name] [options]
|
|
@@ -59,9 +61,8 @@ async function main() {
|
|
|
59
61
|
|
|
60
62
|
await mkdir(projectPath, { recursive: true });
|
|
61
63
|
|
|
62
|
-
const mongoUri = await getMongoUri();
|
|
63
64
|
const leagueUrl = await getLeagueUrl();
|
|
64
|
-
const
|
|
65
|
+
const collectionName = await getCollectionName();
|
|
65
66
|
const leagueName = await getLeagueName();
|
|
66
67
|
let teams;
|
|
67
68
|
|
|
@@ -80,7 +81,7 @@ async function main() {
|
|
|
80
81
|
|
|
81
82
|
close();
|
|
82
83
|
|
|
83
|
-
await scaffoldProject(projectPath, { mongoUri, leagueUrl,
|
|
84
|
+
await scaffoldProject(projectPath, { mongoUri: MONGODB_URI, leagueUrl, collectionName, leagueName, teams, skipInstall: flags.skipInstall });
|
|
84
85
|
|
|
85
86
|
console.log("");
|
|
86
87
|
console.log(" Next steps:");
|
package/src/prompts.mjs
CHANGED
|
@@ -33,14 +33,6 @@ export async function getProjectName(args) {
|
|
|
33
33
|
return (await prompt("Project name: ")).trim() || "ipl-dashboard";
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export async function getMongoUri() {
|
|
37
|
-
if (!isTTY) {
|
|
38
|
-
await consumeAllLines();
|
|
39
|
-
return (pipedLines[promptIndex++] || "").trim();
|
|
40
|
-
}
|
|
41
|
-
return (await prompt("MongoDB URI (or press Enter to skip, can be set later): ")).trim();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
36
|
export async function getLeagueUrl() {
|
|
45
37
|
if (!isTTY) {
|
|
46
38
|
await consumeAllLines();
|
|
@@ -49,12 +41,12 @@ export async function getLeagueUrl() {
|
|
|
49
41
|
return (await prompt("IPL fantasy league URL (or press Enter to skip, can be set later): ")).trim();
|
|
50
42
|
}
|
|
51
43
|
|
|
52
|
-
export async function
|
|
44
|
+
export async function getCollectionName() {
|
|
53
45
|
if (!isTTY) {
|
|
54
46
|
await consumeAllLines();
|
|
55
|
-
return (pipedLines[promptIndex++] || "").trim();
|
|
47
|
+
return (pipedLines[promptIndex++] || "league_data").trim();
|
|
56
48
|
}
|
|
57
|
-
return (await prompt("
|
|
49
|
+
return (await prompt("MongoDB collection name for league data (e.g. ipl_2025_office_league): ")).trim() || "league_data";
|
|
58
50
|
}
|
|
59
51
|
|
|
60
52
|
export async function getLeagueName() {
|
package/src/scaffold.mjs
CHANGED
|
@@ -8,7 +8,10 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
8
8
|
const PACKAGE_ROOT = join(__dirname, "..");
|
|
9
9
|
const TEMPLATE_DIR = join(PACKAGE_ROOT, "template");
|
|
10
10
|
|
|
11
|
-
export async function scaffoldProject(
|
|
11
|
+
export async function scaffoldProject(
|
|
12
|
+
projectPath,
|
|
13
|
+
{ mongoUri, leagueUrl, collectionName, leagueName, teams, skipInstall = false },
|
|
14
|
+
) {
|
|
12
15
|
console.log(`\nCreating project at ${projectPath}...`);
|
|
13
16
|
|
|
14
17
|
await mkdir(projectPath, { recursive: true });
|
|
@@ -19,44 +22,69 @@ export async function scaffoldProject(projectPath, { mongoUri, leagueUrl, league
|
|
|
19
22
|
console.log(" (no template directory found, generating from scratch)");
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
for (const f of [
|
|
23
|
-
|
|
25
|
+
for (const f of [
|
|
26
|
+
"AGENTS.md",
|
|
27
|
+
"tsconfig.tsbuildinfo",
|
|
28
|
+
"tsconfig.buildinfo",
|
|
29
|
+
"package-lock.json",
|
|
30
|
+
]) {
|
|
31
|
+
try {
|
|
32
|
+
await rm(join(projectPath, f));
|
|
33
|
+
} catch {}
|
|
24
34
|
}
|
|
25
35
|
|
|
26
|
-
await writeEnvFile(projectPath, {
|
|
36
|
+
await writeEnvFile(projectPath, {
|
|
37
|
+
mongoUri,
|
|
38
|
+
leagueUrl,
|
|
39
|
+
collectionName,
|
|
40
|
+
leagueName,
|
|
41
|
+
});
|
|
27
42
|
await writeTeamData(projectPath, teams);
|
|
28
43
|
await writeLeagueData(projectPath, { leagueName, leagueUrl, teams });
|
|
29
44
|
await writeMatchPointsPlaceholder(projectPath);
|
|
30
45
|
await updatePackageJson(projectPath);
|
|
31
46
|
|
|
32
|
-
for (const f of [
|
|
33
|
-
|
|
47
|
+
for (const f of [
|
|
48
|
+
"app/api/ipl/live-snapshot.json",
|
|
49
|
+
"app/api/ipl/transfers/live-snapshot.json",
|
|
50
|
+
]) {
|
|
51
|
+
try {
|
|
52
|
+
await rm(join(projectPath, f));
|
|
53
|
+
} catch {}
|
|
34
54
|
}
|
|
35
55
|
|
|
36
56
|
if (!skipInstall) {
|
|
37
57
|
console.log(" Running npm install...");
|
|
38
58
|
execSync("npm install", { cwd: projectPath, stdio: "inherit" });
|
|
39
59
|
|
|
40
|
-
if (
|
|
60
|
+
if (mongoUri && leagueName) {
|
|
41
61
|
console.log(" Seeding league metadata into MongoDB...");
|
|
42
62
|
try {
|
|
43
|
-
execSync(`npm run seed:league -- "${leagueName}"
|
|
63
|
+
execSync(`npm run seed:league -- "${leagueName}" "${collectionName}"`, {
|
|
64
|
+
cwd: projectPath,
|
|
65
|
+
stdio: "inherit",
|
|
66
|
+
});
|
|
44
67
|
} catch {
|
|
45
68
|
console.log(" League seed skipped (MongoDB may not be reachable yet)");
|
|
46
69
|
}
|
|
47
70
|
}
|
|
48
71
|
} else {
|
|
49
|
-
console.log(
|
|
72
|
+
console.log(
|
|
73
|
+
" Skipping npm install (run manually: cd <project> && npm install)",
|
|
74
|
+
);
|
|
50
75
|
}
|
|
51
76
|
|
|
52
77
|
console.log("\n Done! Your project is ready at:", projectPath);
|
|
53
78
|
}
|
|
54
79
|
|
|
55
|
-
async function writeEnvFile(
|
|
80
|
+
async function writeEnvFile(
|
|
81
|
+
projectPath,
|
|
82
|
+
{ mongoUri, leagueUrl, collectionName, leagueName },
|
|
83
|
+
) {
|
|
56
84
|
const envPath = join(projectPath, ".env");
|
|
57
85
|
const lines = [
|
|
58
86
|
`MONGODB_URI=${mongoUri || ""}`,
|
|
59
|
-
`
|
|
87
|
+
`COLLECTION_NAME=${collectionName || "league_data"}`,
|
|
60
88
|
`IPL_LEAGUE_URL=${leagueUrl || ""}`,
|
|
61
89
|
`IPL_LEAGUE_NAME=${leagueName || ""}`,
|
|
62
90
|
`IPL_POST_SECRET=`,
|
|
@@ -115,7 +143,7 @@ async function writeLeagueData(projectPath, { leagueName, leagueUrl, teams }) {
|
|
|
115
143
|
await mkdir(dir, { recursive: true });
|
|
116
144
|
|
|
117
145
|
const teamEntries = teams
|
|
118
|
-
.map((t
|
|
146
|
+
.map((t) => ` { id: ${t.id}, name: "${t.name}", owner: "${t.owner}" }`)
|
|
119
147
|
.join(",\n");
|
|
120
148
|
|
|
121
149
|
const content = `export type LeagueInfo = {
|
|
@@ -27,9 +27,11 @@ async function main() {
|
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const collectionName = process.argv[3] || process.env.COLLECTION_NAME?.trim() || sanitizeCollectionName(leagueName);
|
|
31
|
+
|
|
32
|
+
const uri = process.env.MONGODB_URI;
|
|
31
33
|
if (!uri) {
|
|
32
|
-
console.log("
|
|
34
|
+
console.log("MONGODB_URI not set. Skipping league seed.");
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -54,8 +56,6 @@ async function main() {
|
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
|
|
57
|
-
const collectionName = sanitizeCollectionName(leagueName);
|
|
58
|
-
|
|
59
59
|
const { MongoClient } = await import("mongodb");
|
|
60
60
|
const client = new MongoClient(uri);
|
|
61
61
|
|