Telegram bot contact intergratie
This commit is contained in:
@ -19,6 +19,38 @@ The application supports the following environment variables:
|
||||
| `KVK` | `12345678` | KVK number for contact information |
|
||||
| `EMAIL` | `info@hogelandlinux.nl` | Contact email address |
|
||||
| `PHONE` | `+31 6 12345678` | Contact phone number |
|
||||
| `TELEGRAM_BOT_TOKEN` | *(empty)* | Telegram bot token for contact form notifications |
|
||||
| `TELEGRAM_CHAT_ID` | *(empty)* | Telegram chat ID where notifications will be sent |
|
||||
|
||||
## Telegram Integration Setup (Optional)
|
||||
|
||||
The contact form can send notifications to a Telegram chat. To set this up:
|
||||
|
||||
### 1. Create a Telegram Bot
|
||||
|
||||
1. Message [@BotFather](https://t.me/BotFather) on Telegram
|
||||
2. Send `/newbot` command
|
||||
3. Follow the instructions to create your bot
|
||||
4. Copy the bot token (looks like `123456789:ABCdefGHIjklMNOpqrsTUVwxyz`)
|
||||
|
||||
### 2. Get Your Chat ID
|
||||
|
||||
1. Add your bot to the chat where you want notifications
|
||||
2. Send a message to the bot in that chat
|
||||
3. Visit `https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates`
|
||||
4. Look for the `chat.id` field in the response
|
||||
5. Copy the chat ID (can be positive or negative number)
|
||||
|
||||
### 3. Configure Environment Variables
|
||||
|
||||
Set the following environment variables in your deployment:
|
||||
|
||||
```bash
|
||||
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
|
||||
TELEGRAM_CHAT_ID=123456789
|
||||
```
|
||||
|
||||
**Note:** If these variables are not set, the contact form will still work but won't send Telegram notifications.
|
||||
|
||||
## Coolify Deployment Steps
|
||||
|
||||
@ -52,8 +84,12 @@ COMPANY_NAME=Hogeland Linux
|
||||
KVK=12345678
|
||||
EMAIL=info@hogelandlinux.nl
|
||||
PHONE=+31 6 12345678
|
||||
TELEGRAM_BOT_TOKEN=your_bot_token_here
|
||||
TELEGRAM_CHAT_ID=your_chat_id_here
|
||||
```
|
||||
|
||||
**Note:** The Telegram variables are optional. If not set, the contact form will work but won't send notifications.
|
||||
|
||||
### 5. Configure Domain
|
||||
|
||||
- Set your desired domain/subdomain
|
||||
|
@ -59,7 +59,7 @@ Phone: "+31 6 12345678", // Uw telefoonnummer
|
||||
## Pagina's
|
||||
|
||||
### Hoofdpagina (/)
|
||||
- Hero sectie met animeerde terminal demo
|
||||
- Hero sectie met duidelijke call-to-action
|
||||
- Voordelen van Linux migratie
|
||||
- Informatie over Windows 10 End of Life
|
||||
- Linux distributies showcase met aanbevelingen
|
||||
@ -81,12 +81,12 @@ Het design is:
|
||||
- **Responsive**: Werkt op desktop, tablet en mobiel
|
||||
- **Professioneel**: Vertrouwen opwekkend voor bedrijven
|
||||
- **Eco-vriendelijk**: Groene kleurenpalet die duurzaamheid benadrukt
|
||||
- **Tech-georiënteerd**: Linux terminal demo en visuele mockups
|
||||
- **Tech-georiënteerd**: Visuele mockups en functionaliteit demonstraties
|
||||
|
||||
## Technische Features
|
||||
|
||||
### Visual Elements
|
||||
- **Animeerde Terminal**: Realistische Arch Linux terminal met pacman en fastfetch
|
||||
- **Clean Design**: Moderne en professionele interface zonder technische complexiteit
|
||||
- **Distro Showcase**: 6 populaire Linux distributies met doelgroepen
|
||||
- **Desktop Mockups**: Visuele representaties van Linux interfaces
|
||||
- **Performance Vergelijkingen**: Grafische weergave van Linux vs Windows prestaties
|
||||
|
@ -11,4 +11,6 @@ services:
|
||||
- KVK=12345678
|
||||
- EMAIL=info@hogelandlinux.nl
|
||||
- PHONE=+31 6 12345678
|
||||
- TELEGRAM_BOT_TOKEN= # Set your Telegram bot token here
|
||||
- TELEGRAM_CHAT_ID= # Set your Telegram chat ID here
|
||||
restart: unless-stopped
|
239
main.go
239
main.go
@ -1,28 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Configuration holds all website configuration
|
||||
type Config struct {
|
||||
CompanyName string
|
||||
KVK string
|
||||
Email string
|
||||
Phone string
|
||||
Port string
|
||||
CompanyName string
|
||||
KVK string
|
||||
Email string
|
||||
Phone string
|
||||
Port string
|
||||
TelegramBotToken string
|
||||
TelegramChatID string
|
||||
}
|
||||
|
||||
// PageData holds data for template rendering
|
||||
type PageData struct {
|
||||
CompanyName string
|
||||
Title string
|
||||
KVK string
|
||||
Email string
|
||||
Phone string
|
||||
Config
|
||||
Title string
|
||||
CurrentYear int
|
||||
ErrorMessage string
|
||||
SuccessMessage string
|
||||
FormData ContactForm
|
||||
}
|
||||
|
||||
// ContactForm holds form data
|
||||
type ContactForm struct {
|
||||
Name string
|
||||
Email string
|
||||
Phone string
|
||||
Computer string
|
||||
Service string
|
||||
Message string
|
||||
}
|
||||
|
||||
// Server holds the application state
|
||||
@ -31,6 +51,13 @@ type Server struct {
|
||||
templates *template.Template
|
||||
}
|
||||
|
||||
// Rate limiting
|
||||
var (
|
||||
mu sync.Mutex
|
||||
lastSubmissionTime = make(map[string]time.Time)
|
||||
submissionCooldown = 5 * time.Minute
|
||||
)
|
||||
|
||||
// getEnv returns environment variable or default value
|
||||
func getEnv(key, defaultValue string) string {
|
||||
if value := os.Getenv(key); value != "" {
|
||||
@ -43,11 +70,13 @@ func getEnv(key, defaultValue string) string {
|
||||
func NewServer() *Server {
|
||||
// Configuration - can be overridden with environment variables
|
||||
config := Config{
|
||||
CompanyName: getEnv("COMPANY_NAME", "Hogeland Linux"),
|
||||
KVK: getEnv("KVK", "12345678"), // Replace with actual KVK number
|
||||
Email: getEnv("EMAIL", "info@hogelandlinux.nl"),
|
||||
Phone: getEnv("PHONE", "+31 6 12345678"),
|
||||
Port: ":" + getEnv("PORT", "8080"),
|
||||
CompanyName: getEnv("COMPANY_NAME", "Hogeland Linux"),
|
||||
KVK: getEnv("KVK", "12345678"), // Replace with actual KVK number
|
||||
Email: getEnv("EMAIL", "info@hogelandlinux.nl"),
|
||||
Phone: getEnv("PHONE", "+31 6 12345678"),
|
||||
Port: ":" + getEnv("PORT", "8080"),
|
||||
TelegramBotToken: getEnv("TELEGRAM_BOT_TOKEN", ""), // Set this in environment
|
||||
TelegramChatID: getEnv("TELEGRAM_CHAT_ID", ""), // Set this in environment
|
||||
}
|
||||
|
||||
// Parse templates with error handling
|
||||
@ -65,11 +94,9 @@ func NewServer() *Server {
|
||||
// createPageData creates PageData with the given title
|
||||
func (s *Server) createPageData(title string) PageData {
|
||||
return PageData{
|
||||
CompanyName: s.config.CompanyName,
|
||||
Config: s.config,
|
||||
Title: title,
|
||||
KVK: s.config.KVK,
|
||||
Email: s.config.Email,
|
||||
Phone: s.config.Phone,
|
||||
CurrentYear: time.Now().Year(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,9 +117,183 @@ func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// contactHandler handles the contact page
|
||||
func (s *Server) contactHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := s.createPageData("Contact - " + s.config.CompanyName)
|
||||
|
||||
if r.Method == "POST" {
|
||||
s.handleContactForm(w, r, &data)
|
||||
return
|
||||
}
|
||||
|
||||
s.renderTemplate(w, "contact.html", data)
|
||||
}
|
||||
|
||||
// handleContactForm processes the contact form submission
|
||||
func (s *Server) handleContactForm(w http.ResponseWriter, r *http.Request, data *PageData) {
|
||||
// Get client IP for rate limiting
|
||||
ip := getClientIP(r)
|
||||
|
||||
// Check rate limiting
|
||||
mu.Lock()
|
||||
if lastTime, exists := lastSubmissionTime[ip]; exists {
|
||||
if time.Since(lastTime) < submissionCooldown {
|
||||
mu.Unlock()
|
||||
data.ErrorMessage = "U heeft recent al een bericht verstuurd. Probeer het over een paar minuten opnieuw."
|
||||
s.renderTemplate(w, "contact.html", *data)
|
||||
return
|
||||
}
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
// Parse form data
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
log.Printf("Error parsing form: %v", err)
|
||||
data.ErrorMessage = "Er is een fout opgetreden bij het verwerken van uw bericht."
|
||||
s.renderTemplate(w, "contact.html", *data)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract form data
|
||||
form := ContactForm{
|
||||
Name: strings.TrimSpace(r.FormValue("name")),
|
||||
Email: strings.TrimSpace(r.FormValue("email")),
|
||||
Phone: strings.TrimSpace(r.FormValue("phone")),
|
||||
Computer: strings.TrimSpace(r.FormValue("computer")),
|
||||
Service: strings.TrimSpace(r.FormValue("service")),
|
||||
Message: strings.TrimSpace(r.FormValue("message")),
|
||||
}
|
||||
|
||||
// Store form data for re-rendering on error
|
||||
data.FormData = form
|
||||
|
||||
// Validate required fields
|
||||
if form.Name == "" || form.Email == "" || form.Message == "" {
|
||||
data.ErrorMessage = "Vul alle verplichte velden in (naam, email, bericht)."
|
||||
s.renderTemplate(w, "contact.html", *data)
|
||||
return
|
||||
}
|
||||
|
||||
// Send to Telegram if configured
|
||||
if s.config.TelegramBotToken != "" && s.config.TelegramChatID != "" {
|
||||
err := s.sendToTelegram(form)
|
||||
if err != nil {
|
||||
log.Printf("Error sending message to Telegram: %v", err)
|
||||
data.ErrorMessage = "Er is een fout opgetreden bij het versturen van uw bericht. Probeer het later opnieuw."
|
||||
s.renderTemplate(w, "contact.html", *data)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Update last submission time on success
|
||||
mu.Lock()
|
||||
lastSubmissionTime[ip] = time.Now()
|
||||
mu.Unlock()
|
||||
|
||||
// On success, render success message
|
||||
data.SuccessMessage = "Bedankt voor uw bericht! Wij nemen zo snel mogelijk contact met u op."
|
||||
data.FormData = ContactForm{} // Clear form data
|
||||
s.renderTemplate(w, "contact.html", *data)
|
||||
}
|
||||
|
||||
// sendToTelegram sends the contact form data to Telegram
|
||||
func (s *Server) sendToTelegram(form ContactForm) error {
|
||||
// Format message
|
||||
message := fmt.Sprintf(
|
||||
"🔔 Nieuw contactformulier\n\n"+
|
||||
"👤 *Naam:* %s\n"+
|
||||
"📧 *Email:* %s\n"+
|
||||
"📞 *Telefoon:* %s\n"+
|
||||
"💻 *Computer:* %s\n"+
|
||||
"🛠️ *Service:* %s\n\n"+
|
||||
"💬 *Bericht:*\n%s",
|
||||
escapeMarkdown(form.Name),
|
||||
escapeMarkdown(form.Email),
|
||||
escapeMarkdown(form.Phone),
|
||||
escapeMarkdown(form.Computer),
|
||||
escapeMarkdown(form.Service),
|
||||
escapeMarkdown(form.Message),
|
||||
)
|
||||
|
||||
// Prepare Telegram API request
|
||||
telegramURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", s.config.TelegramBotToken)
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"chat_id": s.config.TelegramChatID,
|
||||
"text": message,
|
||||
"parse_mode": "Markdown",
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal JSON: %v", err)
|
||||
}
|
||||
|
||||
// Send HTTP request
|
||||
resp, err := http.Post(telegramURL, "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send HTTP request: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
bodyBytes, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("Telegram API error: %s, Status Code: %d", string(bodyBytes), resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// escapeMarkdown escapes special characters for Telegram Markdown
|
||||
func escapeMarkdown(text string) string {
|
||||
if text == "" {
|
||||
return "N/A"
|
||||
}
|
||||
// Escape special Markdown characters
|
||||
replacer := strings.NewReplacer(
|
||||
"*", "\\*",
|
||||
"_", "\\_",
|
||||
"`", "\\`",
|
||||
"[", "\\[",
|
||||
"]", "\\]",
|
||||
"(", "\\(",
|
||||
")", "\\)",
|
||||
"~", "\\~",
|
||||
">", "\\>",
|
||||
"#", "\\#",
|
||||
"+", "\\+",
|
||||
"-", "\\-",
|
||||
"=", "\\=",
|
||||
"|", "\\|",
|
||||
"{", "\\{",
|
||||
"}", "\\}",
|
||||
".", "\\.",
|
||||
"!", "\\!",
|
||||
)
|
||||
return replacer.Replace(text)
|
||||
}
|
||||
|
||||
// getClientIP extracts the client IP address from the request
|
||||
func getClientIP(r *http.Request) string {
|
||||
// Check X-Forwarded-For header first (for reverse proxies)
|
||||
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
||||
// X-Forwarded-For can contain multiple IPs, take the first one
|
||||
if idx := strings.Index(xff, ","); idx != -1 {
|
||||
return strings.TrimSpace(xff[:idx])
|
||||
}
|
||||
return strings.TrimSpace(xff)
|
||||
}
|
||||
|
||||
// Check X-Real-IP header
|
||||
if xri := r.Header.Get("X-Real-IP"); xri != "" {
|
||||
return strings.TrimSpace(xri)
|
||||
}
|
||||
|
||||
// Fall back to RemoteAddr
|
||||
if idx := strings.LastIndex(r.RemoteAddr, ":"); idx != -1 {
|
||||
return r.RemoteAddr[:idx]
|
||||
}
|
||||
return r.RemoteAddr
|
||||
}
|
||||
|
||||
// healthHandler provides a simple health check endpoint
|
||||
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
184
static/style.css
184
static/style.css
@ -146,10 +146,10 @@ p {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-content h2 {
|
||||
@ -169,100 +169,6 @@ p {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.hero-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Terminal Window Styling */
|
||||
.terminal-window {
|
||||
background: #1a1a1a;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
||||
max-width: 520px;
|
||||
margin: 0 auto 0 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
.terminal-header {
|
||||
background: #2d2d2d;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.terminal-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.terminal-buttons span {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
background: #ff5f57;
|
||||
}
|
||||
|
||||
.btn-minimize {
|
||||
background: #ffbd2e;
|
||||
}
|
||||
|
||||
.btn-maximize {
|
||||
background: #28ca42;
|
||||
}
|
||||
|
||||
.terminal-title {
|
||||
color: #ccc;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
padding: 20px;
|
||||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.terminal-line {
|
||||
margin-bottom: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
color: #10b981;
|
||||
font-weight: 600;
|
||||
min-width: 180px;
|
||||
}
|
||||
|
||||
.command {
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
.output {
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
color: #10b981;
|
||||
animation: blink 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0%, 50% { opacity: 1; }
|
||||
51%, 100% { opacity: 0; }
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
padding: 12px 24px;
|
||||
@ -872,6 +778,33 @@ p {
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Alert Styles */
|
||||
.alert {
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 1px solid;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.alert-error {
|
||||
background-color: #fef2f2;
|
||||
color: #dc2626;
|
||||
border-color: #fecaca;
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-color: #f0fdf4;
|
||||
color: #16a34a;
|
||||
border-color: #bbf7d0;
|
||||
}
|
||||
|
||||
.alert strong {
|
||||
font-weight: 600;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
@ -1015,12 +948,6 @@ footer {
|
||||
padding: 3rem 0;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-content h2 {
|
||||
font-size: 2.5rem;
|
||||
line-height: 1.2;
|
||||
@ -1036,19 +963,6 @@ footer {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.terminal-window {
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
padding: 16px;
|
||||
font-size: 13px;
|
||||
min-height: 180px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.benefits-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
@ -1154,22 +1068,6 @@ footer {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.terminal-window {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
min-height: 160px;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
min-width: 120px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* Card padding adjustments */
|
||||
.benefit-card, .service-card, .distro-card, .cta-benefit {
|
||||
padding: 1.25rem;
|
||||
@ -1266,23 +1164,12 @@ footer {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hero-content h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.terminal-window {
|
||||
max-height: 250px;
|
||||
overflow-y: auto;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1296,11 +1183,6 @@ footer {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.terminal-body {
|
||||
font-size: 11px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.benefit-card, .service-card, .distro-card, .cta-benefit {
|
||||
padding: 1rem;
|
||||
}
|
||||
@ -1313,9 +1195,7 @@ footer {
|
||||
|
||||
/* High DPI screens */
|
||||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
|
||||
.terminal-body {
|
||||
font-size: 13px;
|
||||
}
|
||||
/* No terminal-specific styles needed */
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
|
@ -79,42 +79,55 @@
|
||||
|
||||
<div class="contact-form">
|
||||
<h2>Stuur een bericht</h2>
|
||||
<form action="#" method="POST">
|
||||
|
||||
{{if .ErrorMessage}}
|
||||
<div class="alert alert-error">
|
||||
<strong>❌ Fout:</strong> {{.ErrorMessage}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .SuccessMessage}}
|
||||
<div class="alert alert-success">
|
||||
<strong>✅ Gelukt:</strong> {{.SuccessMessage}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<form action="/contact" method="POST">
|
||||
<div class="form-group">
|
||||
<label for="name">Naam *</label>
|
||||
<input type="text" id="name" name="name" required>
|
||||
<input type="text" id="name" name="name" value="{{.FormData.Name}}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email *</label>
|
||||
<input type="email" id="email" name="email" required>
|
||||
<input type="email" id="email" name="email" value="{{.FormData.Email}}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="phone">Telefoon</label>
|
||||
<input type="tel" id="phone" name="phone">
|
||||
<input type="tel" id="phone" name="phone" value="{{.FormData.Phone}}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="computer">Huidige computer</label>
|
||||
<input type="text" id="computer" name="computer" placeholder="Bijv. Dell Inspiron 2015, HP Pavilion 2018">
|
||||
<input type="text" id="computer" name="computer" value="{{.FormData.Computer}}" placeholder="Bijv. Dell Inspiron 2015, HP Pavilion 2018">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="service">Gewenste service</label>
|
||||
<select id="service" name="service">
|
||||
<option value="">Selecteer een optie</option>
|
||||
<option value="advice">Gratis advies</option>
|
||||
<option value="installation">Linux installatie</option>
|
||||
<option value="migration">Data migratie</option>
|
||||
<option value="training">Training & ondersteuning</option>
|
||||
<option value="other">Anders</option>
|
||||
<option value="advice" {{if eq .FormData.Service "advice"}}selected{{end}}>Gratis advies</option>
|
||||
<option value="installation" {{if eq .FormData.Service "installation"}}selected{{end}}>Linux installatie</option>
|
||||
<option value="migration" {{if eq .FormData.Service "migration"}}selected{{end}}>Data migratie</option>
|
||||
<option value="training" {{if eq .FormData.Service "training"}}selected{{end}}>Training & ondersteuning</option>
|
||||
<option value="other" {{if eq .FormData.Service "other"}}selected{{end}}>Anders</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="message">Bericht *</label>
|
||||
<textarea id="message" name="message" rows="5" required placeholder="Vertel ons over uw situatie en hoe wij u kunnen helpen..."></textarea>
|
||||
<textarea id="message" name="message" rows="5" required placeholder="Vertel ons over uw situatie en hoe wij u kunnen helpen...">{{.FormData.Message}}</textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Verstuur bericht</button>
|
||||
@ -172,7 +185,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>© 2024 {{.CompanyName}}. Alle rechten voorbehouden.</p>
|
||||
<p>© {{.CurrentYear}} {{.CompanyName}}. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -12,22 +12,24 @@
|
||||
<nav class="navbar">
|
||||
<div class="nav-container">
|
||||
<div class="nav-logo">
|
||||
<h1><a href="/">Hogeland Linux</a></h1>
|
||||
<h1><a href="/">{{.CompanyName}}</a></h1>
|
||||
</div>
|
||||
<div class="nav-links">
|
||||
<a href="/">Home</a>
|
||||
<a href="/" class="active">Home</a>
|
||||
<a href="#voordelen">Voordelen</a>
|
||||
<a href="#distros">Linux Keuze</a>
|
||||
<a href="#diensten">Diensten</a>
|
||||
<a href="/contact">Contact</a>
|
||||
<a href="#services">Diensten</a>
|
||||
<a href="#distros">Distributies</a>
|
||||
</div>
|
||||
<button class="mobile-menu-toggle" onclick="toggleMobileMenu()">
|
||||
<span>☰</span>
|
||||
</button>
|
||||
<div class="mobile-menu" id="mobile-menu">
|
||||
<a href="/">Home</a>
|
||||
<a href="/" class="active">Home</a>
|
||||
<a href="#voordelen">Voordelen</a>
|
||||
<a href="#distros">Linux Keuze</a>
|
||||
<a href="#diensten">Diensten</a>
|
||||
<a href="/contact">Contact</a>
|
||||
<a href="#services">Diensten</a>
|
||||
<a href="#distros">Distributies</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@ -43,47 +45,6 @@
|
||||
<a href="/contact" class="btn btn-secondary">Gratis advies</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="hero-image">
|
||||
<div class="terminal-window">
|
||||
<div class="terminal-header">
|
||||
<div class="terminal-buttons">
|
||||
<span class="btn-close"></span>
|
||||
<span class="btn-minimize"></span>
|
||||
<span class="btn-maximize"></span>
|
||||
</div>
|
||||
<div class="terminal-title">Terminal</div>
|
||||
</div>
|
||||
<div class="terminal-body">
|
||||
<div class="terminal-line">
|
||||
<span class="prompt">ainrommer@computer:~$</span>
|
||||
<span class="command">sudo pacman -Syu</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="output">:: Synchronizing package databases...</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="output">✓ Everything is up to date.</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="prompt">ainrommer@computer:~$</span>
|
||||
<span class="command">fastfetch</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="output">🔥 Garuda Linux (Dragonized Gaming)</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="output">🐧 Linux 6.11.2-zen1-1-zen</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="output">💾 8.2 GiB / 16.0 GiB (51%)</span>
|
||||
</div>
|
||||
<div class="terminal-line">
|
||||
<span class="prompt">ainrommer@computer:~$</span>
|
||||
<span class="cursor">_</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</section>
|
||||
|
||||
<section id="voordelen" class="benefits">
|
||||
@ -166,7 +127,9 @@
|
||||
<div class="distros-grid">
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🐧</div>
|
||||
<div class="distro-logo">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEiUlEQVR4nO1ZXWgcVRQeVNAna0Xw3tSaB/viQ6EP6ltMobXN3EmsRkpDraVCaSISsbV/YrE0P+CDtJuIPpX0xUIxaaRVUBRbX6q2D0piEOKDm02Zu5P9S5Z2/5LtHDl3kmUnO7tzZzO7bWEPHHZnmLnzffeev3uuojSkIQ1Zs8Bp5ZGw9uwrOqMndUbHdEYnuUoSXCW5ZU3gPZ3RUXwGn8V3lPstkZ3PUF2lA5yRWc4oeFKVhPBdHKPuwEPa8+u5SoY4IxnPwEuUZHCs4K7mp+oCnjPSqTM6t3bgdtVVauDYNQMOu5VHrVn3FzgvXZEAfstX8MHW5ie4SsZrD56u+Mc4ftMX8DgbGD3qBp4VSFyBVuWxNRPw22zCWhNEDr0qlGsb3EicWxt4Rjr9Bp/75xasSG7qprhX7nmdUVPX6JtVgU9sX79OZ5T7SSDSsxVWSwRXwiU6Ydj2PvsqGfYM8vWNMP9ZD6R//RbyPAhmJgVmNg15IwQLgSMQ/2RPKYGeygSWTWnIE3jMjtUkqehhDcA0wUnyxizM7dsifgsmNHnD3Q+EkoynjG2VB5LAtSa4c/FzMPZuFtepny5BOUlfGwNj3xZYGD4GicGDkuALpjQgBR6LLKxTZAe+880XFrjr4+La2PMi3JuPlCWRn7sNqR8vCk1eGPRCYEaqAMRKUXbQ+Kkum8kkzuy3TKl3hzCncOcLQqNH2uHu1REwlxZLCMVPvyNvpip5yd18GD0pNVj7c7CkB21gctN/AW8vbxbR3tcgHzfsKxKegfCuZrlV0OgJGQJjMoMl+g7YgJiLOYi+v83d0Xt3lKxEov9dOQKMjroTUOnfFTNoT6tw3IXhozYQd6+clzaF1Hcjdue+Pi5LYNKVAFdJzDWDTv4Gc3s3C4dckeiHTJoA+kSxLIWmZX0gKkMgJ5NBMRSmfvi6cB1+a5O8M1atJFsdge5WBwJHRSh8EAnEHE1o6mYBbHbihkhcNhM6rEkDidXShHRXJ8YyuAnmh4/ZnfjqiLwTf3+hdk6sy4bRM/ttIDA0Ypx3ey/6wU6A1WG074CPYVQ2kWkbYEn/zwYke+tn4KypIvh7qxMZD8onMpUe97eUwPJ4uZTARBZ5b6t1/1SXsHN0bNTYRx2W2TiVEp++7W8p4bmYuzQkgCTP94nryKEWMHPZEqCFGTdmRfhFTY4M+F/MeS6nGYXkVx+L2oh3bITF6T/Lgk//Mir2BJhD5gcPVtxOOhDoV2q9oUl+eaLCzIesDU1R6M1N/SFJwuOGpupuRAduKbshfe2ycHCxpcykRMVpbSm7SohFsLZyJxBQvEqs7eknfd/UO2T0SHeLm+kYVfdNl/ugpl8EVmf03NTv7m0Vlb5RFfgiEgE/V6GQ0btbXO1fV+lZ5aFuLe72qcn7b9umx+vZ3NVVehm/qdSgvX7OT5/gzjZ/1vf2erFgr9I6jPB91o2q+6BeBcOar0dMjATqdsTkcMjX76V2KprxGXz3vhzyORaAbeRl7NtYEYtMcEbihWNW/M/IhDhmVelxrCofiGPWhjREefjlf0AT6pAJW8ezAAAAAElFTkSuQmCC" alt="ubuntu--v1">
|
||||
</div>
|
||||
<h3>Ubuntu</h3>
|
||||
<span class="distro-tag">Populair</span>
|
||||
</div>
|
||||
@ -181,7 +144,11 @@
|
||||
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🍃</div>
|
||||
<div class="distro-logo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="48" height="48" viewBox="0 0 48 48">
|
||||
<path fill="#c5e1a5" d="M21.5,44C13.492,44,7,37.508,7,29.5V18H2V4h29.031C39.298,4,46,10.702,46,18.969V44H21.5z"></path><path fill="#689f38" d="M30.031,8H6v6h2c1.657,0,3,1.343,3,3v0v11.5C11,34.851,16.149,40,22.5,40H38c2.209,0,4-1.791,4-4 V19.969C42,13.359,36.641,8,30.031,8z"></path><path fill="#fff" d="M33.5,15c-1.577,0-2.996,0.672-4,1.74c-1.004-1.069-2.423-1.74-4-1.74c-3.033,0-5.5,2.473-5.5,5.512 V28h3v-7.488c0-1.381,1.122-2.505,2.5-2.505S28,19.13,28,20.512V28h3v-7.488v0c0-1.381,1.122-2.505,2.5-2.505S36,19.13,36,20.512 V28.5c0,1.93-1.57,3.5-3.5,3.5h-12c-1.93,0-3.5-1.57-3.5-3.5V12h-3v16.5c0,3.584,2.916,6.5,6.5,6.5h12c3.584,0,6.5-2.916,6.5-6.5 v-7.988C39,17.472,36.533,15,33.5,15z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Linux Mint</h3>
|
||||
<span class="distro-tag">Windows-achtig</span>
|
||||
</div>
|
||||
@ -196,7 +163,9 @@
|
||||
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🚀</div>
|
||||
<div class="distro-logo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><linearGradient id="inxzwh639poeU1X9W8tTQa" x1="7.037" x2="45.033" y1="7.037" y2="45.033" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#05acb3"/><stop offset="1" stop-color="#038387"/></linearGradient><path fill="url(#inxzwh639poeU1X9W8tTQa)" d="M44,24c0,11.045-8.955,20-20,20S4,35.045,4,24S12.955,4,24,4S44,12.955,44,24z"/><linearGradient id="inxzwh639poeU1X9W8tTQb" x1="22.277" x2="31.658" y1="31.726" y2="57.724" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".472" stop-color="#dde0e2"/><stop offset="1" stop-color="#bbc1c4"/></linearGradient><path fill="url(#inxzwh639poeU1X9W8tTQb)" d="M15.5,38.5h17c1.105,0,2-0.895,2-2v0c0-1.105-0.895-2-2-2h-17c-1.105,0-2,0.895-2,2v0 C13.5,37.605,14.395,38.5,15.5,38.5z"/><linearGradient id="inxzwh639poeU1X9W8tTQc" x1="30.056" x2="40.896" y1="16.127" y2="46.17" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".472" stop-color="#dde0e2"/><stop offset="1" stop-color="#bbc1c4"/></linearGradient><path fill="url(#inxzwh639poeU1X9W8tTQc)" d="M34,16c-3-1-3.5,0.5-4,2.5c-0.618,2.473-1,7-1,8.5s1,2,2,0.5s4-6.5,4.5-8S35.956,16.652,34,16 z"/><linearGradient id="inxzwh639poeU1X9W8tTQd" x1="28.561" x2="31.626" y1="29.85" y2="38.346" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff"/><stop offset=".472" stop-color="#dde0e2"/><stop offset="1" stop-color="#bbc1c4"/></linearGradient><path fill="url(#inxzwh639poeU1X9W8tTQd)" d="M27.996,30.447c-0.642,0.833-0.433,2.571,1.067,2.589c0.938,0.011,1.584-0.887,1.509-2.029 C30.518,30.184,29.104,29.01,27.996,30.447z"/><linearGradient id="inxzwh639poeU1X9W8tTQe" x1="17.026" x2="40.638" y1="8.349" y2="73.788" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#f0f0f0"/><stop offset="1" stop-color="#fff"/></linearGradient><path fill="url(#inxzwh639poeU1X9W8tTQe)" d="M26,12c-3.056-5.239-8.399-4.379-13.366-0.748c-1.265,0.924-1.651,2.649-0.91,4.029 l8.91,16.606c0.49,0.913,1.596,1.3,2.549,0.892h0c1.006-0.431,1.479-1.591,1.059-2.602c-0.819-1.975-2.095-5.059-2.742-6.677 C23.5,22.5,29.846,18.592,26,12z M21.352,19.609c-0.515,0.303-1.907,0.452-3.239-2.812c-1.213-2.971-0.849-4.335-0.212-4.547 s1.971,0.485,3.244,3.001C22.418,17.767,21.868,19.306,21.352,19.609z"/></svg>
|
||||
</div>
|
||||
<h3>Pop!_OS</h3>
|
||||
<span class="distro-tag">Gaming</span>
|
||||
</div>
|
||||
@ -211,7 +180,9 @@
|
||||
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🎨</div>
|
||||
<div class="distro-logo">
|
||||
<img src="data:image/png;base64,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" alt="external-elementary-os-is-a-linux-distribution-based-on-ubuntu-logo-regular-tal-revivo">
|
||||
</div>
|
||||
<h3>Elementary OS</h3>
|
||||
<span class="distro-tag">Mooi</span>
|
||||
</div>
|
||||
@ -226,7 +197,9 @@
|
||||
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🔧</div>
|
||||
<div class="distro-logo">
|
||||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFU0lEQVR4nO1YWW8bVRi1gAfojLcsxWmbZnNBQoDgFyCBVAG1E8/YYydx9sQuhWeekBoJQdpCnxFCVUECBSVt9sTLzDhOkzheEloEVA2pKtpCkGhSpOy7P3Qn8XiJJ3TGdqmQj3SVaMYP59w53/m+e2WyLLLIIov/BcqaJ7QlLYEPipv97cXN/utFjb6HhQ2+zWP145tH68fmC+rGrmtqx9o11tH38+vGy2RPAt5o9T6jbQlaS1sCE6UtAShpCUBxsx+KmibgeOMEFDb44Gj9OBypG4eC2jHQ1IzC8zWjcNh6DfKqvb5cy0i1jOp8+j8hX2YPvq21hWbKbEEQSz6/egTyqkYgt9IL6krvdI7Fc/KxES+wTx06YQ9d0tpDkCr5HLQsw6A2D4PKPPzVMWriuYySL33vx8MnTgd/SDd5NRJAeUBJsZM4NZqfMfJae3A6c+Q9oDR5QGFkpnHKkZ9+26Sy81XDkEu5IYfsBxXRC2qiD1SkE9QUG0/exILCyAJOspOyeu+zaROQiufzKml47QwL3zD3YfbhOmxuh2F2fh2+dt+Dl200KI3OOPJyTgADGEl/mRbyWnvgZCrkjR/7YWl1G5JhaXUbys/6QEE64shH1iED+07qOS81KquG4fUzrCD5CBZXt+ClJhfISTqOPPcVCOZWSn1Caw/VSC1Y5HlkmwjuP1jjdltj7uf+/j63xr+75LwLePngPgG7IthKyQJKbUG/1LRBBYs8HwEirTK6UVSCknRDxVlfVNzcGmC6bgEBzLjk2SaVqERps70T5knmkb0xacOAxtTPv9vY2gFMdzWpAJykw0rKXSJaABrMUsl5laEnzuuK8u5o2pA0vPXhNf7dvb9WAdP1CAhgACfY06IF7E2VkpuUsiJBgL47GpWECz66/Av/7rJLuAb2vsJ34gU0+W+k0mETBcj1XdGoJNzwqs0Nd/5cgduzy/CKzc09ExbATIkWUNTkm3+kDmuhIcc4CCrUXQ09HHEV0c9ZJhb4qSuA67t2vV7eD7jBwdmGK16D4yDyqJAfiBZQ2Ojb+Lcm9UKjGy5euQ0//bYIK+vRvEfkEwXEFuznnTO7IkjmUde6eAEHkTc7oeHilGCT4gTokwtAWFrdAkzXlVkBB+08Ih+OJuR+AfpuzvNCX+Czjl9FfQFMioWEPI9sE7vzf8yvQe2FSThiGeB3Xl7eA3JdvIBD73YAdupqtAaSjA54Oos46XhgoTnPx5IvtjpAZXTtdtjYkThBACIvgjDE9wHmW9ECko4HxkH4+e4STwrt/C75+HkeRSUinD4BrPhGlnw86IuzD7JN4s7z83zaBNBhZYWzWLSA5ONB734BiHgCeeTvAnN01llcEZ06wBcwyYzJpCBZh1URA1zmR1DdFgQF6dx/GDE4oO58iP/djTsLgOt7pQkw0mZJApIewE0uuNAxwxObmV2GwsoBkBPOvVShOfLoGSrwCNrapwE3DIknT9A3JR9okt4emFgorXVwp6gI0MGk9nwINFQft9DOx5JfWNmC41UDgBO0BAHuN2VSIXj1QTrBei4IOwd1sj2g31R+EpC4+8wXkslzAoTubVDBVgyAtS3I7a4Q0LuqTwNiZx7YIx9I+VpFkHykYA1DnDXOfT/NFeny2jY346D/0TPONtJ2/hau8+alRD4iQJA832BQ0Q5xCYNikotKlDbomSTPM4G03copKXbxQPJpXhjyfDpv4xQmT8/jII8R9M2U0kYIcsrzotzI/J0Z8nQYdViMZCyy1tanZJmCusJVKCeZToxgFiSTJZgNjKTn0EiMDudoMJM022SRRRZZyJ5E/ANvJojABjwtUQAAAABJRU5ErkJggg==" alt="fedora">
|
||||
</div>
|
||||
<h3>Fedora</h3>
|
||||
<span class="distro-tag">Geavanceerd</span>
|
||||
</div>
|
||||
@ -241,7 +214,11 @@
|
||||
|
||||
<div class="distro-card">
|
||||
<div class="distro-header">
|
||||
<div class="distro-logo">🔥</div>
|
||||
<div class="distro-logo">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="48" height="48" viewBox="0 0 48 48">
|
||||
<path fill="#1e88e5" d="M28.465,38.611c0.419-1.105,0.664-2.365,0.664-3.714c0-4.133-2.211-7.494-4.929-7.494 c-2.741,0-4.951,3.361-4.951,7.494c0,1.326,0.221,2.586,0.641,3.669c-9.041,0.951-15.407,4.731-17.993,6.432 c4.355-6.278,8.909-13.638,13.262-22.105c1.083-2.101,2.101-4.178,3.05-6.211c0.375,0.243,0.751,0.509,1.171,0.775 c1.945,1.215,3.759,1.879,5.084,2.233c-0.973-0.73-2.033-1.613-3.116-2.697c-0.817-0.817-1.547-1.637-2.167-2.433 C21.016,10.538,22.608,6.669,24,3c2.32,6.144,5.217,12.842,8.841,19.893c2.343,4.531,4.731,8.754,7.117,12.644 c-0.685-0.375-1.437-0.73-2.233-1.039c-1.371-0.53-2.652-0.862-3.759-1.06c1.503,0.751,3.25,1.747,5.084,3.073 c1.194,0.885,2.254,1.769,3.161,2.631c0.021,0.021,0.021,0.021,0.045,0.045c1.26,2.056,2.565,3.957,3.846,5.813 C43.561,43.319,37.306,39.605,28.465,38.611z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Garuda Linux</h3>
|
||||
<span class="distro-tag">Prestaties</span>
|
||||
</div>
|
||||
@ -398,7 +375,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<p>© 2024 {{.CompanyName}}. Alle rechten voorbehouden.</p>
|
||||
<p>© {{.CurrentYear}} {{.CompanyName}}. Alle rechten voorbehouden.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@ -426,65 +403,7 @@
|
||||
});
|
||||
});
|
||||
|
||||
// Terminal animation
|
||||
const terminalBody = document.querySelector('.terminal-body');
|
||||
const lines = [
|
||||
{ type: 'prompt', content: 'ainrommer@computer ~ $' },
|
||||
{ type: 'command', content: 'neofetch', delay: 1000 },
|
||||
{ type: 'output', content: '\n .-/+oossssoo+/-.\n .:+ssssssssssssssss+:.\n -+ssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n -+ssssssssssssssssssssss+-\n-+ssssssssssssssssssssss+-\n`-+ssssssssssssssssssss+-`\n `-+ssssssssssssssssss+-`\n `-+ssssssssssssssss+-`\n `-+ssssssssssssss+-`\n `-+ssssssssssss+-`\n `-+ssssssssss+-`\n `-+ssssssss+-`\n `-+ssssss+-`\n `-+ssss+-`\n `-+ss+-`\n `-+s+-`\n `-+-`\n ``\nOS: Arch Linux x86_64\nKernel: 6.6.8-arch1-1\nUptime: 3 hours, 42 mins\nPackages: 1337 (pacman)\nShell: zsh 5.9\nResolution: 1920x1080\nDE: KDE Plasma 5.27.10\nWM: KWin\nWM Theme: Breeze\nTheme: Breeze Dark [Plasma], Breeze [GTK2/3]\nIcons: Breeze Dark [Plasma], breeze-dark [GTK2/3]\nTerminal: konsole\nCPU: AMD Ryzen 7 5800X (16) @ 3.800GHz\nGPU: NVIDIA GeForce RTX 3070\nMemory: 2847MiB / 32768MiB', delay: 2000 },
|
||||
{ type: 'prompt', content: 'ainrommer@computer ~ $' },
|
||||
{ type: 'command', content: 'sudo pacman -Syu', delay: 3000 },
|
||||
{ type: 'output', content: ':: Synchronizing package databases...\n core 174.7 KiB 623 KiB/s 00:00 [######################] 100%\n extra 1744.4 KiB 1234 KiB/s 00:01 [######################] 100%\n multilib 193.9 KiB 567 KiB/s 00:00 [######################] 100%\n:: Starting full system upgrade...\n:: Replace gtk4 with extra/gtk4? [Y/n] y\nthere is nothing to do', delay: 4000 },
|
||||
{ type: 'prompt', content: 'ainrommer@computer ~ $' },
|
||||
{ type: 'cursor', content: '', delay: 5000 }
|
||||
];
|
||||
|
||||
function typeWriter(text, element, speed = 50) {
|
||||
return new Promise((resolve) => {
|
||||
let i = 0;
|
||||
const timer = setInterval(() => {
|
||||
if (i < text.length) {
|
||||
element.textContent += text.charAt(i);
|
||||
i++;
|
||||
} else {
|
||||
clearInterval(timer);
|
||||
resolve();
|
||||
}
|
||||
}, speed);
|
||||
});
|
||||
}
|
||||
|
||||
function animateTerminal() {
|
||||
terminalBody.innerHTML = '';
|
||||
let currentDelay = 0;
|
||||
|
||||
lines.forEach((line, index) => {
|
||||
setTimeout(() => {
|
||||
const lineElement = document.createElement('div');
|
||||
lineElement.className = 'terminal-line';
|
||||
|
||||
if (line.type === 'prompt') {
|
||||
lineElement.innerHTML = '<span class="prompt">' + line.content + '</span>';
|
||||
} else if (line.type === 'command') {
|
||||
lineElement.innerHTML = '<span class="prompt">ainrommer@computer ~ $ </span><span class="command">' + line.content + '</span>';
|
||||
} else if (line.type === 'output') {
|
||||
lineElement.innerHTML = '<span class="output">' + line.content + '</span>';
|
||||
} else if (line.type === 'cursor') {
|
||||
lineElement.innerHTML = '<span class="prompt">ainrommer@computer ~ $ </span><span class="cursor">█</span>';
|
||||
}
|
||||
|
||||
terminalBody.appendChild(lineElement);
|
||||
terminalBody.scrollTop = terminalBody.scrollHeight;
|
||||
}, currentDelay);
|
||||
|
||||
currentDelay += line.delay || 0;
|
||||
});
|
||||
}
|
||||
|
||||
// Start animation when page loads
|
||||
window.addEventListener('load', () => {
|
||||
setTimeout(animateTerminal, 1000);
|
||||
});
|
||||
// Mobile menu functionality and other interactive features
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user