diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab1e78e --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Binaries +linuxservice +*.exe +*.dll +*.so +*.dylib + +# Build directories +/bin/ +/build/ +/dist/ + +# Logs and caches +*.log +*.cache + +# OS files +.DS_Store +Thumbs.db + +# Editor/project files +.vscode/ +.idea/ + +# Go +*.test +coverage.out + +/wiki/ diff --git a/linuxservice b/linuxservice deleted file mode 100755 index 30c4a42..0000000 Binary files a/linuxservice and /dev/null differ diff --git a/main.go b/main.go index 563e47d..bee2213 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "log" "net/http" "os" + "path/filepath" "strings" "sync" "time" @@ -97,11 +98,35 @@ func NewServer() *Server { SonBirthDate: getEnv("SON_BIRTH_DATE", "2022-01-01"), } + // Template Funcs + funcs := template.FuncMap{ + "dict": func(values ...interface{}) (map[string]interface{}, error) { + if len(values)%2 != 0 { + return nil, fmt.Errorf("dict expects even number of args") + } + m := make(map[string]interface{}, len(values)/2) + for i := 0; i < len(values); i += 2 { + k, ok := values[i].(string) + if !ok { + return nil, fmt.Errorf("dict keys must be strings") + } + m[k] = values[i+1] + } + return m, nil + }, + } + // Parse templates with error handling - templates, err := template.ParseGlob("templates/*.html") + templates, err := template.New("").Funcs(funcs).ParseGlob("templates/*.html") if err != nil { log.Fatalf("Failed to parse templates: %v", err) } + // Optionally parse partials if any exist + if matches, _ := filepath.Glob("templates/partials/*.html"); len(matches) > 0 { + if _, err := templates.ParseFiles(matches...); err != nil { + log.Fatalf("Failed to parse partial templates: %v", err) + } + } return &Server{ config: config, @@ -109,6 +134,21 @@ func NewServer() *Server { } } +// cleanupOldSubmissions periodically purges stale rate-limit entries +func cleanupOldSubmissions() { + for { + time.Sleep(10 * time.Minute) + mu.Lock() + cutoff := time.Now().Add(-submissionCooldown) + for ip, t := range lastSubmissionTime { + if t.Before(cutoff) { + delete(lastSubmissionTime, ip) + } + } + mu.Unlock() + } +} + // createPageData creates PageData with the given title and current page func (s *Server) createPageData(title, currentPage string) PageData { return PageData{ @@ -208,7 +248,7 @@ func (s *Server) handleContactForm(w http.ResponseWriter, r *http.Request, data mu.Unlock() // On success, render success message - data.SuccessMessage = "Bedankt voor uw bericht! We nemen zo snel mogelijk contact met u op." + data.SuccessMessage = "Bedankt voor uw bericht! Ik neem zo snel mogelijk contact met u op." data.FormData = ContactForm{} // Clear form data s.renderTemplate(w, "contact.html", *data) } @@ -238,7 +278,7 @@ func (s *Server) sendToTelegram(form ContactForm) error { payload := map[string]interface{}{ "chat_id": s.config.TelegramChatID, "text": message, - "parse_mode": "Markdown", + "parse_mode": "MarkdownV2", } jsonData, err := json.Marshal(payload) @@ -346,23 +386,57 @@ func (s *Server) aboutHandler(w http.ResponseWriter, r *http.Request) { s.renderTemplate(w, "over-mij.html", data) } +// dienstenHandler handles the services page +func (s *Server) dienstenHandler(w http.ResponseWriter, r *http.Request) { + data := s.createPageData("Diensten en tarieven - "+s.config.CompanyName, "diensten") + s.renderTemplate(w, "diensten.html", data) +} + +// linuxHandler handles the Linux page (distributions + features) +func (s *Server) linuxHandler(w http.ResponseWriter, r *http.Request) { + data := s.createPageData("Linux distributies en functies - "+s.config.CompanyName, "linux") + s.renderTemplate(w, "linux.html", data) +} + // setupRoutes configures all HTTP routes func (s *Server) setupRoutes() { // Static files fs := http.FileServer(http.Dir("static/")) - http.Handle("/static/", http.StripPrefix("/static/", fs)) + http.Handle("/static/", http.StripPrefix("/static/", cacheControlMiddleware(fs))) // Page routes http.HandleFunc("/", s.homeHandler) http.HandleFunc("/contact", s.contactHandler) http.HandleFunc("/over-mij", s.aboutHandler) + http.HandleFunc("/diensten", s.dienstenHandler) + http.HandleFunc("/linux", s.linuxHandler) http.HandleFunc("/health", s.healthHandler) } func main() { server := NewServer() server.setupRoutes() + // Start background cleanup for rate limiting map + go cleanupOldSubmissions() log.Printf("Server starting on %s", server.config.Port) log.Fatal(http.ListenAndServe(server.config.Port, nil)) } + +// cacheControlMiddleware sets Cache-Control headers for static assets +func cacheControlMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + path := r.URL.Path + switch { + case strings.HasSuffix(path, ".css") || strings.HasSuffix(path, ".js") || + strings.HasSuffix(path, ".png") || strings.HasSuffix(path, ".jpg") || + strings.HasSuffix(path, ".jpeg") || strings.HasSuffix(path, ".webp") || + strings.HasSuffix(path, ".svg") || strings.HasSuffix(path, ".ico") || + strings.HasSuffix(path, ".woff2"): + w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") + default: + w.Header().Set("Cache-Control", "public, max-age=300") + } + next.ServeHTTP(w, r) + }) +} diff --git a/static/style.css b/static/css/style.css similarity index 82% rename from static/style.css rename to static/css/style.css index c458480..56f4e5d 100644 --- a/static/style.css +++ b/static/css/style.css @@ -157,7 +157,7 @@ p { /* Hero Section */ .hero { - background: linear-gradient(135deg, rgba(236, 253, 245, 0.85) 0%, rgba(209, 250, 229, 0.85) 100%), url('/static/TuxAinrom.webp'); + background: linear-gradient(135deg, rgba(236, 253, 245, 0.85) 0%, rgba(209, 250, 229, 0.85) 100%), url('/static/images/TuxAinrom.webp'); background-size: cover; background-position: center; background-repeat: no-repeat; @@ -226,6 +226,98 @@ p { } } +/* Universal Card Base Class */ +.card { + background: white; + border-radius: 12px; + padding: 2rem; + transition: transform 0.3s ease, box-shadow 0.3s ease; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + border: 1px solid transparent; + display: flex; + flex-direction: column; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 30px rgba(5, 150, 105, 0.15); +} + +.card h3 { + color: #047857; + margin-bottom: 1rem; +} + +/* Card Variants */ +.card--benefit { + background: #f0fdf4; + border-color: #bbf7d0; + text-align: center; +} + +.card--benefit:hover { + border-color: #34d399; +} + +.card--service { + background: #f0fdf4; + border-left: 4px solid #059669; + border-radius: 12px; +} + +.card--service:hover { + transform: translateY(-3px); +} + +.card--distro { + background: white; + border-radius: 16px; + min-height: 400px; + position: relative; + overflow: hidden; +} + +.card--distro::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, #059669, #10b981); +} + +.card--distro:hover { + transform: translateY(-8px); + border-color: #a7f3d0; +} + +.card--cta { + text-align: center; + border: 2px solid #bbf7d0; +} + +/* Card Content Components */ +.card__icon { + font-size: 3rem; + margin-bottom: 1rem; +} + +.card--benefit .card__icon { + font-size: 3rem; +} + +.card--cta .card__icon { + font-size: 3rem; +} + +/* Clickable Card Utility */ +.card-link { + text-decoration: none; + color: inherit; + display: block; +} + /* Buttons */ .btn { padding: 12px 24px; @@ -269,12 +361,66 @@ p { font-size: 1.1rem; } -/* Benefits Section */ -.benefits { - padding: 5rem 0; +/* Universal Section Classes */ +.section { + padding: 3.5rem 0; +} + +.section--light { background: #fff; } +.section--light-green { + background: #f9fafb; +} + +/* Brand-tinted light background for callouts and CTAs */ +.section--brand { + background: #f0fdf4; +} + +.section--hero { + padding: 4rem 0; + min-height: 80vh; +} + +/* Section Headers */ +.section__title { + text-align: center; + margin-bottom: 3rem; + color: #047857; +} + +.section__subtitle { + text-align: center; + font-size: 1.1rem; + color: #6b7280; + margin-bottom: 4rem; + max-width: 600px; + margin-left: auto; + margin-right: auto; +} + +/* Universal Grid Classes */ +.grid { + display: grid; + gap: 2rem; +} + +.grid--2-col { + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); +} + +.grid--3-col { + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); +} + +.grid--responsive-cards { + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); +} + +/* Legacy Section Classes - Cleaned Up */ + .benefits h2 { text-align: center; margin-bottom: 3rem; @@ -287,34 +433,8 @@ p { gap: 2rem; } -.benefit-card { - background: #f0fdf4; - padding: 2rem; - border-radius: 12px; - text-align: center; - transition: transform 0.3s ease, box-shadow 0.3s ease; - border: 1px solid #bbf7d0; -} - -.benefit-card:hover { - transform: translateY(-5px); - box-shadow: 0 10px 30px rgba(5, 150, 105, 0.15); - border-color: #34d399; -} - -.benefit-icon { - font-size: 3rem; - margin-bottom: 1rem; -} - -.benefit-card h3 { - color: #047857; - margin-bottom: 1rem; -} - /* Windows EOL Section */ .windows-eol { - padding: 5rem 0; background: #fffbeb; position: relative; overflow: hidden; @@ -429,10 +549,6 @@ p { } /* Distributions Section */ -.distros { - padding: 5rem 0; - background: #f9fafb; -} .distros h2 { text-align: center; @@ -458,36 +574,6 @@ p { align-items: stretch; } -.distro-card { - background: white; - border-radius: 16px; - padding: 2rem; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); - transition: all 0.3s ease; - border: 2px solid transparent; - position: relative; - overflow: hidden; - display: flex; - flex-direction: column; - min-height: 400px; -} - -.distro-card::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 4px; - background: linear-gradient(90deg, #059669, #10b981); -} - -.distro-card:hover { - transform: translateY(-8px); - box-shadow: 0 12px 40px rgba(5, 150, 105, 0.15); - border-color: #a7f3d0; -} - .distro-header { display: flex; align-items: flex-start; @@ -588,10 +674,6 @@ p { } /* Services Section */ -.services { - padding: 5rem 0; - background: #fff; -} .services h2 { text-align: center; @@ -605,28 +687,55 @@ p { gap: 2rem; } -.service-card { - background: #f0fdf4; - padding: 2rem; +/* Steps grid: balanced layout 3/2/1 across breakpoints */ +.steps-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 2rem; +} + +@media (max-width: 1024px) { + .steps-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 640px) { + .steps-grid { + grid-template-columns: 1fr; + } +} + +/* Distro tiles */ +.distro-tiles { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 1.5rem; +} + +.distro-tile { + background: #fff; + border: 1px solid #e5e7eb; border-radius: 12px; - border-left: 4px solid #059669; - transition: transform 0.3s ease; + padding: 1.25rem; + text-align: center; + box-shadow: 0 4px 12px rgba(0,0,0,0.06); + transition: transform 0.2s ease, box-shadow 0.2s ease; } -.service-card:hover { - transform: translateY(-3px); +.distro-tile:hover { + transform: translateY(-4px); + box-shadow: 0 10px 20px rgba(5,150,105,0.12); } -.service-card h3 { - color: #047857; - margin-bottom: 1rem; +.distro-tile__img { + width: 72px; + height: 72px; + object-fit: contain; + margin-bottom: 0.75rem; } /* Linux Features Section */ -.linux-features { - padding: 5rem 0; - background: #f9fafb; -} .linux-features h2 { text-align: center; @@ -703,6 +812,18 @@ p { } +/* Intro GNOME section overrides */ +.intro-gnome .feature-image img { + width: 100%; + height: auto; + object-fit: contain; +} + +.intro-gnome .feature-image { + aspect-ratio: auto; +} + + .feature-showcase h3 { color: #047857; @@ -726,7 +847,6 @@ p { /* CTA Section */ .cta { - padding: 5rem 0; background: linear-gradient(135deg, #059669 0%, #047857 100%); color: white; text-align: center; @@ -744,12 +864,43 @@ p { } /* Contact Page Styles */ -.contact-hero { +/* Deprecated: contact-hero replaced by .page-hero */ + +/* Generic page hero reused across pages */ +.page-hero { background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%); - padding: 3rem 0; + padding: 2.25rem 0; text-align: center; } +/* Match heading color for reusable hero */ +.page-hero h1 { + color: #047857; + margin-bottom: 1rem; +} + +/* Keep heading links visually identical to headings */ +h2 a { + text-decoration: none; + color: inherit; +} + +/* Ensure card titles with links look identical to non-linked titles */ +.card h3 a, +.card h3 a:visited, +.card h3 a:hover, +.card h3 a:active { + text-decoration: none; + color: inherit; +} + +/* Reusable link wrapper to make whole cards clickable */ +.card-link { + text-decoration: none; + color: inherit; + display: block; +} + .contact-hero h1 { color: #047857; margin-bottom: 1rem; @@ -881,10 +1032,6 @@ p { min-height: 120px; } -.contact-cta { - padding: 4rem 0; - background: #f0fdf4; -} .contact-cta h2 { text-align: center; @@ -898,22 +1045,58 @@ p { gap: 2rem; } +/* Pricing/Tarieven benefit cards */ .cta-benefit { - text-align: center; - padding: 2rem; - background: white; + background: #fff; + border: 1px solid #e5e7eb; border-radius: 12px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + padding: 1.5rem; + text-align: center; + box-shadow: 0 4px 12px rgba(0,0,0,0.06); + transition: transform 0.2s ease, box-shadow 0.2s ease; } -.cta-benefit .benefit-icon { - font-size: 3rem; - margin-bottom: 1rem; +.cta-benefit:hover { + transform: translateY(-4px); + box-shadow: 0 10px 20px rgba(5,150,105,0.12); } -.cta-benefit h3 { +.benefit-icon { + width: 56px; + height: 56px; + border-radius: 9999px; + background: #ecfdf5; + border: 2px solid #bbf7d0; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 0.75rem auto; +} + +.benefit-icon__glyph { + font-weight: 700; color: #047857; - margin-bottom: 1rem; + font-size: 1.25rem; + line-height: 1; +} + +/* Collapsible disclaimer styles */ +details.disclaimer { + margin-top: 0.5rem; +} + +details.disclaimer summary { + cursor: pointer; + color: #047857; + font-weight: 600; +} + +details.disclaimer .disclaimer-body { + background: #f9fafb; + border-left: 4px solid #059669; + padding: 1rem 1rem 1rem 1.25rem; + border-radius: 6px; + margin-top: 0.75rem; } /* Footer */ @@ -957,8 +1140,8 @@ footer { } /* About page */ -.about { - padding: 5rem 0; +.section { + padding: 3.5rem 0; } .about-grid { @@ -1067,9 +1250,7 @@ footer { gap: 1.5rem; } - .benefit-card { - padding: 1.5rem; - } + .eol-content { grid-template-columns: 1fr; @@ -1081,9 +1262,7 @@ footer { gap: 1.5rem; } - .distro-card { - padding: 1.5rem; - } + .contact-grid { grid-template-columns: 1fr; @@ -1112,8 +1291,11 @@ footer { } /* Section padding adjustments */ - .benefits, .windows-eol, .distros, .services, .linux-features, .cta { - padding: 3rem 0; + .page-hero { + padding: 1.75rem 0; + } + .section { + padding: 2.25rem 0; } /* Typography adjustments */ @@ -1159,12 +1341,12 @@ footer { } /* Card padding adjustments */ - .benefit-card, .service-card, .distro-card, .cta-benefit { + .card { padding: 1.25rem; } /* Icon size adjustments */ - .benefit-icon, .cta-benefit .benefit-icon { + .card__icon { font-size: 2.5rem; } @@ -1196,8 +1378,11 @@ footer { } /* Section padding for very small screens */ - .benefits, .windows-eol, .distros, .services, .linux-features, .cta { - padding: 2rem 0; + .page-hero { + padding: 1.5rem 0; + } + .section { + padding: 1.75rem 0; } /* Typography for very small screens */ @@ -1277,7 +1462,7 @@ footer { font-size: 1rem; } - .benefit-card, .service-card, .distro-card, .cta-benefit { + .card { padding: 1rem; } @@ -1299,9 +1484,7 @@ footer { } } -.benefit-card, -.service-card, -.cta-benefit { +.card { animation: fadeInUp 0.6s ease-out; } diff --git a/static/favicon.ico b/static/icons/favicon.ico similarity index 100% rename from static/favicon.ico rename to static/icons/favicon.ico diff --git a/static/manifest.json b/static/icons/manifest.json similarity index 80% rename from static/manifest.json rename to static/icons/manifest.json index b515705..7ad6277 100644 --- a/static/manifest.json +++ b/static/icons/manifest.json @@ -8,12 +8,12 @@ "theme_color": "#059669", "icons": [ { - "src": "/static/android-chrome-192x192.png", + "src": "/static/images/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" }, { - "src": "/static/android-chrome-512x512.png", + "src": "/static/images/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" } diff --git a/static/DutchOpen2024.jpg b/static/images/DutchOpen2024.jpg similarity index 100% rename from static/DutchOpen2024.jpg rename to static/images/DutchOpen2024.jpg diff --git a/static/GamingBenchmarkLinuxvsWindows.webp b/static/images/GamingBenchmarkLinuxvsWindows.webp similarity index 100% rename from static/GamingBenchmarkLinuxvsWindows.webp rename to static/images/GamingBenchmarkLinuxvsWindows.webp diff --git a/static/LinuxMintCinnamonSoftwareManager.webp b/static/images/LinuxMintCinnamonSoftwareManager.webp similarity index 100% rename from static/LinuxMintCinnamonSoftwareManager.webp rename to static/images/LinuxMintCinnamonSoftwareManager.webp diff --git a/static/Tux.svg b/static/images/Tux.svg similarity index 100% rename from static/Tux.svg rename to static/images/Tux.svg diff --git a/static/TuxAinrom.png b/static/images/TuxAinrom.png similarity index 100% rename from static/TuxAinrom.png rename to static/images/TuxAinrom.png diff --git a/static/TuxAinrom.webp b/static/images/TuxAinrom.webp similarity index 100% rename from static/TuxAinrom.webp rename to static/images/TuxAinrom.webp diff --git a/static/Zorin-17-desktop.webp b/static/images/Zorin-17-desktop.webp similarity index 100% rename from static/Zorin-17-desktop.webp rename to static/images/Zorin-17-desktop.webp diff --git a/static/android-chrome-192x192.png b/static/images/android-chrome-192x192.png similarity index 100% rename from static/android-chrome-192x192.png rename to static/images/android-chrome-192x192.png diff --git a/static/android-chrome-512x512.png b/static/images/android-chrome-512x512.png similarity index 100% rename from static/android-chrome-512x512.png rename to static/images/android-chrome-512x512.png diff --git a/static/apple-touch-icon.png b/static/images/apple-touch-icon.png similarity index 100% rename from static/apple-touch-icon.png rename to static/images/apple-touch-icon.png diff --git a/static/clippy.png b/static/images/clippy.png similarity index 100% rename from static/clippy.png rename to static/images/clippy.png diff --git a/static/clippy_transparent.png b/static/images/clippy_transparent.png similarity index 100% rename from static/clippy_transparent.png rename to static/images/clippy_transparent.png diff --git a/static/images/elementary.png b/static/images/elementary.png new file mode 100644 index 0000000..0c30e68 Binary files /dev/null and b/static/images/elementary.png differ diff --git a/static/favicon-16x16.png b/static/images/favicon-16x16.png similarity index 100% rename from static/favicon-16x16.png rename to static/images/favicon-16x16.png diff --git a/static/favicon-32x32.png b/static/images/favicon-32x32.png similarity index 100% rename from static/favicon-32x32.png rename to static/images/favicon-32x32.png diff --git a/static/images/fedora.png b/static/images/fedora.png new file mode 100644 index 0000000..3e308b9 Binary files /dev/null and b/static/images/fedora.png differ diff --git a/static/images/garuda.svg b/static/images/garuda.svg new file mode 100644 index 0000000..49087c2 --- /dev/null +++ b/static/images/garuda.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/gnome.jpg b/static/images/gnome.jpg new file mode 100644 index 0000000..13820a8 Binary files /dev/null and b/static/images/gnome.jpg differ diff --git a/static/images/gnome.webp b/static/images/gnome.webp new file mode 100644 index 0000000..98c49d2 Binary files /dev/null and b/static/images/gnome.webp differ diff --git a/static/images/mint.svg b/static/images/mint.svg new file mode 100644 index 0000000..fd38dad --- /dev/null +++ b/static/images/mint.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/images/popos.svg b/static/images/popos.svg new file mode 100644 index 0000000..44628a2 --- /dev/null +++ b/static/images/popos.svg @@ -0,0 +1 @@ + diff --git a/static/images/ubuntu.png b/static/images/ubuntu.png new file mode 100644 index 0000000..69fd1bd Binary files /dev/null and b/static/images/ubuntu.png differ diff --git a/templates/contact.html b/templates/contact.html index 590862b..a944fc2 100644 --- a/templates/contact.html +++ b/templates/contact.html @@ -15,7 +15,7 @@ - + @@ -26,15 +26,15 @@ - + - - - - - + + + + + @@ -44,25 +44,27 @@ - + + + - + {{template "header" .}}
-
+

