inital commit

This commit is contained in:
Dominic 2025-06-27 21:53:50 -04:00
commit baed8c9c3b
5 changed files with 383 additions and 0 deletions

48
README.md Normal file
View file

@ -0,0 +1,48 @@
# HOMEMAKER
Keep making the web your own! Create your own custom static homepage!
live demo: https://home.domdit.com/
#### Features:
- Customizable background images
- Background images persist in new tabs and browser instances through the use of a cookie
- Customizable links
- Links have keybinds so you can type a letter and automatically be redirected to the page of your choice
- Tabbing system to sort your links
- Customizable fonts, colors, links, page title
- Configuration file based generation
## Quickstart:
1. Clone this repository
2. Modify homemaker.conf
3. Put your favorite wallpapers in the folder `bg/`
3. Run `python3 homemaker.py build` to compile your homepage
4. The compiled homepage is now in a folder called `build/`
5. Run `python3 homemaker.py serve`
6. Go to http://localhost:8000 to view your homepage
7. repeat steps 2 through 7 until you have a homepage you are happy with.
8. Take the files in the `build/` folder and host them wherever you host everything else
9. Update all of your browsers so that the home button and new tab button point to your new homepage
## How to Host:
### With your own server using nginx
I am not going to go in depth here. If you have your own server, I would:
- put the compiled files in the `build/` directory in `/var/www/homepage`
- create an nginx config entry that looks something like this:
```
server {
server_name home.<my-domain>.com www.home.<my-domain>.com;
location / {
root /var/www/homepage;
}
}
```
- reload nginx and you are good to go!
### Hosting locally
Similar to hosting remotely, probably, just read for yourself: https://tcude.net/hosting-internal-sites-with-nginx/

BIN
bg/pokemon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

27
homemaker.conf Normal file
View file

@ -0,0 +1,27 @@
# in this file, spaces and tabs are acceptable between key and value
# Modify the homepage style
# title is the name that is shown in the tab in the browser
# the rest is pretty self explanatory
[style]
title Home
font monospace
font_color #e6e6fa
font_size 25
link_color #e6e6fa
link_hover_color #FF3F33
# each section should start with the word section then the name of the section
# do not exceed over 9 sections, idk what will happen lol but it probably will stop working
# the first letter is the keybind
# the second column is the displayed name on the homepage
# the third column is the link
[links]
section main
d domdit https://www.domdit.com
g google https://www.google.com
y youtube https://www.youtube.com
section games
n nethack https://www.nethack.org
b brogue https://sites.google.com/site/broguegame

159
homemaker.py Executable file
View file

