create-geocities-app 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.
- checksums.yaml +7 -0
- data/README.md +309 -0
- data/bin/create-geocities-app +133 -0
- data/lib/create_geocities_app/generator.rb +87 -0
- data/lib/create_geocities_app/themes.rb +53 -0
- data/lib/create_geocities_app/version.rb +3 -0
- data/lib/create_geocities_app.rb +3 -0
- data/templates/about.html +157 -0
- data/templates/css/style.css +729 -0
- data/templates/gallery.html +211 -0
- data/templates/guestbook.html +173 -0
- data/templates/index.html +193 -0
- data/templates/js/main.js +382 -0
- data/templates/links.html +198 -0
- metadata +86 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 56c68d88c3f8127a342256c88d5cd258fc0d83fa6f366f628e84bb1f17c27bde
|
|
4
|
+
data.tar.gz: c8e51993915440bcbe9bf743dc4a834f7b42d97ad8cbfd68721426154eea7f19
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e0606c5b82d1577f9e22f135004c4336bafc1c267e249c8c9f743e61aaadf2adf4fe295682f07500c4191e16fb69ec9fb272fbae6e0147d11027940f02730ff0
|
|
7
|
+
data.tar.gz: a0590f600c72197163996b9328234e4b1aeb1ef2806c015ddf3412d263f8e10b0c47655974ae6d83e99ca44930c663f3d261443d7cec63c2f1f50fe044cbce6f
|
data/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# 🌐 geocities-boilerplate
|
|
2
|
+
|
|
3
|
+
> Scaffold a complete 1990s Geocities-themed static website in seconds.
|
|
4
|
+
|
|
5
|
+
[](https://rubygems.org/gems/create-geocities-app)
|
|
6
|
+
[](https://rubygems.org/gems/create-geocities-app)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://sugardaddyapp.github.io/geocities-boilerplate/)
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
██████╗ ███████╗ ██████╗ ██████╗██╗████████╗██╗███████╗███████╗
|
|
12
|
+
██╔════╝ ██╔════╝██╔═══██╗██╔════╝██║╚══██╔══╝██║██╔════╝██╔════╝
|
|
13
|
+
██║ ███╗█████╗ ██║ ██║██║ ██║ ██║ ██║█████╗ ███████╗
|
|
14
|
+
██║ ██║██╔══╝ ██║ ██║██║ ██║ ██║ ██║██╔══╝ ╚════██║
|
|
15
|
+
╚██████╔╝███████╗╚██████╔╝╚██████╗██║ ██║ ██║███████╗███████║
|
|
16
|
+
╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝
|
|
17
|
+
|
|
18
|
+
geocities-boilerplate ✨ Welcome to 1996 ✨
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**[🌐 View Live Demo](https://sugardaddyapp.github.io/geocities-boilerplate/)**
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## What is this?
|
|
26
|
+
|
|
27
|
+
`geocities-boilerplate` is a CLI tool that generates a fully self-contained, retro 1990s Geocities-style personal website. Think neon colors, blinking text, animated star trails, marquee banners, visitor counters, and guestbooks — all of it, generated instantly with a single command.
|
|
28
|
+
|
|
29
|
+
The generated site is **pure static HTML, CSS, and vanilla JavaScript**. No build tools, no frameworks, no dependencies. Just open `index.html` in any browser and relive the golden age of the web.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
gem install create-geocities-app
|
|
37
|
+
create-geocities-app my-site
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then open `my-site/index.html` in your browser. That's it!
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Every Way to Run It
|
|
45
|
+
|
|
46
|
+
Pick your language or runtime — all produce the same site.
|
|
47
|
+
|
|
48
|
+
### Ruby / RubyGems
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
gem install create-geocities-app
|
|
52
|
+
create-geocities-app my-site
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Node.js / npm
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# one-shot, no install
|
|
59
|
+
npx create-geocities-app my-site
|
|
60
|
+
|
|
61
|
+
# or install globally
|
|
62
|
+
npm install -g create-geocities-app
|
|
63
|
+
create-geocities-app my-site
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Python / PyPI
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# one-shot with pipx (recommended)
|
|
70
|
+
pipx run create-geocities-app my-site
|
|
71
|
+
|
|
72
|
+
# or install permanently
|
|
73
|
+
pip install create-geocities-app
|
|
74
|
+
create-geocities-app my-site
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Rust / Cargo
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cargo install create-geocities-app
|
|
81
|
+
create-geocities-app my-site
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### PHP / Composer
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# global install
|
|
88
|
+
composer global require geocities-app/create-geocities-app
|
|
89
|
+
create-geocities-app my-site
|
|
90
|
+
|
|
91
|
+
# or as a project scaffold
|
|
92
|
+
composer create-project geocities-app/create-geocities-app my-site
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Deno / JSR
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# run without installing
|
|
99
|
+
deno run --allow-read --allow-write jsr:@geocities/create-app my-site
|
|
100
|
+
|
|
101
|
+
# or compile to a native binary first
|
|
102
|
+
deno compile --allow-read --allow-write --output create-geocities-app jsr:@geocities/create-app
|
|
103
|
+
./create-geocities-app my-site
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Go
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# run without installing
|
|
110
|
+
go run github.com/sugardaddyapp/geocities-boilerplate/go@latest my-site
|
|
111
|
+
|
|
112
|
+
# or install the binary
|
|
113
|
+
go install github.com/sugardaddyapp/geocities-boilerplate/go@latest
|
|
114
|
+
create-geocities-app my-site
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
All variants accept the same flags:
|
|
118
|
+
|
|
119
|
+
| Flag | Meaning |
|
|
120
|
+
|------|---------|
|
|
121
|
+
| `my-site` | Output directory name (default: `my-geocities-site`) |
|
|
122
|
+
| `-y` / `--yes` | Skip all prompts and use defaults |
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Demo
|
|
127
|
+
|
|
128
|
+
**Live demo:** [https://sugardaddyapp.github.io/geocities-boilerplate/](https://sugardaddyapp.github.io/geocities-boilerplate/)
|
|
129
|
+
|
|
130
|
+
The demo is generated with all options enabled (neon theme, sparkle cursor, falling stars, all 5 pages). It is automatically rebuilt and deployed to GitHub Pages on every push to `main`.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Interactive Setup
|
|
135
|
+
|
|
136
|
+
When you run `create-geocities-app my-site`, you'll be walked through a series of prompts:
|
|
137
|
+
|
|
138
|
+
| # | Prompt | Type | Description |
|
|
139
|
+
|---|--------|------|-------------|
|
|
140
|
+
| 1 | **Site name** | text | Your homepage title, e.g. `CoolDude's Homepage` |
|
|
141
|
+
| 2 | **Your name** | text | Displayed in headers, footers, and contact sections |
|
|
142
|
+
| 3 | **Color theme** | select | Choose from 5 retro color palettes (see below) |
|
|
143
|
+
| 4 | **Extra pages** | multi | About, Gallery, Guestbook, Cool Links |
|
|
144
|
+
| 5 | **Cursor effect** | select | Sparkle, Star Trail, Comet, Rainbow, or None |
|
|
145
|
+
| 6 | **Falling effect** | select | Stars, Snow, or None |
|
|
146
|
+
| 7 | **Welcome alert** | yes/no | Show a `alert()` greeting when the page loads |
|
|
147
|
+
| 8 | **Auto-play music** | yes/no | Play a Web Audio API 8-bit jingle on load |
|
|
148
|
+
| 9 | **Fake high count** | yes/no | Start visitor counter at ~10,000 (looks popular!) |
|
|
149
|
+
|
|
150
|
+
### Skip prompts (use all defaults)
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
create-geocities-app my-site --yes
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Generated Output
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
my-site/
|
|
162
|
+
├── index.html ← Homepage
|
|
163
|
+
├── about.html ← About Me (if selected)
|
|
164
|
+
├── gallery.html ← Photo Gallery with lightbox (if selected)
|
|
165
|
+
├── guestbook.html ← Guestbook (if selected)
|
|
166
|
+
├── links.html ← Cool Links (if selected)
|
|
167
|
+
├── css/
|
|
168
|
+
│ └── style.css ← Full retro stylesheet (theme-specific)
|
|
169
|
+
└── js/
|
|
170
|
+
└── main.js ← All JS effects (counter, cursor, music, etc.)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Zero runtime dependencies** in the generated output. Every file is self-contained and works offline.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Color Themes
|
|
178
|
+
|
|
179
|
+
Choose a theme during setup. Each theme controls background, text, link, and accent colors throughout the entire site.
|
|
180
|
+
|
|
181
|
+
| Theme | Background | Primary Text | Headings | Links | Feel |
|
|
182
|
+
|-------|-----------|--------------|----------|-------|------|
|
|
183
|
+
| `neon` | `#000000` | `#00FF00` | `#FFFF00` | `#FF00FF` | Hacker/Matrix vibes |
|
|
184
|
+
| `space` | `#000033` | `#CCCCFF` | `#FFDD00` | `#00FFFF` | Deep space explorer |
|
|
185
|
+
| `candy` | `#FF69B4` | `#FFFFFF` | `#FFFF00` | `#00FFFF` | Sweet and electric |
|
|
186
|
+
| `forest` | `#003300` | `#CCFFCC` | `#FFDD00` | `#99FF99` | Dark enchanted forest |
|
|
187
|
+
| `windows` | `#008080` | `#000000` | `#000080` | `#000080` | Classic Windows 95 |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Pages
|
|
192
|
+
|
|
193
|
+
### 🏠 index.html — Homepage
|
|
194
|
+
Every generated site includes a homepage with:
|
|
195
|
+
- **Marquee banner** — scrolling welcome text (CSS animation, no deprecated `<marquee>` tag)
|
|
196
|
+
- **Rainbow animated site title** — CSS `hue-rotate` animation cycles through all colors
|
|
197
|
+
- **Neon-pulsing headings** — `text-shadow` breathes in and out
|
|
198
|
+
- **"What's New" section** — with blinking NEW badges
|
|
199
|
+
- **Under Construction section** — animated yellow/black caution tape
|
|
200
|
+
- **Sidebar** — navigation, live clock, spinning globe, visitor counter, web ring
|
|
201
|
+
- **Web ring widget** — retro navigation to prev/home/next sites
|
|
202
|
+
- **Footer** — "Best viewed in Netscape Navigator" badge, copyright
|
|
203
|
+
|
|
204
|
+
### 👤 about.html — About Me
|
|
205
|
+
- **Fun Facts list** — blinking star bullet points
|
|
206
|
+
- **Interests grid** — styled badge chips for hobbies
|
|
207
|
+
- **Favorites table** — a retro-styled table of favorite things (music, movies, games, etc.)
|
|
208
|
+
- **Contact section** — email and guestbook links
|
|
209
|
+
|
|
210
|
+
### 🖼️ gallery.html — Photo Gallery
|
|
211
|
+
- **Photo of the Month** spotlight at the top
|
|
212
|
+
- **3-column image grid** — each item has thick beveled Windows-95-style borders
|
|
213
|
+
- **Captions** in Comic Sans below each image
|
|
214
|
+
- **Lightbox viewer** — click any photo to open it full-size in an overlay; press ESC or click outside to close
|
|
215
|
+
- Placeholder images pre-filled — replace with your own
|
|
216
|
+
|
|
217
|
+
### 📖 guestbook.html — Guestbook
|
|
218
|
+
- **Sign form** — fields for name, email, website, location, and message
|
|
219
|
+
- **Fake previous entries** — pre-populated with period-authentic guestbook posts (fully editable)
|
|
220
|
+
- **Client-side submit** — shows a thank-you alert and resets the form
|
|
221
|
+
- Note explaining how to add a real backend (Formspree, Netlify Forms, etc.)
|
|
222
|
+
|
|
223
|
+
### 🔗 links.html — Cool Links
|
|
224
|
+
- Links organized into categories: Friends, Games, Web & Tech, Art, News
|
|
225
|
+
- **Blinking animated bullets** before each link
|
|
226
|
+
- Description text below each link
|
|
227
|
+
- "Request Link Exchange" email button
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Effects Reference
|
|
232
|
+
|
|
233
|
+
### Cursor Effects
|
|
234
|
+
|
|
235
|
+
| Effect | What it does |
|
|
236
|
+
|--------|-------------|
|
|
237
|
+
| **Sparkle** ✨ | Random glitter glyphs (`✦`, `✧`, `★`, `·`) spawn at your cursor and float upward |
|
|
238
|
+
| **Star Trail** ★ | Yellow ★ characters follow the cursor and fade out with a scale-down animation |
|
|
239
|
+
| **Comet** ☄️ | An orange-to-white horizontal streak trails behind cursor movement |
|
|
240
|
+
| **Rainbow** 🌈 | Colored dots cycle through the full hue spectrum as you move the cursor |
|
|
241
|
+
| **None** | No cursor effect |
|
|
242
|
+
|
|
243
|
+
### Falling Background Effects
|
|
244
|
+
|
|
245
|
+
| Effect | What it does |
|
|
246
|
+
|--------|-------------|
|
|
247
|
+
| **Stars** ⭐ | 60 colored star characters (`★`) fall from top of screen with random sizes, speeds, and drift |
|
|
248
|
+
| **Snow** ❄️ | 40 white circular snowflakes drift downward with random horizontal drift |
|
|
249
|
+
| **None** | No falling effect |
|
|
250
|
+
|
|
251
|
+
### Other Effects
|
|
252
|
+
|
|
253
|
+
| Effect | Details |
|
|
254
|
+
|--------|---------|
|
|
255
|
+
| **Visitor counter** | Odometer-style LCD digit boxes, animates on load, persists via `localStorage` |
|
|
256
|
+
| **Live clock** | `HH:MM:SS` display in the sidebar, updated every second |
|
|
257
|
+
| **Marquee banner** | CSS `@keyframes` scroll animation — pauses on hover |
|
|
258
|
+
| **Blinking text** | CSS `@keyframes blink` — used on NEW badges, bullet points, and decorations |
|
|
259
|
+
| **Rainbow headings** | CSS `filter: hue-rotate()` animation cycles through all colors |
|
|
260
|
+
| **Neon glow pulse** | `text-shadow` breathes in/out on all major headings |
|
|
261
|
+
| **Spinning globe** | 🌍 emoji spins continuously via CSS `rotate` animation |
|
|
262
|
+
| **Under construction** | Yellow/black diagonal-stripe caution tape with a spinning 🚧 icon |
|
|
263
|
+
| **Page entry animation** | Content fades and slides up on load |
|
|
264
|
+
| **8-bit music jingle** | Square-wave melody via Web Audio API — plays on first interaction; toggle with the PLAY/STOP button |
|
|
265
|
+
| **Matrix rain** | Press **M** on any page to toggle a green Matrix-style canvas rain effect |
|
|
266
|
+
| **Custom scrollbar** | Themed scrollbar matching the color palette (Chrome/Edge/Safari) |
|
|
267
|
+
| **Gallery lightbox** | Click-to-expand image viewer with caption, close button, and ESC key support |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## GitHub Pages Setup (for your generated site)
|
|
272
|
+
|
|
273
|
+
To host your generated site on GitHub Pages:
|
|
274
|
+
|
|
275
|
+
1. Create a new GitHub repository
|
|
276
|
+
2. Copy the contents of your generated folder into it
|
|
277
|
+
3. Push to `main`
|
|
278
|
+
4. Go to **Settings → Pages → Source → Deploy from a branch → main → / (root)**
|
|
279
|
+
5. Your site is live at `https://<username>.github.io/<repo-name>/`
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Requirements
|
|
284
|
+
|
|
285
|
+
Ruby 2.7+
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
MIT © Jamey Baldwin
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Acknowledgements
|
|
296
|
+
|
|
297
|
+
- Inspired by the preserved [GeoCities archive](https://geocities.restorativland.org/) and [GifCities](https://gifcities.org/)
|
|
298
|
+
- Color palette ideas from the original GeoCities neighborhood aesthetics
|
|
299
|
+
- Built with ❤️ and an unhealthy amount of nostalgia for 1996
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
Also checkout my other projects:
|
|
304
|
+
[Best Sugar Daddy Apps](https://github.com/sugardaddyapp/bestsugardaddyapps/)
|
|
305
|
+
[Best Sugar Daddy Apps 2026](https://bestsugardaddyapps.com/)
|
|
306
|
+
[Best Sugar Daddy Apps NPM](https://www.npmjs.com/package/best-sugar-daddy-apps)
|
|
307
|
+
[Best Sugar Daddy Apps Socket](https://socket.dev/npm/package/best-sugar-daddy-apps)
|
|
308
|
+
|
|
309
|
+
*Best viewed in Netscape Navigator 4.0 at 800×600 resolution.*
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "../lib/create_geocities_app"
|
|
6
|
+
|
|
7
|
+
begin
|
|
8
|
+
require "tty-prompt"
|
|
9
|
+
require "pastel"
|
|
10
|
+
rescue LoadError
|
|
11
|
+
warn "Error: tty-prompt and pastel are required. Run: gem install tty-prompt pastel"
|
|
12
|
+
exit 1
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
BANNER = <<~BANNER
|
|
16
|
+
|
|
17
|
+
\e[33m ██████╗ ███████╗ ██████╗ ██████╗██╗████████╗██╗███████╗███████╗\e[0m
|
|
18
|
+
\e[33m ██╔════╝ ██╔════╝██╔═══██╗██╔════╝██║╚══██╔══╝██║██╔════╝██╔════╝\e[0m
|
|
19
|
+
\e[32m ██║ ███╗█████╗ ██║ ██║██║ ██║ ██║ ██║█████╗ ███████╗\e[0m
|
|
20
|
+
\e[32m ██║ ██║██╔══╝ ██║ ██║██║ ██║ ██║ ██║██╔══╝ ╚════██║\e[0m
|
|
21
|
+
\e[36m ╚██████╔╝███████╗╚██████╔╝╚██████╗██║ ██║ ██║███████╗███████║\e[0m
|
|
22
|
+
\e[36m ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝\e[0m
|
|
23
|
+
\e[35m create-geocities-app ✨ Welcome to 1996 ✨\e[0m
|
|
24
|
+
|
|
25
|
+
BANNER
|
|
26
|
+
|
|
27
|
+
DEFAULT_ANSWERS = {
|
|
28
|
+
site_name: "My Geocities Site",
|
|
29
|
+
author_name: "Webmaster",
|
|
30
|
+
theme: "neon",
|
|
31
|
+
pages: %w[about gallery guestbook links],
|
|
32
|
+
cursor_effect: "sparkle",
|
|
33
|
+
falling_effect: "stars",
|
|
34
|
+
welcome_alert: true,
|
|
35
|
+
play_music: true,
|
|
36
|
+
fake_high_count: true,
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
options = { yes: false }
|
|
40
|
+
output_name = nil
|
|
41
|
+
|
|
42
|
+
OptionParser.new do |opts|
|
|
43
|
+
opts.banner = "Usage: create-geocities-app [OUTPUT_DIR] [options]"
|
|
44
|
+
opts.on("-y", "--yes", "Skip prompts and use defaults") { options[:yes] = true }
|
|
45
|
+
end.parse!(ARGV)
|
|
46
|
+
|
|
47
|
+
output_name = ARGV.shift || "my-geocities-site"
|
|
48
|
+
output_dir = File.expand_path(output_name, Dir.pwd)
|
|
49
|
+
|
|
50
|
+
puts BANNER
|
|
51
|
+
puts "\e[36mCreating your site in: \e[1m#{output_dir}\e[0m\n\n"
|
|
52
|
+
|
|
53
|
+
answers = if options[:yes]
|
|
54
|
+
DEFAULT_ANSWERS
|
|
55
|
+
else
|
|
56
|
+
prompt = TTY::Prompt.new
|
|
57
|
+
|
|
58
|
+
site_name = prompt.ask("What is your site name?", default: "My Awesome Homepage") do |q|
|
|
59
|
+
q.validate(->(v) { v.strip.length > 0 }, "Site name cannot be empty")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
author_name = prompt.ask("What is your name (or handle)?", default: "Webmaster") do |q|
|
|
63
|
+
q.validate(->(v) { v.strip.length > 0 }, "Name cannot be empty")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
theme = prompt.select("Pick a color theme:") do |menu|
|
|
67
|
+
menu.choice "Neon (black bg, green + yellow + magenta)", "neon"
|
|
68
|
+
menu.choice "Space (dark blue, stars, gold + cyan)", "space"
|
|
69
|
+
menu.choice "Candy (hot pink bg, cyan + yellow)", "candy"
|
|
70
|
+
menu.choice "Forest (dark green, gold accents)", "forest"
|
|
71
|
+
menu.choice "Windows 95 (teal bg, grey panels)", "windows"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
pages = prompt.multi_select("Which extra pages do you want?") do |menu|
|
|
75
|
+
menu.default 1, 2, 3, 4
|
|
76
|
+
menu.choice "About Me", "about"
|
|
77
|
+
menu.choice "Gallery", "gallery"
|
|
78
|
+
menu.choice "Guestbook", "guestbook"
|
|
79
|
+
menu.choice "Cool Links", "links"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
cursor_effect = prompt.select("Pick a cursor effect:") do |menu|
|
|
83
|
+
menu.choice "Sparkle ✨ (glitter dots spawn at cursor)", "sparkle"
|
|
84
|
+
menu.choice "Star Trail ★ (stars follow and fade)", "startrail"
|
|
85
|
+
menu.choice "Comet ☄️ (colored streak trail)", "comet"
|
|
86
|
+
menu.choice "Rainbow 🌈 (hue-cycling dot trail)", "rainbow"
|
|
87
|
+
menu.choice "None (no cursor effect)", "none"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
falling_effect = prompt.select("Pick a falling background effect:") do |menu|
|
|
91
|
+
menu.choice "Stars ⭐ (white dots fall from top)", "stars"
|
|
92
|
+
menu.choice "Snow ❄️ (snowflakes drift down)", "snow"
|
|
93
|
+
menu.choice "None (no falling effect)", "none"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
welcome_alert = prompt.yes?("Show a welcome alert when the page loads?")
|
|
97
|
+
play_music = prompt.yes?("Auto-play a retro 8-bit music jingle on load?", default: false)
|
|
98
|
+
fake_high_count = prompt.yes?("Start visitor counter at a high number (looks popular!)?")
|
|
99
|
+
|
|
100
|
+
{
|
|
101
|
+
site_name: site_name,
|
|
102
|
+
author_name: author_name,
|
|
103
|
+
theme: theme,
|
|
104
|
+
pages: pages,
|
|
105
|
+
cursor_effect: cursor_effect,
|
|
106
|
+
falling_effect: falling_effect,
|
|
107
|
+
welcome_alert: welcome_alert,
|
|
108
|
+
play_music: play_music,
|
|
109
|
+
fake_high_count: fake_high_count,
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
puts "\e[33m\n⚙️ Generating files...\n\n\e[0m"
|
|
114
|
+
|
|
115
|
+
generated = CreateGeocitiesApp.generate(output_dir, answers)
|
|
116
|
+
|
|
117
|
+
puts "\e[32m✅ Done! Your Geocities site is ready.\n\e[0m"
|
|
118
|
+
puts "\e[37m📁 Files created:\e[0m"
|
|
119
|
+
generated.each { |f| puts "\e[36m └─ #{output_name}/#{f}\e[0m" }
|
|
120
|
+
puts "\e[36m └─ #{output_name}/css/style.css\e[0m"
|
|
121
|
+
puts "\e[36m └─ #{output_name}/js/main.js\e[0m"
|
|
122
|
+
|
|
123
|
+
puts <<~BOX
|
|
124
|
+
|
|
125
|
+
\e[33m╔══════════════════════════════════════════════╗
|
|
126
|
+
║ 🌐 Open #{output_name}/index.html in ║
|
|
127
|
+
║ your browser to see your site! ║
|
|
128
|
+
║ ║
|
|
129
|
+
║ Best viewed in Netscape Navigator 4.0 ║
|
|
130
|
+
║ at 800×600 resolution. 😉 ║
|
|
131
|
+
╚══════════════════════════════════════════════╝\e[0m
|
|
132
|
+
|
|
133
|
+
BOX
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require "fileutils"
|
|
2
|
+
require_relative "themes"
|
|
3
|
+
|
|
4
|
+
module CreateGeocitiesApp
|
|
5
|
+
ALL_PAGES = [
|
|
6
|
+
{ key: "index", label: "🏠 Home", file: "index.html" },
|
|
7
|
+
{ key: "about", label: "👤 About Me", file: "about.html" },
|
|
8
|
+
{ key: "gallery", label: "🖼️ Gallery", file: "gallery.html" },
|
|
9
|
+
{ key: "guestbook", label: "📖 Guestbook", file: "guestbook.html" },
|
|
10
|
+
{ key: "links", label: "🔗 Cool Links", file: "links.html" },
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
TEMPLATE_DIR = File.expand_path("../../../templates", __FILE__)
|
|
14
|
+
|
|
15
|
+
def self.interpolate(template, vars)
|
|
16
|
+
template.gsub(/\{\{(\w+)\}\}/) { vars[$1] || vars[$1.to_sym] || "{{#{$1}}}" }.to_s
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.build_nav_links(pages, current_page)
|
|
20
|
+
active = ["index"] + pages
|
|
21
|
+
ALL_PAGES.select { |p| active.include?(p[:key]) }.map do |p|
|
|
22
|
+
cls = p[:key] == current_page ? "nav-link nav-active" : "nav-link"
|
|
23
|
+
%(<a href="#{p[:file]}" class="#{cls}">#{p[:label]}</a>)
|
|
24
|
+
end.join("\n ")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.generate(output_dir, answers)
|
|
28
|
+
theme = get_theme(answers[:theme])
|
|
29
|
+
pages = answers[:pages] || []
|
|
30
|
+
|
|
31
|
+
FileUtils.mkdir_p(File.join(output_dir, "css"))
|
|
32
|
+
FileUtils.mkdir_p(File.join(output_dir, "js"))
|
|
33
|
+
|
|
34
|
+
base_vars = {
|
|
35
|
+
"SITE_NAME" => answers[:site_name],
|
|
36
|
+
"AUTHOR_NAME" => answers[:author_name],
|
|
37
|
+
"THEME_NAME" => theme[:name],
|
|
38
|
+
"BG" => theme[:bg],
|
|
39
|
+
"BG_PATTERN" => theme[:bg_pattern],
|
|
40
|
+
"BG_SIZE" => theme[:bg_size],
|
|
41
|
+
"TEXT_COLOR" => theme[:text_color],
|
|
42
|
+
"HEADING_COLOR" => theme[:heading_color],
|
|
43
|
+
"LINK_COLOR" => theme[:link_color],
|
|
44
|
+
"LINK_HOVER" => theme[:link_hover],
|
|
45
|
+
"ACCENT_COLOR" => theme[:accent_color],
|
|
46
|
+
"BORDER_LIGHT" => theme[:border_light],
|
|
47
|
+
"BORDER_DARK" => theme[:border_dark],
|
|
48
|
+
"PANEL_BG" => theme[:panel_bg],
|
|
49
|
+
"PANEL_BORDER" => theme[:panel_border],
|
|
50
|
+
"COUNTER_BG" => theme[:counter_bg],
|
|
51
|
+
"COUNTER_TEXT" => theme[:counter_text],
|
|
52
|
+
"TABLE_BORDER" => theme[:table_border],
|
|
53
|
+
"TABLE_HEADER_BG" => theme[:table_header_bg],
|
|
54
|
+
"GLOW_COLOR" => theme[:glow_color],
|
|
55
|
+
"NAV_ACTIVE_BG" => theme[:nav_active_bg],
|
|
56
|
+
"NAV_ACTIVE_TEXT" => theme[:nav_active_text],
|
|
57
|
+
"CURSOR_EFFECT" => answers[:cursor_effect] || "none",
|
|
58
|
+
"FALLING_EFFECT" => answers[:falling_effect] || "none",
|
|
59
|
+
"WELCOME_ALERT" => answers[:welcome_alert] ? "true" : "false",
|
|
60
|
+
"PLAY_MUSIC" => answers[:play_music] ? "true" : "false",
|
|
61
|
+
"FAKE_HIGH_COUNT" => answers[:fake_high_count] ? "true" : "false",
|
|
62
|
+
"YEAR" => Time.now.year.to_s,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
css_src = File.read(File.join(TEMPLATE_DIR, "css", "style.css"))
|
|
66
|
+
File.write(File.join(output_dir, "css", "style.css"), interpolate(css_src, base_vars))
|
|
67
|
+
|
|
68
|
+
js_src = File.read(File.join(TEMPLATE_DIR, "js", "main.js"))
|
|
69
|
+
File.write(File.join(output_dir, "js", "main.js"), interpolate(js_src, base_vars))
|
|
70
|
+
|
|
71
|
+
pages_to_generate = [{ key: "index", file: "index.html" }] +
|
|
72
|
+
pages.map { |p| { key: p, file: "#{p}.html" } }
|
|
73
|
+
|
|
74
|
+
generated = []
|
|
75
|
+
pages_to_generate.each do |page|
|
|
76
|
+
tmpl = File.join(TEMPLATE_DIR, page[:file])
|
|
77
|
+
next unless File.exist?(tmpl)
|
|
78
|
+
|
|
79
|
+
nav = build_nav_links(pages, page[:key])
|
|
80
|
+
html = interpolate(File.read(tmpl), base_vars.merge("NAV_LINKS" => nav))
|
|
81
|
+
File.write(File.join(output_dir, page[:file]), html)
|
|
82
|
+
generated << page[:file]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
generated
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module CreateGeocitiesApp
|
|
2
|
+
THEMES = {
|
|
3
|
+
"neon" => {
|
|
4
|
+
bg: "#000000", bg_pattern: "radial-gradient(circle, #001100 1px, transparent 1px)",
|
|
5
|
+
bg_size: "20px 20px", text_color: "#00FF00", heading_color: "#FFFF00",
|
|
6
|
+
link_color: "#FF00FF", link_hover: "#00FFFF", accent_color: "#00FFFF",
|
|
7
|
+
border_light: "#00FF00", border_dark: "#003300", panel_bg: "#001100",
|
|
8
|
+
panel_border: "#00FF00", counter_bg: "#000000", counter_text: "#00FF00",
|
|
9
|
+
table_border: "#00FF00", table_header_bg: "#003300", glow_color: "#00FF00",
|
|
10
|
+
nav_active_bg: "#00FF00", nav_active_text: "#000000", name: "Neon",
|
|
11
|
+
},
|
|
12
|
+
"space" => {
|
|
13
|
+
bg: "#000033", bg_pattern: "radial-gradient(circle, #ffffff 1px, transparent 1px)",
|
|
14
|
+
bg_size: "30px 30px", text_color: "#CCCCFF", heading_color: "#FFDD00",
|
|
15
|
+
link_color: "#00FFFF", link_hover: "#FF6600", accent_color: "#FF6600",
|
|
16
|
+
border_light: "#6666FF", border_dark: "#000022", panel_bg: "#000055",
|
|
17
|
+
panel_border: "#6666FF", counter_bg: "#000022", counter_text: "#00FFFF",
|
|
18
|
+
table_border: "#6666FF", table_header_bg: "#000055", glow_color: "#6666FF",
|
|
19
|
+
nav_active_bg: "#FFDD00", nav_active_text: "#000033", name: "Space",
|
|
20
|
+
},
|
|
21
|
+
"candy" => {
|
|
22
|
+
bg: "#FF69B4", bg_pattern: "repeating-linear-gradient(45deg, #FF1493 0px, #FF1493 2px, #FF69B4 2px, #FF69B4 20px)",
|
|
23
|
+
bg_size: "auto", text_color: "#FFFFFF", heading_color: "#FFFF00",
|
|
24
|
+
link_color: "#00FFFF", link_hover: "#FF1493", accent_color: "#FF1493",
|
|
25
|
+
border_light: "#FFFFFF", border_dark: "#CC0066", panel_bg: "#FF1493",
|
|
26
|
+
panel_border: "#FFFFFF", counter_bg: "#CC0066", counter_text: "#FFFF00",
|
|
27
|
+
table_border: "#FFFFFF", table_header_bg: "#FF1493", glow_color: "#FFFFFF",
|
|
28
|
+
nav_active_bg: "#FFFF00", nav_active_text: "#CC0066", name: "Candy",
|
|
29
|
+
},
|
|
30
|
+
"forest" => {
|
|
31
|
+
bg: "#003300", bg_pattern: "repeating-linear-gradient(0deg, #002200 0px, #002200 1px, #003300 1px, #003300 20px)",
|
|
32
|
+
bg_size: "auto", text_color: "#CCFFCC", heading_color: "#FFDD00",
|
|
33
|
+
link_color: "#99FF99", link_hover: "#FF6600", accent_color: "#FF6600",
|
|
34
|
+
border_light: "#66FF66", border_dark: "#001100", panel_bg: "#002200",
|
|
35
|
+
panel_border: "#66FF66", counter_bg: "#001100", counter_text: "#99FF99",
|
|
36
|
+
table_border: "#66FF66", table_header_bg: "#002200", glow_color: "#66FF66",
|
|
37
|
+
nav_active_bg: "#FFDD00", nav_active_text: "#002200", name: "Forest",
|
|
38
|
+
},
|
|
39
|
+
"windows" => {
|
|
40
|
+
bg: "#008080", bg_pattern: "none", bg_size: "auto",
|
|
41
|
+
text_color: "#000000", heading_color: "#000080",
|
|
42
|
+
link_color: "#000080", link_hover: "#FF0000", accent_color: "#000080",
|
|
43
|
+
border_light: "#FFFFFF", border_dark: "#808080", panel_bg: "#C0C0C0",
|
|
44
|
+
panel_border: "#808080", counter_bg: "#000080", counter_text: "#FFFFFF",
|
|
45
|
+
table_border: "#808080", table_header_bg: "#000080", glow_color: "#000080",
|
|
46
|
+
nav_active_bg: "#000080", nav_active_text: "#FFFFFF", name: "Windows 95",
|
|
47
|
+
},
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
def self.get_theme(name)
|
|
51
|
+
THEMES[name] || THEMES["neon"]
|
|
52
|
+
end
|
|
53
|
+
end
|