Neem contact op

-

Heeft u vragen over Linux migratie? Wij helpen u graag verder!

+

Heeft u vragen over Linux-migratie? Ik help u graag verder!

-
+
@@ -154,7 +156,7 @@
- +
@@ -164,29 +166,29 @@
-
+

Waarom kiezen voor {{.CompanyName}}?

-
-
🎯
+
+
🎯

Persoonlijke aanpak

-

Elke klant is uniek, en wij bieden maatwerkoplossingen.

+

Elke klant is uniek. Ik lever maatwerkoplossingen.

-
-
🛠️
+
+
🛠️

Professionele service

Ruim 20 jaar ervaring met Linux systemen en migraties.

-
-
🤝
+
+
🤝

Volledige ondersteuning

-

Van installatie tot training, wij begeleiden u door het hele proces.

+

Van installatie tot training: ik begeleid u door het hele proces.

-
-
💚
+
+
💚

Duurzame keuze

-

Samen bouwen we aan een duurzamere digitale toekomst.

+

U kiest voor een duurzamere digitale toekomst.

diff --git a/templates/diensten.html b/templates/diensten.html new file mode 100644 index 0000000..e3427d2 --- /dev/null +++ b/templates/diensten.html @@ -0,0 +1,147 @@ + + + + + + {{.Title}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{template "header" .}} + +
+
+
+

