@programinglive/commiter 1.2.12 → 1.2.17
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/.github/ISSUE_TEMPLATE/bug_report.md +28 -28
- package/.github/ISSUE_TEMPLATE/config.yml +5 -5
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/PULL_REQUEST_TEMPLATE.md +24 -24
- package/.github/workflows/publish.yml +8 -5
- package/CHANGELOG.md +275 -235
- package/CODE_OF_CONDUCT.md +36 -36
- package/LICENSE +21 -21
- package/PUBLISH.md +142 -142
- package/README.md +218 -217
- package/SECURITY.md +30 -30
- package/commitlint.config.cjs +4 -4
- package/docs/CREATE_RELEASES.md +103 -103
- package/{PRD.md → docs/PRD.md} +96 -96
- package/docs/QUICK_RELEASE_GUIDE.md +101 -101
- package/docs/release-notes/RELEASE_NOTES.md +226 -185
- package/index.js +199 -199
- package/netlify.toml +2 -2
- package/package.json +96 -96
- package/scripts/create-releases.js +219 -219
- package/scripts/release.cjs +285 -258
- package/scripts/update-release-notes.cjs +182 -182
- package/web/README.md +79 -79
- package/web/css/style.css +963 -963
- package/web/favicon.svg +10 -10
- package/web/index.html +510 -510
- package/web/js/script.js +256 -256
- package/web/og-image.svg +24 -24
- package/.netlify/netlify.toml +0 -25
- package/.netlify/state.json +0 -3
|
@@ -1,182 +1,182 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
|
|
6
|
-
function updateReleaseNotes({
|
|
7
|
-
rootDir = process.cwd(),
|
|
8
|
-
releaseNotesRelativePath = path.join('docs', 'release-notes', 'RELEASE_NOTES.md'),
|
|
9
|
-
changelogRelativePath = 'CHANGELOG.md',
|
|
10
|
-
packageJsonRelativePath = 'package.json',
|
|
11
|
-
now = () => new Date()
|
|
12
|
-
} = {}) {
|
|
13
|
-
const releaseNotesPath = path.join(rootDir, releaseNotesRelativePath);
|
|
14
|
-
if (!fs.existsSync(releaseNotesPath)) {
|
|
15
|
-
console.log(`ℹ️ Release notes file not found at ${releaseNotesPath}; skipping update.`);
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const packageJsonPath = path.join(rootDir, packageJsonRelativePath);
|
|
20
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
21
|
-
console.log(`ℹ️ package.json not found at ${packageJsonPath}; skipping release notes update.`);
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const changelogPath = path.join(rootDir, changelogRelativePath);
|
|
26
|
-
if (!fs.existsSync(changelogPath)) {
|
|
27
|
-
console.log(`ℹ️ CHANGELOG not found at ${changelogPath}; skipping release notes update.`);
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
32
|
-
const version = packageJson.version;
|
|
33
|
-
if (!version) {
|
|
34
|
-
console.log('ℹ️ package.json version is missing; skipping release notes update.');
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const releaseNotesContent = fs.readFileSync(releaseNotesPath, 'utf8');
|
|
39
|
-
if (releaseNotesContent.includes(`| ${version} `) || releaseNotesContent.includes(`## ${version}`)) {
|
|
40
|
-
console.log(`ℹ️ Release notes already contain version ${version}; skipping.`);
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const changelogContent = fs.readFileSync(changelogPath, 'utf8');
|
|
45
|
-
const changelogInfo = extractChangelogInfo({ changelogContent, version });
|
|
46
|
-
|
|
47
|
-
const releaseDate = changelogInfo.date || formatDate(now());
|
|
48
|
-
const highlight = changelogInfo.highlight || changelogInfo.heading || 'See CHANGELOG for details.';
|
|
49
|
-
const sectionHeading = changelogInfo.heading || '';
|
|
50
|
-
const detailBullets = Array.isArray(changelogInfo.bullets) && changelogInfo.bullets.length > 0
|
|
51
|
-
? changelogInfo.bullets
|
|
52
|
-
: [highlight];
|
|
53
|
-
|
|
54
|
-
const updatedContent = insertReleaseNotesEntry({
|
|
55
|
-
content: releaseNotesContent,
|
|
56
|
-
version,
|
|
57
|
-
releaseDate,
|
|
58
|
-
highlight,
|
|
59
|
-
sectionHeading,
|
|
60
|
-
detailBullets
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
fs.writeFileSync(releaseNotesPath, updatedContent);
|
|
64
|
-
console.log(`✅ Added release notes entry for version ${version}.`);
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function insertReleaseNotesEntry({ content, version, releaseDate, highlight, sectionHeading, detailBullets }) {
|
|
69
|
-
const lines = content.split('\n');
|
|
70
|
-
const headerSeparatorIndex = lines.findIndex((line) => line.trim().startsWith('|---------'));
|
|
71
|
-
if (headerSeparatorIndex === -1) {
|
|
72
|
-
throw new Error('Unable to locate release notes table header.');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const newRow = `| ${version} | ${releaseDate} | ${escapePipes(highlight)} |`;
|
|
76
|
-
lines.splice(headerSeparatorIndex + 1, 0, newRow);
|
|
77
|
-
|
|
78
|
-
const sectionLines = [];
|
|
79
|
-
sectionLines.push('');
|
|
80
|
-
const trimmedHeading = typeof sectionHeading === 'string' ? sectionHeading.trim() : '';
|
|
81
|
-
const headingSuffix = trimmedHeading ? ` – ${trimmedHeading}` : '';
|
|
82
|
-
sectionLines.push(`## ${version}${headingSuffix}`);
|
|
83
|
-
sectionLines.push('');
|
|
84
|
-
sectionLines.push(`Released on **${releaseDate}**.`);
|
|
85
|
-
sectionLines.push('');
|
|
86
|
-
for (const bullet of detailBullets) {
|
|
87
|
-
sectionLines.push(`- ${bullet}`);
|
|
88
|
-
}
|
|
89
|
-
sectionLines.push('');
|
|
90
|
-
|
|
91
|
-
const firstSectionIndex = lines.findIndex((line, idx) => idx > headerSeparatorIndex && line.startsWith('## '));
|
|
92
|
-
if (firstSectionIndex === -1) {
|
|
93
|
-
lines.push(...sectionLines);
|
|
94
|
-
} else {
|
|
95
|
-
lines.splice(firstSectionIndex, 0, ...sectionLines);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return lines.join('\n');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function extractChangelogInfo({ changelogContent, version }) {
|
|
102
|
-
const versionHeadingRegex = new RegExp(`^### \\[${escapeRegExp(version)}\\][^\n]*`, 'm');
|
|
103
|
-
const match = changelogContent.match(versionHeadingRegex);
|
|
104
|
-
if (!match) {
|
|
105
|
-
return {};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const headingIndex = match.index;
|
|
109
|
-
const rest = changelogContent.slice(headingIndex + match[0].length);
|
|
110
|
-
const nextVersionRegex = /^### \[[^\n]*\]/m;
|
|
111
|
-
const nextVersionMatch = nextVersionRegex.exec(rest);
|
|
112
|
-
const section = nextVersionMatch ? rest.slice(0, nextVersionMatch.index) : rest;
|
|
113
|
-
|
|
114
|
-
const dateMatch = match[0].match(/\((\d{4}-\d{2}-\d{2})\)/);
|
|
115
|
-
const date = dateMatch ? dateMatch[1] : undefined;
|
|
116
|
-
|
|
117
|
-
const categoryRegex = /^###\s+([^\n]+)$/m;
|
|
118
|
-
const categoryMatch = section.match(categoryRegex);
|
|
119
|
-
let heading;
|
|
120
|
-
if (categoryMatch) {
|
|
121
|
-
heading = sanitizeText(categoryMatch[1]);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const bullets = [];
|
|
125
|
-
const bulletRegex = /^\*\s+([^\n]+)$/gm;
|
|
126
|
-
let bulletMatch;
|
|
127
|
-
while ((bulletMatch = bulletRegex.exec(section)) !== null) {
|
|
128
|
-
const sanitized = sanitizeText(bulletMatch[1]);
|
|
129
|
-
if (!bullets.includes(sanitized)) {
|
|
130
|
-
bullets.push(sanitized);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const highlight = bullets.length > 0 ? bullets[0] : undefined;
|
|
135
|
-
|
|
136
|
-
return {
|
|
137
|
-
date,
|
|
138
|
-
highlight,
|
|
139
|
-
heading,
|
|
140
|
-
bullets
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function sanitizeText(text) {
|
|
145
|
-
return text
|
|
146
|
-
.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1')
|
|
147
|
-
.replace(/\s+/g, ' ')
|
|
148
|
-
.trim();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function escapeRegExp(string) {
|
|
152
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function escapePipes(text) {
|
|
156
|
-
return text.replace(/\|/g, '\\|');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function formatDate(date) {
|
|
160
|
-
const year = date.getFullYear();
|
|
161
|
-
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
162
|
-
const day = String(date.getDate()).padStart(2, '0');
|
|
163
|
-
return `${year}-${month}-${day}`;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
module.exports = {
|
|
167
|
-
updateReleaseNotes,
|
|
168
|
-
insertReleaseNotesEntry,
|
|
169
|
-
extractChangelogInfo,
|
|
170
|
-
sanitizeText,
|
|
171
|
-
escapePipes,
|
|
172
|
-
formatDate
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
if (require.main === module) {
|
|
176
|
-
try {
|
|
177
|
-
updateReleaseNotes();
|
|
178
|
-
} catch (error) {
|
|
179
|
-
console.error(`❌ Failed to update release notes: ${error.message}`);
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function updateReleaseNotes({
|
|
7
|
+
rootDir = process.cwd(),
|
|
8
|
+
releaseNotesRelativePath = path.join('docs', 'release-notes', 'RELEASE_NOTES.md'),
|
|
9
|
+
changelogRelativePath = 'CHANGELOG.md',
|
|
10
|
+
packageJsonRelativePath = 'package.json',
|
|
11
|
+
now = () => new Date()
|
|
12
|
+
} = {}) {
|
|
13
|
+
const releaseNotesPath = path.join(rootDir, releaseNotesRelativePath);
|
|
14
|
+
if (!fs.existsSync(releaseNotesPath)) {
|
|
15
|
+
console.log(`ℹ️ Release notes file not found at ${releaseNotesPath}; skipping update.`);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const packageJsonPath = path.join(rootDir, packageJsonRelativePath);
|
|
20
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
21
|
+
console.log(`ℹ️ package.json not found at ${packageJsonPath}; skipping release notes update.`);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const changelogPath = path.join(rootDir, changelogRelativePath);
|
|
26
|
+
if (!fs.existsSync(changelogPath)) {
|
|
27
|
+
console.log(`ℹ️ CHANGELOG not found at ${changelogPath}; skipping release notes update.`);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
32
|
+
const version = packageJson.version;
|
|
33
|
+
if (!version) {
|
|
34
|
+
console.log('ℹ️ package.json version is missing; skipping release notes update.');
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const releaseNotesContent = fs.readFileSync(releaseNotesPath, 'utf8');
|
|
39
|
+
if (releaseNotesContent.includes(`| ${version} `) || releaseNotesContent.includes(`## ${version}`)) {
|
|
40
|
+
console.log(`ℹ️ Release notes already contain version ${version}; skipping.`);
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const changelogContent = fs.readFileSync(changelogPath, 'utf8');
|
|
45
|
+
const changelogInfo = extractChangelogInfo({ changelogContent, version });
|
|
46
|
+
|
|
47
|
+
const releaseDate = changelogInfo.date || formatDate(now());
|
|
48
|
+
const highlight = changelogInfo.highlight || changelogInfo.heading || 'See CHANGELOG for details.';
|
|
49
|
+
const sectionHeading = changelogInfo.heading || '';
|
|
50
|
+
const detailBullets = Array.isArray(changelogInfo.bullets) && changelogInfo.bullets.length > 0
|
|
51
|
+
? changelogInfo.bullets
|
|
52
|
+
: [highlight];
|
|
53
|
+
|
|
54
|
+
const updatedContent = insertReleaseNotesEntry({
|
|
55
|
+
content: releaseNotesContent,
|
|
56
|
+
version,
|
|
57
|
+
releaseDate,
|
|
58
|
+
highlight,
|
|
59
|
+
sectionHeading,
|
|
60
|
+
detailBullets
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
fs.writeFileSync(releaseNotesPath, updatedContent);
|
|
64
|
+
console.log(`✅ Added release notes entry for version ${version}.`);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function insertReleaseNotesEntry({ content, version, releaseDate, highlight, sectionHeading, detailBullets }) {
|
|
69
|
+
const lines = content.split('\n');
|
|
70
|
+
const headerSeparatorIndex = lines.findIndex((line) => line.trim().startsWith('|---------'));
|
|
71
|
+
if (headerSeparatorIndex === -1) {
|
|
72
|
+
throw new Error('Unable to locate release notes table header.');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const newRow = `| ${version} | ${releaseDate} | ${escapePipes(highlight)} |`;
|
|
76
|
+
lines.splice(headerSeparatorIndex + 1, 0, newRow);
|
|
77
|
+
|
|
78
|
+
const sectionLines = [];
|
|
79
|
+
sectionLines.push('');
|
|
80
|
+
const trimmedHeading = typeof sectionHeading === 'string' ? sectionHeading.trim() : '';
|
|
81
|
+
const headingSuffix = trimmedHeading ? ` – ${trimmedHeading}` : '';
|
|
82
|
+
sectionLines.push(`## ${version}${headingSuffix}`);
|
|
83
|
+
sectionLines.push('');
|
|
84
|
+
sectionLines.push(`Released on **${releaseDate}**.`);
|
|
85
|
+
sectionLines.push('');
|
|
86
|
+
for (const bullet of detailBullets) {
|
|
87
|
+
sectionLines.push(`- ${bullet}`);
|
|
88
|
+
}
|
|
89
|
+
sectionLines.push('');
|
|
90
|
+
|
|
91
|
+
const firstSectionIndex = lines.findIndex((line, idx) => idx > headerSeparatorIndex && line.startsWith('## '));
|
|
92
|
+
if (firstSectionIndex === -1) {
|
|
93
|
+
lines.push(...sectionLines);
|
|
94
|
+
} else {
|
|
95
|
+
lines.splice(firstSectionIndex, 0, ...sectionLines);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return lines.join('\n');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function extractChangelogInfo({ changelogContent, version }) {
|
|
102
|
+
const versionHeadingRegex = new RegExp(`^### \\[${escapeRegExp(version)}\\][^\n]*`, 'm');
|
|
103
|
+
const match = changelogContent.match(versionHeadingRegex);
|
|
104
|
+
if (!match) {
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const headingIndex = match.index;
|
|
109
|
+
const rest = changelogContent.slice(headingIndex + match[0].length);
|
|
110
|
+
const nextVersionRegex = /^### \[[^\n]*\]/m;
|
|
111
|
+
const nextVersionMatch = nextVersionRegex.exec(rest);
|
|
112
|
+
const section = nextVersionMatch ? rest.slice(0, nextVersionMatch.index) : rest;
|
|
113
|
+
|
|
114
|
+
const dateMatch = match[0].match(/\((\d{4}-\d{2}-\d{2})\)/);
|
|
115
|
+
const date = dateMatch ? dateMatch[1] : undefined;
|
|
116
|
+
|
|
117
|
+
const categoryRegex = /^###\s+([^\n]+)$/m;
|
|
118
|
+
const categoryMatch = section.match(categoryRegex);
|
|
119
|
+
let heading;
|
|
120
|
+
if (categoryMatch) {
|
|
121
|
+
heading = sanitizeText(categoryMatch[1]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const bullets = [];
|
|
125
|
+
const bulletRegex = /^\*\s+([^\n]+)$/gm;
|
|
126
|
+
let bulletMatch;
|
|
127
|
+
while ((bulletMatch = bulletRegex.exec(section)) !== null) {
|
|
128
|
+
const sanitized = sanitizeText(bulletMatch[1]);
|
|
129
|
+
if (!bullets.includes(sanitized)) {
|
|
130
|
+
bullets.push(sanitized);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const highlight = bullets.length > 0 ? bullets[0] : undefined;
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
date,
|
|
138
|
+
highlight,
|
|
139
|
+
heading,
|
|
140
|
+
bullets
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function sanitizeText(text) {
|
|
145
|
+
return text
|
|
146
|
+
.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1')
|
|
147
|
+
.replace(/\s+/g, ' ')
|
|
148
|
+
.trim();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function escapeRegExp(string) {
|
|
152
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function escapePipes(text) {
|
|
156
|
+
return text.replace(/\|/g, '\\|');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function formatDate(date) {
|
|
160
|
+
const year = date.getFullYear();
|
|
161
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
162
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
163
|
+
return `${year}-${month}-${day}`;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = {
|
|
167
|
+
updateReleaseNotes,
|
|
168
|
+
insertReleaseNotesEntry,
|
|
169
|
+
extractChangelogInfo,
|
|
170
|
+
sanitizeText,
|
|
171
|
+
escapePipes,
|
|
172
|
+
formatDate
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
if (require.main === module) {
|
|
176
|
+
try {
|
|
177
|
+
updateReleaseNotes();
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error(`❌ Failed to update release notes: ${error.message}`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
package/web/README.md
CHANGED
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
# Commiter Website
|
|
2
|
-
|
|
3
|
-
This is the static website for the Commiter project. It can be deployed to any web server or hosting platform.
|
|
4
|
-
|
|
5
|
-
## 📁 Structure
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
web/
|
|
9
|
-
├── index.html # Main landing page
|
|
10
|
-
├── css/
|
|
11
|
-
│ └── style.css # Styles with modern dark theme
|
|
12
|
-
├── js/
|
|
13
|
-
│ └── script.js # Interactive features
|
|
14
|
-
└── README.md # This file
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## 🚀 Deployment Options
|
|
18
|
-
|
|
19
|
-
### Option 1: Plesk / cPanel
|
|
20
|
-
1. Compress the `web` folder contents into a ZIP file
|
|
21
|
-
2. Upload to your Plesk/cPanel file manager
|
|
22
|
-
3. Extract in your public_html or desired directory
|
|
23
|
-
4. Access via your domain
|
|
24
|
-
|
|
25
|
-
### Option 2: Static Hosting (Netlify, Vercel, GitHub Pages)
|
|
26
|
-
1. Push the `web` folder to a Git repository
|
|
27
|
-
2. Connect to your hosting platform
|
|
28
|
-
3. Set the build directory to `web`
|
|
29
|
-
4. Deploy
|
|
30
|
-
|
|
31
|
-
### Option 3: Simple HTTP Server (Testing)
|
|
32
|
-
```bash
|
|
33
|
-
# Navigate to the web directory
|
|
34
|
-
cd web
|
|
35
|
-
|
|
36
|
-
# Python 3
|
|
37
|
-
python -m http.server 8000
|
|
38
|
-
|
|
39
|
-
# Node.js (if you have http-server installed)
|
|
40
|
-
npx http-server -p 8000
|
|
41
|
-
|
|
42
|
-
# PHP
|
|
43
|
-
php -S localhost:8000
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Then open http://localhost:8000 in your browser.
|
|
47
|
-
|
|
48
|
-
## 🎨 Features
|
|
49
|
-
|
|
50
|
-
- **Modern Design**: Dark theme with glassmorphism effects
|
|
51
|
-
- **Fully Responsive**: Works on desktop, tablet, and mobile
|
|
52
|
-
- **Smooth Animations**: Scroll animations and transitions
|
|
53
|
-
- **Interactive Elements**: Copy-to-clipboard, smooth scrolling
|
|
54
|
-
- **SEO Optimized**: Meta tags and semantic HTML
|
|
55
|
-
- **Fast Loading**: Optimized CSS and JavaScript
|
|
56
|
-
|
|
57
|
-
## 🛠️ Customization
|
|
58
|
-
|
|
59
|
-
### Colors
|
|
60
|
-
Edit CSS variables in `css/style.css`:
|
|
61
|
-
```css
|
|
62
|
-
:root {
|
|
63
|
-
--primary: #6366f1;
|
|
64
|
-
--secondary: #8b5cf6;
|
|
65
|
-
--accent: #ec4899;
|
|
66
|
-
/* ... more variables */
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Content
|
|
71
|
-
Edit `index.html` to update:
|
|
72
|
-
- Version numbers
|
|
73
|
-
- Release information
|
|
74
|
-
- Links and URLs
|
|
75
|
-
- Text content
|
|
76
|
-
|
|
77
|
-
## 📝 License
|
|
78
|
-
|
|
79
|
-
This website is part of the Commiter project and is released under the MIT License.
|
|
1
|
+
# Commiter Website
|
|
2
|
+
|
|
3
|
+
This is the static website for the Commiter project. It can be deployed to any web server or hosting platform.
|
|
4
|
+
|
|
5
|
+
## 📁 Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
web/
|
|
9
|
+
├── index.html # Main landing page
|
|
10
|
+
├── css/
|
|
11
|
+
│ └── style.css # Styles with modern dark theme
|
|
12
|
+
├── js/
|
|
13
|
+
│ └── script.js # Interactive features
|
|
14
|
+
└── README.md # This file
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 🚀 Deployment Options
|
|
18
|
+
|
|
19
|
+
### Option 1: Plesk / cPanel
|
|
20
|
+
1. Compress the `web` folder contents into a ZIP file
|
|
21
|
+
2. Upload to your Plesk/cPanel file manager
|
|
22
|
+
3. Extract in your public_html or desired directory
|
|
23
|
+
4. Access via your domain
|
|
24
|
+
|
|
25
|
+
### Option 2: Static Hosting (Netlify, Vercel, GitHub Pages)
|
|
26
|
+
1. Push the `web` folder to a Git repository
|
|
27
|
+
2. Connect to your hosting platform
|
|
28
|
+
3. Set the build directory to `web`
|
|
29
|
+
4. Deploy
|
|
30
|
+
|
|
31
|
+
### Option 3: Simple HTTP Server (Testing)
|
|
32
|
+
```bash
|
|
33
|
+
# Navigate to the web directory
|
|
34
|
+
cd web
|
|
35
|
+
|
|
36
|
+
# Python 3
|
|
37
|
+
python -m http.server 8000
|
|
38
|
+
|
|
39
|
+
# Node.js (if you have http-server installed)
|
|
40
|
+
npx http-server -p 8000
|
|
41
|
+
|
|
42
|
+
# PHP
|
|
43
|
+
php -S localhost:8000
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then open http://localhost:8000 in your browser.
|
|
47
|
+
|
|
48
|
+
## 🎨 Features
|
|
49
|
+
|
|
50
|
+
- **Modern Design**: Dark theme with glassmorphism effects
|
|
51
|
+
- **Fully Responsive**: Works on desktop, tablet, and mobile
|
|
52
|
+
- **Smooth Animations**: Scroll animations and transitions
|
|
53
|
+
- **Interactive Elements**: Copy-to-clipboard, smooth scrolling
|
|
54
|
+
- **SEO Optimized**: Meta tags and semantic HTML
|
|
55
|
+
- **Fast Loading**: Optimized CSS and JavaScript
|
|
56
|
+
|
|
57
|
+
## 🛠️ Customization
|
|
58
|
+
|
|
59
|
+
### Colors
|
|
60
|
+
Edit CSS variables in `css/style.css`:
|
|
61
|
+
```css
|
|
62
|
+
:root {
|
|
63
|
+
--primary: #6366f1;
|
|
64
|
+
--secondary: #8b5cf6;
|
|
65
|
+
--accent: #ec4899;
|
|
66
|
+
/* ... more variables */
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Content
|
|
71
|
+
Edit `index.html` to update:
|
|
72
|
+
- Version numbers
|
|
73
|
+
- Release information
|
|
74
|
+
- Links and URLs
|
|
75
|
+
- Text content
|
|
76
|
+
|
|
77
|
+
## 📝 License
|
|
78
|
+
|
|
79
|
+
This website is part of the Commiter project and is released under the MIT License.
|