Landing page minimale stile Linkstack 100% statica - HTML/CSS puro senza JavaScript https://me.emanuelegori.uno/
  • HTML 45.5%
  • CSS 24.3%
  • Python 21.2%
  • PHP 9%
Find a file
2026-10-17 19:13:45 +02:00
deploy v2.2.2: README bilingue, niente .md pubblicati, pulizia residui 2026-10-03 21:54:49 +02:00
en v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
icons v2.2.2: README bilingue, niente .md pubblicati, pulizia residui 2026-10-03 21:54:49 +02:00
.gitignore v2.2.2: README bilingue, niente .md pubblicati, pulizia residui 2026-10-03 21:54:49 +02:00
avatar.png v2.1.0: SEO, accessibilità e ottimizzazione immagini 2026-08-20 19:54:42 +02:00
avatar.webp v2.1.0: SEO, accessibilità e ottimizzazione immagini 2026-08-20 19:54:42 +02:00
CHANGELOG.md v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
favicon.ico Add new favicon 2026-01-22 13:21:40 +01:00
index.html v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
LICENSE.IT.md Update HTML and CSS 2026-01-13 23:40:37 +01:00
LICENSE.md Update HTML and CSS 2026-01-13 23:40:37 +01:00
og-image.png feat: add personalized og-image.png with correct avatar 2026-01-24 16:41:57 +01:00
README.it-IT.md v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
README.md v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
readme.txt v2.3.2: tolto emanuelegori.github.io dai dati strutturati 2026-10-17 19:13:45 +02:00
robots.txt Aggiorna robots.txt 2026-08-20 20:01:39 +02:00
sitemap.xml v2.3.1: link Privacy della pagina inglese verso /en/privacy/ 2026-10-04 00:54:15 +02:00
style.css v2.3.0: tema chiaro automatico e pulsante sole/luna solo CSS 2026-10-03 22:24:37 +02:00

Contact Page - Static Version

Italiano | English

Version License Docs

JavaScript HTML CSS Schema.org Lighthouse Cookies Tracking Languages Page size Built with

Minimal Linktree/Linkstack-style landing page, 100% static (plain HTML/CSS, zero JavaScript).

Source repository of the page published at me.emanuelegori.uno, with a copy at emanuelegori.alwaysdata.net.


Contents


Features

  • Plain HTML/CSS - Zero JavaScript, maximum simplicity
  • Modern design - Responsive dark mode with glassmorphism
  • Privacy-first - No tracking, analytics or cookies
  • Light and fast - Instant loading
  • Self-hosted - Full control over your data
  • Accessible - Works with JS disabled
  • Bilingual - Italian and English page, with automatic redirect based on the browser language
  • Light and dark theme - Follows the system, with a CSS-only sun/moon button
  • SEO optimized - Open Graph meta tags, Twitter Cards, Schema.org, hreflang
  • Fediverse verification - <link rel="me"> tags for the Mastodon green badge

Quick Start

# 1. Clone the repository
git clone https://git.emanuelegori.uno/emanuelegori/contact-page-static.git
cd contact-page-static

# 2. Customize the content (both languages)
nano index.html en/index.html

# 3. Publish on any web server
# Example: nginx, Apache, GitHub Pages, Netlify

Done! Your page is ready.


Installation

Requirements

  • A web server (nginx, Apache, Caddy, etc.)
  • Or static hosting (GitHub Pages, Netlify, Vercel, Cloudflare Pages)
  • No runtime dependencies

Project Structure

contact-page-static/
├── index.html          # Main page (Italian)
├── en/
│   └── index.html      # English version
├── style.css           # CSS styles
├── favicon.ico         # Site favicon
├── avatar.png          # Your profile picture (fallback, 240×240px)
├── avatar.webp         # Same picture in WebP, served via <picture>
├── og-image.png        # Social preview image (1200×630px)
├── robots.txt          # Crawler directives + sitemap reference
├── sitemap.xml         # XML sitemap with language alternates
├── icons/              # Link icons (SVG, PNG for raster logos)
├── deploy/             # Deploy scripts + nginx.conf (not published)
├── README.md           # This file
├── README.it-IT.md     # Italian documentation
├── CHANGELOG.md        # Change history (Italian)
├── LICENSE.md          # Code license (GPL v2)
└── LICENSE.IT.md       # Unofficial Italian translation of the GPL v2