Diensten en tarieven

+

Linux blijft vrij. Mijn hulp is betaalbaar, met duidelijke afspraken vooraf.

+
+
+ +
+
+

Wat ik voor u kan doen

+
+
+

Gratis advies

+

Ik bekijk uw huidige computer en adviseer over de beste Linux-distributie en aanpak.

+
+
+

Installatieservice

+

Professionele Linux-installatie met basissoftware, updates en drivers waar nodig.

+
+
+

Datamigratie

+

Overzetten van bestanden, documenten en foto’s van uw oude systeem naar Linux. Zie ook de back-updisclaimer hieronder.

+
+
+

Training en ondersteuning

+

Uitleg en begeleiding zodat u direct prettig aan de slag kunt met Linux.

+
+
+
+
+ +
+
+

Waarom betalen voor hulp bij Linux?

+

Linux zelf is vrije software. Iedereen kan het downloaden en gebruiken. Wat ik aanbied, is mijn tijd, kennis en zorg: ik neem u het uitzoekwerk, de installatie en de uitleg uit handen. Zo kunt u zonder stress meteen prettig aan de slag.

+
+
+ +
+
+

Tarieven

+
+
+ +

€20 per half uur

+

Transparant, zonder verborgen kosten. Reistijd in overleg, binnen Het Hogeland vaak kosteloos.