@ -0,0 +1,159 @@
#!/usr/bin/python3
import argparse
import http.server
import json
import os
import re
import shutil
import socketserver
class Builder:
def __init__(self):
self.config_file_path = 'homemaker.conf'
self.template_path = 'templates/template.html'
self.build_directory = 'build'
self.key_map = {}
self.bg_map = {}
self.bg_options = ''
self.links = ''
self.style_map = {
'title': 'Homepage',
'bg_img': 'null',
'font': 'monospace',
'font_color': '#e6e6fa',
'font_size': '25',
'link_color': '#e6e6fa',
'link_hover_color': '#ff3f33',
}
self.section_count = 0
self.section_links = ''
self.section_array = []
self.section_map = {}
def main(self):
self.handle_backgrounds()
self.set_up_build_dir()
self.parse_config_file()
self.cleanup()
self.generate_files()
self.copy_bgs()
def set_up_build_dir(self):
if os.path.exists(self.build_directory):
print('Deleting build directory...')
shutil.rmtree(self.build_directory)
print('Creating build directory...')
os.makedirs(self.build_directory)
def handle_backgrounds(self):
print('Parsing background images...')
for root, dirs, files in os.walk("bg/", topdown=False):
for idx, file_path in enumerate(files):
file_name = file_path.split('/')[-1].split('.')[0]
if idx == 0:
self.style_map['bg_img'] = file_path
self.bg_map[file_name] = file_path
option = f'\t<option value="{file_name}">{file_name}</option>\n'
self.bg_options += option
def parse_config_file(self):
print('Parsing config file...')
with open(self.config_file_path) as f:
mode = None
for line in f:
line = line.strip()
if line[0] == '#':
continue
if line == "[style]":
print('Handling styles...')
mode = 'style'
continue
if line == "[links]":
print('Handling links...')
mode = 'links'
continue
if mode == 'links':
self.handle_links(line)
elif mode == 'style':
self.handle_styles(line)
def handle_styles(self, line):
style = re.split(r'[ \t]+', line)
if style[0] in self.style_map:
self.style_map[style[0]] = style[1]
def handle_links(self, line):
links = re.split(r'[ \t]+', line)
if links[0] == 'section':
self.section_count += 1
self.section_links += f'<a href="#" class="link" onclick="toggleSection("{links[1]}")">[{self.section_count}]&nbsp;{links[1]}</a> '
self.section_array.append(links[1])
if self.links == '':
self.links += f'<div id="{links[1]}" style="display:block">\n'
else:
self.links += f'<div id="{links[1]}" style="display:none">\n'
self.section_map[str(self.section_count)] = links[1]
elif links[0] == '':
self.links += '</div>\n'
else:
self.links += f'\t<a href="{links[2]}" id="{links[1]}" class="link">[{links[0]}] {links[1]} </a><br>\n'
self.key_map[links[0]] = links[2]
def cleanup(self):
self.links += '</div>\n\n'
def generate_files(self):
print('Generating Files...')
with open(self.template_path) as f:
compiled_file = f.read() \
.replace('{{bg_options}}', self.bg_options) \
.replace('{{links}}', self.links) \
.replace('{{section_links}}', self.section_links) \
.replace('{{bg_map}}', json.dumps(self.bg_map)) \
.replace('{{key_map}}', json.dumps(self.key_map)) \
.replace('{{section_array}}', json.dumps(self.section_array)) \
.replace('{{section_map}}', json.dumps(self.section_map))
for style, value in self.style_map.items():
compiled_file = compiled_file.replace('{{' + style + '}}', value)
with open(self.build_directory + '/index.html', 'w+') as f:
f.write(compiled_file)
def copy_bgs(self):
print('Copying backgrounds..')
shutil.copytree('bg/', self.build_directory + '/bg/')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('action', type=str, help='OPTIONS:\n build - delete and recompile your build folder. \n serve - run webserver')
args = parser.parse_args()
if args.action == 'build':
b = Builder()
b.main()
elif args.action == 'serve':
os.chdir('build/')
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print(f"Check out your homepage here: http://localhost:{PORT}")
httpd.serve_forever()

149
templates/template.html Normal file
View file

@ -0,0 +1,149 @@
<head>
<title>{{title}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<style>
body {
background-image: url("bg/{{bg_img}}");
background-size: cover;
background-position: center;
font-family: {{font}};
font-size: {{font_size}}px;
color: {{font_color}};
}
table, th, td {
border: 1px solid black;
}
.settings {
position: absolute;
top: 10px;
right: 20px;
font-size: 14px;
}
option, select {
width: 70px;
font-family: {{font}};
background: grey;
}
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.link-container {
width: 300px;
background: rgba(255, 255, 50, 0.11);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.26);
padding: 20px;
}
.link {
color: {{link_color}};
text-decoration: none;
}
.link:hover {
color: {{link_hover_color}};
text-decoration: none;
}
</style>
<div class='settings'>
<select name="dropdown" id="dropdown">
<option value="">set bg</option>
{{bg_options}}
</select>
</div>
<div class="container">
<div class="link-container">
{{links}}
<br>
<span style="font-size:14px">
{{section_links}}
</span><br>
</div>
</div>
<script>
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
var bg = getCookie("bg")
console.log(bg)
if (bg != "" && bg != 'undefined') {
changeWallpaper(bg)
}
function changeWallpaper(bg) {
document.cookie = "bg=" + bg;
var bg_map = {{bg_map}}
document.body.style.backgroundImage = "url('bg/"+ bg_map[bg] +"')";
}
document.getElementById("dropdown").addEventListener("change", function () {
if (this.value != "") {
changeWallpaper(this.value);
}
});
var key_map = {{key_map}}
function toggleSection(section) {
var sections = {{section_array}}
for (let i = 0; i < sections.length; i++) {
if (section == sections[i]) {
document.getElementById(sections[i]).style.display = 'block';
} else {
document.getElementById(sections[i]).style.display = 'none';
}
}
}
document.onkeypress = function (e) {
var section_map = {{section_map}}
if (e.key in section_map) {
toggleSection(section_map[e.key])
} else {
if (e.key in key_map) {
window.location.href = key_map[e.key];
}
}
};
</script>
</body>