.md files, readme.txt and the deploy/ folder are not published by the deploy scripts.

English version

/ is the Italian page, /en/ the English one. With deploy/nginx.conf, visitors opening / with a browser whose preferred language is not Italian are redirected to /en/; the IT link points to /?lang=it to stay on the Italian page. Without that configuration (static hosting) both pages still work, just without the automatic redirect. When you change a text, update it in both pages.

Light and dark theme

The theme follows the system setting (prefers-color-scheme). The sun/moon button next to IT · EN is a hidden checkbox: when checked, :has() inverts the system theme. No JavaScript or cookies, so the choice is not remembered when reloading the page or switching language. In browsers without :has() the button has no effect; the automatic theme still works.

Colors are variables in :root; the light theme redefines them in two identical blocks in style.css (light system without the button, dark system with the button): if you change a light-theme color, update both. A white monochrome logo with class="icon-mono" turns black in the light theme.


Deployment

Option 1: Traditional Web Server

# Copy the files to the document root
sudo cp -r * /var/www/html/contact/

# Or with rsync
rsync -av --exclude='.git' * user@server:/var/www/html/contact/

nginx configuration (minimal; for the language redirect see deploy/nginx.conf):

server {
    listen 80;
    server_name me.yourdomain.com;
    root /var/www/html/contact;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

Option 2: Docker (optional)

Create a docker-compose.yml:

services:
  contact-page:
    image: nginx:alpine
    container_name: contact-page-static
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./:/usr/share/nginx/html:ro
      - ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - proxy

networks:
  proxy:
    external: true

Deploy:

docker compose up -d

Option 3: Free Static Hosting

The project works with:

  • GitHub Pages - Free, custom domain
  • Netlify - Automatic deploy from Git
  • Vercel - Automatic optimizations
  • Cloudflare Pages - Free global CDN

GitHub Pages example:

  1. Push to a GitHub repository
  2. Settings → Pages → Source: main branch
  3. Site available at username.github.io/contact-page-static

Automatic deploy (deploy/ folder)

Script Where How
webhook-listener.py VPS with Docker receives the Forgejo webhook on every push to main (HMAC-SHA256 signature)
update-site.php shared hosting (Alwaysdata) scheduled task: compares the SHA of the latest commit and updates when it changes
update-site.py any server with Python same as update-site.php, via cron

All three copy the publishable files and update, in both pages, the "Last update" date, the version (read from CHANGELOG.md), the copyright year and the CSS ?v= parameter, which makes browsers download the new stylesheet with each version. Environment variables in deploy/.env.example.


Customization

1. Edit Content (index.html and en/index.html)

<!-- Name and bio -->
<h1 class="name">Your Name</h1>
<p class="tagline">Your tagline</p>
<p class="bio">Your bio...</p>

<!-- Add/remove links: one card per <li> -->
<li>
    <a href="your-url" class="link-card" data-category="blog" target="_blank" rel="noopener me">
        <div class="link-icon">
            <img src="icons/icon-name.svg" alt="" width="64" height="64" decoding="async">
        </div>
        <div class="link-name">Link Name</div>
        <div class="link-description">Description</div>
    </a>
</li>

The icon has alt="" because it is decorative: the card name is already in the text. In en/index.html paths start with ../ (../icons/icon-name.svg).

2. Change Colors (style.css)

:root {
    --bg-primary: #0a0a0a;                 /* Main background */
    --bg-card: rgba(42, 42, 42, 0.6);      /* Card background */
    --text-primary: #ffffff;               /* Main text */
    --text-secondary: #b0b0b0;             /* Secondary text */
    --accent-blog: #ff7b00;                /* Hover border, per category */
}

3. Add an Avatar

Upload avatar.png (or .jpg) to the project root. The HTML is already set up. For better performance, resize it to 240×240px and add an avatar.webp next to it: the <picture> tag serves WebP to browsers that support it and PNG to the others.

4. Custom Favicon

  1. Create your favicon.ico (16x16, 32x32, 48x48 px)
  2. Save it in the project root
  3. The link is already in index.html:
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    

5. Social Image (og-image.png)

For good previews on Facebook/LinkedIn/Twitter:

Specs:

  • Size: 1200 × 630 px
  • Format: PNG or JPG
  • Content: name, tagline, avatar, URL
  • Background: consistent with the page design

Suggested tools:

  • Canva - Social media templates
  • GIMP - Open source editor
  • Figma - Professional design

6. Add Icons

Icons in icons/:

File Use
homelab-notes.png Homelab Notes blog logo (128×128 raster, light stroke on transparent)
wordpress.svg WordPress.org profile
forgejo.svg Forgejo / Gitea
git.svg Generic Git
mastodon.svg Mastodon / Fediverse
peertube.svg PeerTube
bluesky.svg Bluesky
keyoxide.svg Keyoxide
email.svg Email
gravatar.svg Gravatar
phanpy.svg Phanpy
pixelfed.svg Pixelfed
twitter.svg Twitter / X
linkedin.svg LinkedIn

Recommended sources:

Save it as icons/icon-name.svg and reference it in the HTML. The page background is dark: a logo with a black stroke needs to be lightened and made transparent.

7. Mastodon Verification (green badge ✅)

To get the green badge on Mastodon:

  1. Add <link rel="me"> to the <head> of index.html:

    <link rel="me" href="https://mastodon.instance/@username">
    
  2. In your Mastodon profile, add the link to the page:

    Metadata → Label: Website → Content: https://me.yourdomain.com
    
  3. Save → the green badge appears automatically


Privacy

This page is fully privacy-first:

Feature Status
Third-party JavaScript ❌ None
Tracking/Analytics ❌ None
Cookies ❌ None
External requests ❌ None
Self-hosted ✅ 100%
Verifiable code ✅ Open source
Works without JS ✅ Yes

GDPR compliance: no cookie banner or dedicated privacy policy needed for the page itself (only for any external links).


Contributing

Pull requests are welcome! For major changes:

  1. Open an issue first
  2. Describe the proposed change
  3. Fork and create a branch for your feature
  4. Submit the pull request

Guidelines:

  • Keep the code clean and commented
  • Test on different browsers (Firefox, Chrome, Safari)
  • Check accessibility (screen readers, keyboard navigation)
  • Update both languages, pages and READMEs
  • Respect the existing licenses

Licenses

Source Code (HTML, CSS)

The code is released under the GNU General Public License v2 or later (GPL v2+).

See LICENSE.md for the full text; LICENSE.IT.md is an unofficial Italian translation.

Why GPL v2+:

  • Compatible with WordPress and the GPL ecosystem
  • Ensures derivative works stay open source
  • Aligned with FOSS values

Documentation

The documentation (README, guides, wiki) is released under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0).

Full text: creativecommons.org/licenses/by-nc-sa/4.0.

You can:

  • Share and adapt the documents
  • Use them for non-commercial purposes
  • Give credit to the author

You cannot:

  • Use the documentation commercially
  • Apply additional restrictions

Support

Issues or Questions

FAQ

Q: Can I use it for my site?
A: Yes! It is GPL v2+, free to use, modify and distribute.

Q: Do I have to keep the credits?
A: Yes, the GPL requires keeping the copyright notice.

Q: Does it work on mobile?
A: Yes, it is fully responsive.

Q: Can I remove the footer?
A: Technically yes, but the footer contains the credits required by the license.


Credits


Changelog

See CHANGELOG.md for the change history (in Italian).


© 2025-2026 Emanuele Gori | Theme: ContactPage v2.3.2 | GPL v2+