+
+
+ +

Voorbeelden

+

Installatie + basisinrichting + uitleg: 1 à 2 uur. Migratie van gegevens: afhankelijk van volume en snelheid van opslag.

+
+
+ +

Extra service

+

Optioneel kan ik data kopiëren naar uw USB-stick(s) of externe schijf. Zie de back-updisclaimer.

+
+
+
+

Toegankelijkheid

+

Mijn standaardtarief is €20 per half uur. Dat is een eerlijke vergoeding voor mijn werk, waarmee ik deze service in Het Hogeland kan blijven aanbieden.

+

Heeft u een smalle beurs of zit u in een moeilijke situatie? Dan kijken we samen naar een oplossing. Ik vind dat financiële drempels geen reden mogen zijn om de overstap naar Linux te missen.

+

Ik organiseer regelmatig gratis informatiebijeenkomsten en help bij Repair Cafés. Dat blijft kosteloos.

+
+
+
+ +
+
+

Mijn aanpak

+
+

1. Kennismaking (gratis)

We bespreken wensen, hardware en gebruik.

+

2. Proefstart

Linux live vanaf USB om te testen op uw pc.

+

3. Installatie

Compleet ingericht met updates, drivers en basissoftware.

+

4. Migratie

Bestanden, foto’s en documenten veilig overzetten.

