@dytsou/calendar-build 1.1.1
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 +98 -0
- package/build.js +53 -0
- package/index.html.template +96 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Calendar App
|
|
2
|
+
|
|
3
|
+
A simple calendar application that displays multiple Google Calendars in a single view.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
1. Copy `.env.example` to `.env`:
|
|
8
|
+
```bash
|
|
9
|
+
cp .env.example .env
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Edit `.env` and add your calendar sources (comma-separated):
|
|
13
|
+
```
|
|
14
|
+
CALENDAR_SOURCES=calendar1,calendar2,calendar3
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
3. Build the HTML file:
|
|
18
|
+
```bash
|
|
19
|
+
# Option 1: Using npm/pnpm (after installing)
|
|
20
|
+
pnpm install
|
|
21
|
+
pnpm run build
|
|
22
|
+
# or use the global command if installed globally
|
|
23
|
+
calendar-build
|
|
24
|
+
|
|
25
|
+
# Option 2: Direct execution
|
|
26
|
+
node build.js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
4. Open `index.html` in your browser.
|
|
30
|
+
|
|
31
|
+
## Install Package
|
|
32
|
+
|
|
33
|
+
This package is published to **both registries**:
|
|
34
|
+
|
|
35
|
+
- **npmjs.com**: https://www.npmjs.com/package/@dytsou/calendar-build
|
|
36
|
+
- **GitHub Packages**: https://github.com/dytsou/cal/packages
|
|
37
|
+
|
|
38
|
+
### Installation from npmjs (Default - Recommended)
|
|
39
|
+
|
|
40
|
+
**Global installation:**
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g @dytsou/calendar-build
|
|
43
|
+
# or
|
|
44
|
+
pnpm install -g @dytsou/calendar-build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Then use anywhere:
|
|
48
|
+
```bash
|
|
49
|
+
calendar-build
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Local installation:**
|
|
53
|
+
```bash
|
|
54
|
+
npm install @dytsou/calendar-build
|
|
55
|
+
# or
|
|
56
|
+
pnpm install @dytsou/calendar-build
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then use:
|
|
60
|
+
```bash
|
|
61
|
+
npx calendar-build
|
|
62
|
+
# or
|
|
63
|
+
pnpm run build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Installation from GitHub Packages
|
|
67
|
+
|
|
68
|
+
If you prefer to install from GitHub Packages:
|
|
69
|
+
|
|
70
|
+
**1. Setup GitHub Packages Authentication**
|
|
71
|
+
|
|
72
|
+
Create or edit `.npmrc` file in your home directory:
|
|
73
|
+
|
|
74
|
+
```ini
|
|
75
|
+
@dytsou:registry=https://npm.pkg.github.com
|
|
76
|
+
//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**2. Get your GitHub token:**
|
|
80
|
+
1. Go to https://github.com/settings/tokens
|
|
81
|
+
2. Click "Generate new token" → "Generate new token (classic)"
|
|
82
|
+
3. Select `read:packages` permission
|
|
83
|
+
4. Copy the token and replace `YOUR_GITHUB_TOKEN` in `.npmrc`
|
|
84
|
+
|
|
85
|
+
**3. Install:**
|
|
86
|
+
```bash
|
|
87
|
+
npm install -g @dytsou/calendar-build
|
|
88
|
+
# or
|
|
89
|
+
pnpm install -g @dytsou/calendar-build
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
- `index.html.template` - Template file with placeholder for calendar sources
|
|
95
|
+
- `build.js` - Build script that injects calendar sources from `.env`
|
|
96
|
+
- `.env` - Local environment file (not committed to git)
|
|
97
|
+
- `.env.example` - Example environment file template
|
|
98
|
+
|
package/build.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
// Read .env file
|
|
7
|
+
const envPath = path.join(__dirname, '.env');
|
|
8
|
+
if (!fs.existsSync(envPath)) {
|
|
9
|
+
console.error('Error: .env file not found');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
14
|
+
const envLines = envContent.split('\n');
|
|
15
|
+
|
|
16
|
+
// Parse CALENDAR_SOURCES from .env
|
|
17
|
+
let calendarSources = [];
|
|
18
|
+
for (const line of envLines) {
|
|
19
|
+
if (line.startsWith('CALENDAR_SOURCES=')) {
|
|
20
|
+
const value = line.substring('CALENDAR_SOURCES='.length).trim();
|
|
21
|
+
calendarSources = value.split(',').map(s => s.trim()).filter(s => s);
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (calendarSources.length === 0) {
|
|
27
|
+
console.error('Error: No calendar sources found in .env file');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Read template HTML
|
|
32
|
+
const templatePath = path.join(__dirname, 'index.html.template');
|
|
33
|
+
if (!fs.existsSync(templatePath)) {
|
|
34
|
+
console.error('Error: index.html.template not found');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let html = fs.readFileSync(templatePath, 'utf-8');
|
|
39
|
+
|
|
40
|
+
// Generate calendar array as JavaScript code
|
|
41
|
+
const calendarArrayCode = '[\n' + calendarSources
|
|
42
|
+
.map(cal => ` "${cal}"`)
|
|
43
|
+
.join(',\n') + '\n ]';
|
|
44
|
+
|
|
45
|
+
// Replace placeholder
|
|
46
|
+
html = html.replace('{{CALENDAR_SOURCES}}', calendarArrayCode);
|
|
47
|
+
|
|
48
|
+
// Write built HTML
|
|
49
|
+
const outputPath = path.join(__dirname, 'index.html');
|
|
50
|
+
fs.writeFileSync(outputPath, html, 'utf-8');
|
|
51
|
+
|
|
52
|
+
console.log(`✓ Built index.html with ${calendarSources.length} calendar source(s)`);
|
|
53
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-TW">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>My Calendar</title>
|
|
8
|
+
<link rel="icon" type="image/png" href="asset/favicon.png">
|
|
9
|
+
|
|
10
|
+
<style>
|
|
11
|
+
body {
|
|
12
|
+
transition: opacity ease-in 0.2s;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body[unresolved] {
|
|
16
|
+
opacity: 0;
|
|
17
|
+
display: block;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
position: relative;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
iframe {
|
|
23
|
+
border: solid 1px #777;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100vh;
|
|
26
|
+
}
|
|
27
|
+
</style>
|
|
28
|
+
</head>
|
|
29
|
+
|
|
30
|
+
<body unresolved>
|
|
31
|
+
|
|
32
|
+
<iframe id="calendarFrame" frameborder="0" scrolling="no"></iframe>
|
|
33
|
+
|
|
34
|
+
<script>
|
|
35
|
+
const calendarBaseURL = "https://calendar.google.com/calendar/embed?";
|
|
36
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
37
|
+
const calendarParams = new URLSearchParams({
|
|
38
|
+
height: 600,
|
|
39
|
+
wkst: 1,
|
|
40
|
+
ctz: "Asia/Taipei",
|
|
41
|
+
showPrint: 0,
|
|
42
|
+
showTitle: 0,
|
|
43
|
+
showDate: 0,
|
|
44
|
+
showNav: 0,
|
|
45
|
+
showCalendars: 0,
|
|
46
|
+
showTabs: 0,
|
|
47
|
+
mode: "WEEK"
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const calendars = {{CALENDAR_SOURCES}};
|
|
51
|
+
|
|
52
|
+
const defaultColor = "%23A1B3FF";
|
|
53
|
+
|
|
54
|
+
const parseDatesRange = (value) => {
|
|
55
|
+
if (!value) return null;
|
|
56
|
+
const match = /^(\d{8})\/(\d{8})$/.exec(value);
|
|
57
|
+
if (!match) return null;
|
|
58
|
+
const [, start, end] = match;
|
|
59
|
+
|
|
60
|
+
// Basic validation to ensure chronological order.
|
|
61
|
+
if (start > end) return null;
|
|
62
|
+
|
|
63
|
+
return `${start}/${end}`;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const datesFromQuery = parseDatesRange(searchParams.get("dates"));
|
|
67
|
+
if (datesFromQuery) {
|
|
68
|
+
calendarParams.set("dates", datesFromQuery);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const defaultMode = "WEEK";
|
|
72
|
+
const allowedModes = new Set(["MONTH", "WEEK", "AGENDA"]);
|
|
73
|
+
const requestedMode = searchParams.get("mode");
|
|
74
|
+
if (requestedMode) {
|
|
75
|
+
const normalizedMode = requestedMode.toUpperCase();
|
|
76
|
+
if (allowedModes.has(normalizedMode)) {
|
|
77
|
+
calendarParams.set("mode", normalizedMode);
|
|
78
|
+
} else {
|
|
79
|
+
calendarParams.set("mode", defaultMode);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
calendars.forEach(calendar => {
|
|
84
|
+
calendarParams.append("src", calendar);
|
|
85
|
+
calendarParams.append("color", defaultColor);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
document.getElementById("calendarFrame").src = calendarBaseURL + calendarParams.toString();
|
|
89
|
+
|
|
90
|
+
window.onload = () => document.body.removeAttribute('unresolved');
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
</body>
|
|
94
|
+
|
|
95
|
+
</html>
|
|
96
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dytsou/calendar-build",
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Build script for calendar HTML from template and environment variables",
|
|
5
|
+
"main": "build.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"calendar-build": "build.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"build.js",
|
|
11
|
+
"index.html.template",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "node build.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"calendar",
|
|
19
|
+
"build",
|
|
20
|
+
"template"
|
|
21
|
+
],
|
|
22
|
+
"author": "dytsou",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/dytsou/cal.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/dytsou/cal/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/dytsou/cal#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=12.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|