Anpassung
- Readme mit Beschreibug der Software - style.css mit modernerem look und HOBBYHIMMEL Farben
This commit is contained in:
parent
1bf8c6545f
commit
c39fd04b07
131
README.md
131
README.md
|
|
@ -57,6 +57,137 @@ Codierung der Ports:
|
|||
| 23 | 5 | 6 | weiß-blau | grün | 0x22-P06 |
|
||||
| 24 | 5 | 7 | weiß-blau | weiß-braun | 0x22-P07 |
|
||||
|
||||
---
|
||||
|
||||
## Software-Features
|
||||
|
||||
### 🌐 Webserver & Benutzeroberfläche
|
||||
|
||||
Das System stellt einen vollständig konfigurierbaren Webserver bereit mit folgenden Seiten:
|
||||
|
||||
- **Dashboard** (`/`) — Übersicht und Kontrolzentrum
|
||||
- **Admin-Panel** (`/admin`) — Systeminfo und Verwaltungsfunktionen
|
||||
- **Dateisystem-Manager** (`/fs.html`) — Upload, Download und Verwaltung von Dateien auf der SD
|
||||
- **Port-Konfiguration** (`/portconfig`) — Konfigurieren und Benennen der 16 RJ45-Ports
|
||||
|
||||
### 🔌 Port Management & LED-Anzeige
|
||||
|
||||
**Automatische Portüberwachung:**
|
||||
- Echtzeit-Überwachung aller 16 Ports via PCF8575 IO-Expander
|
||||
- Automatische Erkennung von korrekten/fehlerhaften Kabelverbindungen
|
||||
- Polling-Zyklus alle ~50ms
|
||||
|
||||
**NeoPixel LED-Codierung:**
|
||||
- **Grün**: Port-Zustand korrekt (Kabel richtig eingesteckt)
|
||||
- **Rot (blinkend)**: Port-Zustand falsch (Kabel falsch oder nicht eingesteckt)
|
||||
- **Aus**: Port ist deaktiviert
|
||||
|
||||
**Port-Konfiguration:**
|
||||
- Individuelle Benennung jedes Ports möglich
|
||||
- Aktivieren/Deaktivieren von Ports
|
||||
- Persistente Speicherung der Konfiguration in `portconfig.json`
|
||||
|
||||
### 📡 WiFi & Netzwerkverbindung
|
||||
|
||||
**Hauptmodi:**
|
||||
1. **Station-Modus** — Verbindung zu bestehendem WiFi-Netzwerk
|
||||
2. **Soft-AP Modus (Captive Portal)** — Fallback-Konfigurationsmodus mit SSID `EspConfig`
|
||||
|
||||
**Automatische Verbindungsverwaltung:**
|
||||
- Timeout nach 30 Sekunden bei fehlgeschlagener Verbindung
|
||||
- Automatischer Fallback zur Soft-AP (Captive Portal)
|
||||
- Auto-Reconnect alle 5 Minuten
|
||||
- LED-Rückmeldung: Blinken während Verbindungsaufbau, leuchten im AP-Modus
|
||||
|
||||
**Captive Portal:**
|
||||
- Automatische Umleitung auf Konfigurationsseite
|
||||
- Sicheres Speichern von WiFi-Credentials (XOR-Verschlüsselte Speicherung in `/wifi.dat`)
|
||||
- Validierung: Passwort 8-64 Zeichen erforderlich
|
||||
|
||||
### 💾 Dateisystem (LittleFS)
|
||||
|
||||
**Funktionen:**
|
||||
- Upload von Dateien (Drag & Drop, Mehrfach)
|
||||
- Löschen von Dateien und Ordnern (rekursiv)
|
||||
- Erstellen neuer Ordner
|
||||
- Speicherübersicht (genutzt/verfügbar/gesamt)
|
||||
- Formatierung des gesamten Filesystems möglich
|
||||
|
||||
**Sortierung:**
|
||||
- Nach Dateiname (A-Z)
|
||||
- Nach Dateigröße
|
||||
|
||||
**Vordefinierte HTML-Assets:**
|
||||
Alle HTML/CSS-Dateien sind ins Filesystem eingebunden und können über die Web-UI verwaltet werden:
|
||||
- `index.html` — Dashboard
|
||||
- `admin.html` — Admin-Panel
|
||||
- `fs.html` — Dateisystem-Manager
|
||||
- `portconfig.html` — Port-Konfiguration
|
||||
- `style.css` — Styling
|
||||
|
||||
### ⚙️ Admin & System-Funktionen
|
||||
|
||||
**Systemübersicht:**
|
||||
- Live-Laufzeit (Tage, Stunden, Minuten, Sekunden)
|
||||
- WiFi-Signalstärke (RSSI in dBm)
|
||||
- Heap-Speicher und Fragmentierung
|
||||
- Flash-Speicher (Größe, Mode, Speed)
|
||||
- CPU-Frequenz
|
||||
- Reset-Grund
|
||||
- Sketch-Build-Zeit
|
||||
- ESP Core und SDK Version
|
||||
|
||||
**Systemfunktionen:**
|
||||
- **WiFi-Reconnect** — Manuelle Neuverbindung zum Netzwerk
|
||||
- **ESP-Restart** — Neustart des Gerätes
|
||||
- **OTA-Updates** — Wireless Sketch-Updates über Arduino IDE oder PlatformIO
|
||||
|
||||
### 🔗 REST-API Endpoints
|
||||
|
||||
**Admin-Informationen:**
|
||||
- `GET /admin/renew` — Laufzeit und WiFi-Signal
|
||||
- `GET /admin/once` — Detaillierte Systeminfo
|
||||
|
||||
**Port-Verwaltung:**
|
||||
- `GET /portconfig/data` — Konfiguration aller 16 Ports (JSON)
|
||||
- `POST /portconfig` — Speichern von Port-Namen und Enable-Status
|
||||
- `GET /status/data` — Live-Status aller Ports (Name, Enable, aktueller Zustand)
|
||||
|
||||
**Dateisystem:**
|
||||
- `POST /upload` — Datei-Upload
|
||||
- `GET /format` — Filesystem formatieren
|
||||
|
||||
**Netzwerk:**
|
||||
- `GET /reconnect` — WiFi-Reconnect triggern
|
||||
|
||||
---
|
||||
|
||||
## Technische Architektur
|
||||
|
||||
### Hardware-Kommunikation
|
||||
|
||||
**I2C-Bus (Datenleitung D1/D2):**
|
||||
- PCF8575 IO-Expander @ Adresse 0x21
|
||||
- Boot-Scan aller I2C-Adressen
|
||||
|
||||
**GPIO/Schnittstellen:**
|
||||
- D6 — NeoPixel DIN (16 RGB-LEDs, 800 kHz)
|
||||
- D1 — I2C SCL (mit 10kΩ PullUp)
|
||||
- D2 — I2C SDA (mit 10kΩ PullUp)
|
||||
|
||||
**Serielle Schnittstelle:**
|
||||
- Baudrate: 115200
|
||||
- Umfangreiches Debug-Output für Troubleshooting
|
||||
|
||||
### Code-Organisation
|
||||
|
||||
Das Projekt ist in 7 Arduino-Tabs organisiert:
|
||||
- `KeyPatch.ino` — Hauptsketch und Setup
|
||||
- `Connect.ino` — WiFi-Management und Verbindungslogik
|
||||
- `Webserver.ino` — HTTP-Endpoints und Web-UI
|
||||
- `Admin.ino` — Adminpanel und Systeminfo
|
||||
- `LittleFS.ino` — Dateisystem-Verwaltung
|
||||
- `NeoPixelHandler.ino` — LED-Steuerung und Farb-Codierung
|
||||
- `Config.ino` — Port-Konfiguration und Persistierung
|
||||
|
||||
---
|
||||
|
|
|
|||
260
data/style.css
260
data/style.css
|
|
@ -1,120 +1,284 @@
|
|||
|
||||
/* For more information visit:https://fipsok.de */
|
||||
/* HOBBYHIMMEL KeyPatch - Modern CSS */
|
||||
:root {
|
||||
--color-primary: #76B043;
|
||||
--color-dark: #3F4242;
|
||||
--color-gray: #6D6E71;
|
||||
--color-light: #F5F5F5;
|
||||
--color-white: #FFFFFF;
|
||||
--border-radius: 12px;
|
||||
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
--shadow-hover: 0 6px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background-color: #87cefa;
|
||||
font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background-color: var(--color-light);
|
||||
color: var(--color-dark);
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1,h2 {
|
||||
color: #e1e1e1;
|
||||
text-shadow: 2px 2px 2px black;
|
||||
|
||||
h1, h2 {
|
||||
color: var(--color-dark);
|
||||
font-weight: 600;
|
||||
margin: 20px 0 15px 0;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
li {
|
||||
background-color: #feb1e2;
|
||||
background-color: var(--color-white);
|
||||
list-style-type: none;
|
||||
margin-bottom: 10px;
|
||||
padding: 2px 5px 1px 0;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 16px;
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
li a:first-child, li b {
|
||||
background-color: #8f05a5;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-decoration:none;
|
||||
padding: 2px 5px;
|
||||
text-shadow: 2px 2px 1px black;
|
||||
cursor:pointer;
|
||||
background-color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
color: var(--color-white);
|
||||
text-decoration: none;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: none;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
li a:first-child:hover, li b:hover {
|
||||
background-color: var(--color-dark);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
li strong {
|
||||
color: red;
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input {
|
||||
height:35px;
|
||||
font-size:14px;
|
||||
padding-left: .3em;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
padding: 10px 12px;
|
||||
border: 2px solid var(--color-gray);
|
||||
border-radius: var(--border-radius);
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(118, 176, 67, 0.1);
|
||||
}
|
||||
|
||||
label + a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 + main {
|
||||
display: flex;
|
||||
}
|
||||
width: 100%;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
aside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.2em;
|
||||
padding: 0;
|
||||
background-color: var(--color-white);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 20px;
|
||||
box-shadow: var(--shadow);
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
button {
|
||||
height:40px;
|
||||
width:130px;
|
||||
font-size:16px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
margin-top: 1em;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
box-shadow: var(--shadow);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
div button {
|
||||
background-color: #7bff97;
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-white);
|
||||
}
|
||||
|
||||
div button:hover {
|
||||
background-color: #5FA03A;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
background-color: var(--color-white);
|
||||
padding: 15px 20px;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--shadow);
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#left {
|
||||
align-items:flex-end;
|
||||
text-shadow: 0.5px 0.5px 1px #757474;
|
||||
align-items: flex-end;
|
||||
text-shadow: none;
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
#cr {
|
||||
font-weight: bold;
|
||||
cursor:pointer;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
#up {
|
||||
width: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: #fecdee;
|
||||
padding: 0.5em;
|
||||
background-color: #E8F5E9;
|
||||
padding: 15px;
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
max-width: 320px;
|
||||
border-radius: 0.5em;
|
||||
max-width: 400px;
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
box-shadow: var(--shadow);
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
.no {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form [title] {
|
||||
background-color: skyblue;
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-white);
|
||||
font-size: 1em;
|
||||
width: 120px;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
form [title]:hover {
|
||||
background-color: #5FA03A;
|
||||
}
|
||||
|
||||
form:nth-of-type(2) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
[value*=Format] {
|
||||
margin-top: 1em;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--color-white);
|
||||
border: 2px solid var(--color-primary);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
[name="group"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[name="group"] + label {
|
||||
font-size: 1.5em;
|
||||
margin-right: 5px;
|
||||
font-size: 1.1em;
|
||||
margin-right: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--color-dark);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[name="group"] + label::before {
|
||||
content: "\002610";
|
||||
}
|
||||
margin-right: 8px;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
[name="group"]:checked + label::before {
|
||||
content: '\002611\0027A5';
|
||||
content: '\002611';
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.ip {
|
||||
right: 6em;
|
||||
position: relative;
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
h1 + main {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ip {
|
||||
position: relative;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
max-width: 50vw;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.note {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,3 @@ lib_deps =
|
|||
adafruit/Adafruit NeoPixel @ ^1.11.0
|
||||
https://github.com/RobTillaart/PCF8575
|
||||
bblanchon/ArduinoJson @ ^6.21.0
|
||||
|
||||
board_build.filesystem = littlefs
|
||||
board_upload.maximum_size = 1048576
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include <PCF8575.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <ESP8266HTTPUpdateServer.h> // for web-based firmware upload
|
||||
#include <ArduinoOTA.h>
|
||||
#include <LittleFS.h>
|
||||
#include "Config.ino"
|
||||
|
|
@ -10,6 +11,7 @@
|
|||
|
||||
// Globale Deklarationen für alle Tabs
|
||||
ESP8266WebServer server(80);
|
||||
ESP8266HTTPUpdateServer httpUpdater; // provides /update endpoint
|
||||
const byte DNS_PORT = 53;
|
||||
DNSServer dnsServer;
|
||||
|
||||
|
|
@ -131,10 +133,33 @@ void setup() {
|
|||
loadPortConfig(); // Lade Port-Konfiguration
|
||||
connectWifi();
|
||||
admin();
|
||||
ArduinoOTA.onStart([]() {
|
||||
|
||||
// configure OTA service (IDE/network update)
|
||||
ArduinoOTA.setHostname("KeyPatch"); // optional, default is esp8266-[ChipID]
|
||||
ArduinoOTA.setPassword((const char *)"esp8266"); // change to a strong password or read from config
|
||||
ArduinoOTA.onStart([]() {
|
||||
Serial.println("OTA start");
|
||||
//save(); // Wenn Werte vor dem Neustart gespeichert werden sollen
|
||||
});
|
||||
ArduinoOTA.onEnd([]() {
|
||||
Serial.println("OTA end");
|
||||
});
|
||||
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
|
||||
Serial.printf("OTA progress: %u%%\r", (progress / (total / 100)));
|
||||
});
|
||||
ArduinoOTA.onError([](ota_error_t error) {
|
||||
Serial.printf("OTA Error[%u]: ", error);
|
||||
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
|
||||
// allow firmware upload via HTTP (web page)
|
||||
httpUpdater.setup(&server); // no auth
|
||||
// httpUpdater.setup(&server, "admin", "secret"); // with basic auth
|
||||
server.begin();
|
||||
|
||||
// Handler für Port-Konfiguration
|
||||
|
|
|
|||
|
|
@ -1,120 +1,284 @@
|
|||
|
||||
/* For more information visit:https://fipsok.de */
|
||||
/* HOBBYHIMMEL KeyPatch - Modern CSS */
|
||||
:root {
|
||||
--color-primary: #76B043;
|
||||
--color-dark: #3F4242;
|
||||
--color-gray: #6D6E71;
|
||||
--color-light: #F5F5F5;
|
||||
--color-white: #FFFFFF;
|
||||
--border-radius: 12px;
|
||||
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
--shadow-hover: 0 6px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background-color: #87cefa;
|
||||
font-family: 'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
background-color: var(--color-light);
|
||||
color: var(--color-dark);
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
h1,h2 {
|
||||
color: #e1e1e1;
|
||||
text-shadow: 2px 2px 2px black;
|
||||
|
||||
h1, h2 {
|
||||
color: var(--color-dark);
|
||||
font-weight: 600;
|
||||
margin: 20px 0 15px 0;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
li {
|
||||
background-color: #feb1e2;
|
||||
background-color: var(--color-white);
|
||||
list-style-type: none;
|
||||
margin-bottom: 10px;
|
||||
padding: 2px 5px 1px 0;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
margin-bottom: 12px;
|
||||
padding: 12px 16px;
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
li a:first-child, li b {
|
||||
background-color: #8f05a5;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-decoration:none;
|
||||
padding: 2px 5px;
|
||||
text-shadow: 2px 2px 1px black;
|
||||
cursor:pointer;
|
||||
background-color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
color: var(--color-white);
|
||||
text-decoration: none;
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
transition: all 0.3s ease;
|
||||
text-shadow: none;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
li a:first-child:hover, li b:hover {
|
||||
background-color: var(--color-dark);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
li strong {
|
||||
color: red;
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
input {
|
||||
height:35px;
|
||||
font-size:14px;
|
||||
padding-left: .3em;
|
||||
height: 40px;
|
||||
font-size: 14px;
|
||||
padding: 10px 12px;
|
||||
border: 2px solid var(--color-gray);
|
||||
border-radius: var(--border-radius);
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 0 0 3px rgba(118, 176, 67, 0.1);
|
||||
}
|
||||
|
||||
label + a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 + main {
|
||||
display: flex;
|
||||
}
|
||||
width: 100%;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
aside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.2em;
|
||||
padding: 0;
|
||||
background-color: var(--color-white);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 20px;
|
||||
box-shadow: var(--shadow);
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
button {
|
||||
height:40px;
|
||||
width:130px;
|
||||
font-size:16px;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
margin-top: 1em;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
box-shadow: var(--shadow);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
box-shadow: var(--shadow-hover);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
div button {
|
||||
background-color: #7bff97;
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-white);
|
||||
}
|
||||
|
||||
div button:hover {
|
||||
background-color: #5FA03A;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
background-color: var(--color-white);
|
||||
padding: 15px 20px;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: var(--shadow);
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#left {
|
||||
align-items:flex-end;
|
||||
text-shadow: 0.5px 0.5px 1px #757474;
|
||||
align-items: flex-end;
|
||||
text-shadow: none;
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
#cr {
|
||||
font-weight: bold;
|
||||
cursor:pointer;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
#up {
|
||||
width: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.note {
|
||||
background-color: #fecdee;
|
||||
padding: 0.5em;
|
||||
background-color: #E8F5E9;
|
||||
padding: 15px;
|
||||
margin-top: 1em;
|
||||
text-align: center;
|
||||
max-width: 320px;
|
||||
border-radius: 0.5em;
|
||||
max-width: 400px;
|
||||
border-radius: var(--border-radius);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
box-shadow: var(--shadow);
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
.no {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form [title] {
|
||||
background-color: skyblue;
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-white);
|
||||
font-size: 1em;
|
||||
width: 120px;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
form [title]:hover {
|
||||
background-color: #5FA03A;
|
||||
}
|
||||
|
||||
form:nth-of-type(2) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
[value*=Format] {
|
||||
margin-top: 1em;
|
||||
box-shadow: 5px 5px 5px rgba(0,0,0,0.7);
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--color-white);
|
||||
border: 2px solid var(--color-primary);
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
[name="group"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[name="group"] + label {
|
||||
font-size: 1.5em;
|
||||
margin-right: 5px;
|
||||
font-size: 1.1em;
|
||||
margin-right: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--color-dark);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
[name="group"] + label::before {
|
||||
content: "\002610";
|
||||
}
|
||||
margin-right: 8px;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
[name="group"]:checked + label::before {
|
||||
content: '\002611\0027A5';
|
||||
content: '\002611';
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.ip {
|
||||
right: 6em;
|
||||
position: relative;
|
||||
body {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
h1 + main {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ip {
|
||||
position: relative;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
max-width: 50vw;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.note {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user