+

5. Uitleg & nazorg

Korte training en laagdrempelige ondersteuning.

+
+
+
+ +
+
+

Belangrijk over back-ups

+
+ Lees de back-updisclaimer +
+

Ik lever een Linux-installatie- en migratieservice. Back-ups maken en bewaren is in principe de verantwoordelijkheid van de klant. Als extra service kan ik, op uw verzoek, data kopiëren naar door u aangeleverde USB-sticks of een externe schijf. Als u geen opslag bij de hand heeft, kan ik USB-sticks van verschillende groottes meebrengen en leveren tegen een normale, eerlijke prijs.

+

Hoewel ik zorgvuldig werk, kan er bij datakopie of migratie altijd een risico op dataverlies bestaan, bijvoorbeeld door defecte schijven, corrupte data of hardwarefouten. U blijft verantwoordelijk voor uw eigen data. Ik ben niet aansprakelijk voor verlies of beschadiging van gegevens. Ik adviseer altijd om vooraf een eigen back-up te maken.

+
+
+ +
+
+
+ + {{template "footer" .}} + + + + diff --git a/templates/footer.html b/templates/footer.html index 521222a..dc245a2 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -20,7 +20,7 @@

Gemeenschap

Lid van Nederlandse Linux Gebruikers Groep (NLLGG.nl)

Actief bij Buurtlinux.nl initiatief

-

Wij ondersteunen de End-of-10-beweging voor duurzaam computergebruik.

+

Ik ondersteun de End-of-10-beweging voor duurzaam computergebruik.

Over mij · Contact

diff --git a/templates/header.html b/templates/header.html index edde632..8f23520 100644 --- a/templates/header.html +++ b/templates/header.html @@ -4,15 +4,14 @@
-
-
-

Waarom Linux kiezen?

-
-
-
🛡️
-

Veilig en betrouwbaar

-

Linux is van nature veiliger dan Windows. Minder virussen, geen gedwongen updates en volledige controle over uw systeem.

-
-
-
💰
-

Volledig gratis

-

Geen licentiekosten, geen abonnementen. Linux en alle software zijn gratis en open source.

-
-
-
🔄
-

Oude hardware hergebruiken

-

Uw computer van 10 jaar oud? Linux maakt hem weer snel! Geen nieuwe hardware nodig.

-
-
-
🌱
-

Milieuvriendelijk

-

Stop e-waste! Door Linux te gebruiken houdt u uw apparaten langer werkend en uit de afvalberg.

-
-
-
🔒
-

Privacybescherming

-

Geen tracking en geen verborgen gegevensverzameling. Uw privacy blijft van uzelf.

-
-
-
-

Snel en efficiënt

-

Linux gebruikt minder systeembronnen, waardoor uw computer sneller opstart en soepeler werkt.

-
-
-
-
+ {{template "benefits" (dict "Page" . "SectionClass" "section--light") }} -
+

Windows 10-ondersteuning eindigt

- Clippy advising to use Linux + Clippy advising to use Linux

Microsoft stopt de ondersteuning voor Windows 10 in oktober 2025. Dit betekent:

@@ -188,12 +152,26 @@
-
+
-

Welke Linux past bij u?

+

Mijn aanpak

+
+

1. Kennismaking (gratis)

Korte intake: wensen, hardware en gebruik. Samen kiezen we een route.

+

2. Proefstart

Linux live vanaf USB zodat u ziet hoe het werkt op uw pc.

+

3. Installatie

Veilig, met updates, codecs, printer, Nederlandse taal en basissoftware.

+

4. Migratie

Bestanden, foto's, documenten en favorieten overzetten.

+

5. Uitleg & nazorg

Korte training, daarna laagdrempelig bereikbaar voor vragen.

+
+

Daarnaast geef ik gratis informatiebijeenkomsten en help ik soms bij Repair Cafés met installaties, zonder kosten.

+
+
+ +
+
-
+
-
-
-

Linux in actie

-

Zie hoe Linux eruitziet en werkt in de praktijk

- -
-
-
- Zorin OS 17 Desktop Interface -
- Bron: DebugPoint.com -
-
-

Moderne desktopinterface

-

Linux ziet er vertrouwd en professioneel uit. Deze Zorin OS desktop lijkt op Windows maar is veel sneller en veiliger.

-
- -
-
- Linux Mint Software Manager -
- Bron: LinuxMint.com -
-
-

Eenvoudig software installeren

-

Duizenden gratis programma's met één klik installeren via de Software Manager. Net zo makkelijk als een app store.

-
- -
- -

Gamingprestaties

-

Linux kan vaak betere gamingprestaties leveren dan Windows, dankzij minder overhead en optimalisaties voor moderne games.

-
-
-
-
+ {{template "linux_features" (dict "Page" . "SectionClass" "section--light-green") }} -
+

Klaar voor de overstap?

Laat uw computer niet eindigen als e-waste. Geef hem een tweede leven met Linux - ik help u graag.

diff --git a/templates/linux.html b/templates/linux.html new file mode 100644 index 0000000..18eab1e --- /dev/null +++ b/templates/linux.html @@ -0,0 +1,117 @@ + + + + + + {{.Title}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{template "header" .}} + +
+
+
+

Waarom Linux?

+

Nieuw bij Linux? Geen zorgen. Linux is een betrouwbaar en eenvoudig computersysteem dat uw computer vaak weer prettig laat werken, zonder dat u ervoor hoeft te betalen. U kunt blijven doen wat u gewend bent: internetten, e-mailen, foto’s bekijken, videobellen en bankieren. Hieronder vindt u een korte uitleg en voorbeelden in beeld.

+
+
+ +
+
+

Rustig overstappen naar Linux

+
+
+
+ GNOME desktop op Linux +
+ GNOME desktop. Bron: iFixit +
+
+
+
+

Bekende bediening

+

Menu, vensters, bureaublad: het werkt zoals u verwacht. U kunt direct aan de slag.

+

Wat u dagelijks nodig hebt

+

Internet, e-mail, videobellen, foto’s beheren, bankieren en documenten maken: het kan allemaal. Veel vertrouwde apps zijn beschikbaar en er zijn goede alternatieven voor Windows-programma’s. Ik help u stap voor stap op weg.

+
+
+
+
+ + {{template "benefits" (dict "Page" . "SectionClass" "section--light-green") }} + +
+
+

Welke Linux past bij u?

+

Niet iedereen hoeft alle keuzes te zien. Daarom drie eenvoudige opties om mee te beginnen.

+
+
+ Linux Mint +

Linux Mint

+

Heel vertrouwd voor overstappers. Lijkt qua bediening op Windows en werkt stabiel.

+
+
+ Ubuntu +

Ubuntu LTS

+

Veelgebruikt en jarenlang ondersteund. Geschikt voor allerlei toepassingen.

+
+
+ Elementary OS +

Elementary OS

+

Rustig en overzichtelijk, met een eenvoudig ontwerp dat prettig oogt.

+
+
+

Wilt u later meer ontdekken? Er bestaan nog veel andere varianten zoals Fedora, Pop!_OS of Garuda Linux, ideaal voor wie graag experimenteert of speciale wensen heeft.

+
+
+ + {{template "linux_features" (dict "Page" . "SectionClass" "section--light-green") }} + +
+
+

Klaar voor de overstap?

+

Laat uw computer niet eindigen als e-waste. Geef hem een tweede leven met Linux - ik help u graag.

+ Neem contact op +
+
+
+ + {{template "footer" .}} + + + + diff --git a/templates/over-mij.html b/templates/over-mij.html index ad81157..be1a2a5 100644 --- a/templates/over-mij.html +++ b/templates/over-mij.html @@ -30,11 +30,11 @@ - - - - - + + + + + @@ -44,20 +44,20 @@ - + {{template "header" .}}
-
+

Over mij

Maak kennis met de Linux-evangelist van Het Hogeland.

-
+
@@ -66,7 +66,7 @@
- Foto van mijzelf met mijn zoontje bij grasbaanraces + Foto van mijzelf met mijn zoontje bij grasbaanraces
Ik met mijn zoontje bij de grasbaanraces (Dutch Open 2024)
@@ -85,7 +85,7 @@
- Foto van mijzelf met mijn zoontje bij grasbaanraces + Foto van mijzelf met mijn zoontje bij grasbaanraces
Ik met mijn zoontje bij de grasbaanraces (Dutch Open 2024)
diff --git a/templates/partials/benefits.html b/templates/partials/benefits.html new file mode 100644 index 0000000..6cfec75 --- /dev/null +++ b/templates/partials/benefits.html @@ -0,0 +1,43 @@ +{{define "benefits"}} + {{/* Pass SectionClass via dict: template "benefits" (dict "Page" . "SectionClass" "section--light") */}} + {{ $sectionClass := "section--light" }} + {{ with index . "SectionClass" }}{{ $sectionClass = . }}{{ end }} +
+ +
+{{end}} + diff --git a/templates/partials/linux_features.html b/templates/partials/linux_features.html new file mode 100644 index 0000000..0da200f --- /dev/null +++ b/templates/partials/linux_features.html @@ -0,0 +1,43 @@ +{{define "linux_features"}} + {{ $sectionClass := "section--light-green" }} + {{ with index . "SectionClass" }}{{ $sectionClass = . }}{{ end }} +
+
+

Linux in actie

+

Zie hoe Linux eruitziet en werkt in de praktijk

+
+
+
+ Zorin OS 17 Desktop +
+ Bron: DebugPoint.com +
+
+

Moderne desktopinterface

+

Ziet er vertrouwd uit, werkt snel en stabiel. Ideaal voor dagelijks gebruik.

+
+
+
+ Linux Mint Softwarebeheer +
+ Bron: LinuxMint.com +
+
+

Eenvoudig software installeren

+

Duizenden gratis programma’s met één klik via Softwarebeheer.

+
+
+ +

Gamingprestaties

+

Prima geschikt voor gaming dankzij moderne drivers en optimalisaties.

+
+
+
+
+{{end}} +