Compare commits
31 Commits
v0.1.2.a.2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c52173544d | ||
|
|
a3f714b5c0 | ||
|
|
d5539d788a | ||
|
|
4f00ad57e5 | ||
| 0330ca768d | |||
| aa7cb5105f | |||
| ee998cf77a | |||
| 4e1f56802c | |||
| 0334133c78 | |||
| 16a1db487a | |||
| 37e5d1c6a1 | |||
| d483fee544 | |||
| a9ee4f8866 | |||
| c9b2be1724 | |||
| 7f06853544 | |||
| 884288a2c4 | |||
| a9d4d98c4c | |||
| 1af1d5338b | |||
| b8ff46f8af | |||
| 4d53a201b4 | |||
| 16970b0866 | |||
| edb1ada059 | |||
| e48dd33a96 | |||
| 132fb8e8e0 | |||
| 1bced7c89e | |||
| 5d7de5d9a6 | |||
| 566552ffee | |||
| d9fe4f258d | |||
| 750c35a652 | |||
| dca47ab1eb | |||
|
|
193a434b32 |
355
PLUGINS.md
Normal file
355
PLUGINS.md
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
# 📘 **ZDTT Plugin Development Guide**
|
||||||
|
|
||||||
|
*Create safe, powerful extensions for the ZDTT Terminal.*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🟦 Introduction
|
||||||
|
|
||||||
|
ZDTT supports a secure, sandboxed plugin system that allows developers to extend the terminal with custom commands.
|
||||||
|
|
||||||
|
Plugins live inside:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
A plugin is simply a Python file that:
|
||||||
|
|
||||||
|
1. Contains **no top-level executable code**
|
||||||
|
2. Defines functions or classes
|
||||||
|
3. Defines a mandatory function:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register_commands():
|
||||||
|
return { "command": callable }
|
||||||
|
```
|
||||||
|
|
||||||
|
Plugins are automatically loaded when ZDTT starts or when you run:
|
||||||
|
|
||||||
|
```
|
||||||
|
plugins reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🛡️ Plugin Security Model
|
||||||
|
|
||||||
|
ZDTT has strict safety validation to protect users from malicious plugins.
|
||||||
|
Every plugin must pass **six security layers**:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. AST Validation**
|
||||||
|
|
||||||
|
At load time, ZDTT parses the plugin using Python’s AST.
|
||||||
|
|
||||||
|
Allowed at the top level:
|
||||||
|
|
||||||
|
* Imports
|
||||||
|
* From-imports
|
||||||
|
* Function definitions
|
||||||
|
* Class definitions
|
||||||
|
* A file-level docstring
|
||||||
|
|
||||||
|
Forbidden (**causes quarantine**):
|
||||||
|
|
||||||
|
* Print statements
|
||||||
|
* Assignments
|
||||||
|
* Function calls
|
||||||
|
* Loops
|
||||||
|
* Try/except blocks
|
||||||
|
* Any executable code
|
||||||
|
* Anything that runs automatically
|
||||||
|
|
||||||
|
Example of an unsafe plugin:
|
||||||
|
|
||||||
|
```python
|
||||||
|
print("hacked!") # ❌ this will be quarantined
|
||||||
|
os.system("rm -rf /") # ❌ also quarantined
|
||||||
|
```
|
||||||
|
|
||||||
|
Unsafe plugins are moved to:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/quarantine/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. Import Trust Prompt**
|
||||||
|
|
||||||
|
Plugins may import modules:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
```
|
||||||
|
|
||||||
|
However:
|
||||||
|
**Any plugin with imports triggers a trust confirmation.**
|
||||||
|
|
||||||
|
If the user does **not** trust the plugin, it is quarantined.
|
||||||
|
|
||||||
|
If the user approves, the plugin name is added to:
|
||||||
|
|
||||||
|
```
|
||||||
|
config.json → trusted_plugins
|
||||||
|
```
|
||||||
|
|
||||||
|
Only trusted plugins may use `__import__`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. Sandboxed Execution**
|
||||||
|
|
||||||
|
Plugins run inside a restricted environment:
|
||||||
|
|
||||||
|
* Only safe builtins are exposed
|
||||||
|
* Dangerous builtins (like `exec` or `eval`) are blocked
|
||||||
|
* Imports only work for trusted plugins
|
||||||
|
* Code cannot escape the sandbox
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. register_commands() Validation**
|
||||||
|
|
||||||
|
Every plugin must define:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register_commands():
|
||||||
|
return {"name": function}
|
||||||
|
```
|
||||||
|
|
||||||
|
ZDTT verifies:
|
||||||
|
|
||||||
|
* The function exists
|
||||||
|
* The return value is a dict
|
||||||
|
* All values are callable
|
||||||
|
* Command names are valid strings
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. Protected Command Names**
|
||||||
|
|
||||||
|
Plugins **cannot override** important commands such as:
|
||||||
|
|
||||||
|
```
|
||||||
|
ssh, sudo, su, cp, mv, rm, ls, cat,
|
||||||
|
chmod, chown, history, zps, zdtt,
|
||||||
|
pip, python, python3, curl, wget
|
||||||
|
```
|
||||||
|
|
||||||
|
Attempting to override them causes quarantine.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. Runtime Registration**
|
||||||
|
|
||||||
|
Once the plugin passes all previous checks, ZDTT adds its commands to the shell environment.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
{
|
||||||
|
"weather": cmd_weather,
|
||||||
|
"hello": cmd_hello
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
These appear in autocomplete and `help`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟩 Plugin Structure
|
||||||
|
|
||||||
|
A minimal valid plugin:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
My Plugin
|
||||||
|
"""
|
||||||
|
|
||||||
|
def cmd_test(args):
|
||||||
|
print("Hello from ZDTT plugin!")
|
||||||
|
|
||||||
|
def register_commands():
|
||||||
|
return {"test": cmd_test}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟧 Arguments
|
||||||
|
|
||||||
|
ZDTT passes command arguments as a list.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
hello world how are you
|
||||||
|
```
|
||||||
|
|
||||||
|
Results in:
|
||||||
|
|
||||||
|
```python
|
||||||
|
cmd_hello(["world", "how", "are", "you"])
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟪 Example Plugin (Official)
|
||||||
|
|
||||||
|
From `example_plugin.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
Example ZDTT Plugin
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
def cmd_hello(args):
|
||||||
|
...
|
||||||
|
|
||||||
|
def cmd_weather(args):
|
||||||
|
...
|
||||||
|
|
||||||
|
def cmd_sysinfo(args):
|
||||||
|
...
|
||||||
|
|
||||||
|
def register_commands():
|
||||||
|
return {
|
||||||
|
"hello": cmd_hello,
|
||||||
|
"weather": cmd_weather,
|
||||||
|
"sysinfo": cmd_sysinfo
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
All three commands use argument lists exactly as ZDTT passes them.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟫 Installing Plugins
|
||||||
|
|
||||||
|
### **Manual Install**
|
||||||
|
|
||||||
|
Place plugin file in:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reload:
|
||||||
|
|
||||||
|
```
|
||||||
|
plugins reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Install via ZPS**
|
||||||
|
|
||||||
|
Install directly from a URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
zps install https://raw.githubusercontent.com/user/repo/plugin.py
|
||||||
|
```
|
||||||
|
|
||||||
|
ZPS will:
|
||||||
|
|
||||||
|
* Download the file
|
||||||
|
* Save it to your plugin directory
|
||||||
|
* Warn if it already exists
|
||||||
|
* Ask if you trust imports (if any)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟨 Debugging Plugins
|
||||||
|
|
||||||
|
ZDTT logs plugin errors to:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/plugin_errors.log
|
||||||
|
```
|
||||||
|
|
||||||
|
Quarantined plugins appear in:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/quarantine/
|
||||||
|
```
|
||||||
|
|
||||||
|
Reload plugins:
|
||||||
|
|
||||||
|
```
|
||||||
|
plugins reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟩 Best Practices for Plugin Developers
|
||||||
|
|
||||||
|
✔ Wrap all code inside functions
|
||||||
|
✔ Avoid imports unless required
|
||||||
|
✔ Validate arg lists
|
||||||
|
✔ Use try/except around risky operations
|
||||||
|
✔ Keep commands short and simple
|
||||||
|
✔ Document your commands
|
||||||
|
✔ Never modify global state
|
||||||
|
✔ Don’t override protected commands
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟦 Advanced Plugin Tips
|
||||||
|
|
||||||
|
### Show usage/help
|
||||||
|
|
||||||
|
```python
|
||||||
|
def cmd_calc(args):
|
||||||
|
"""Usage: calc <expression>"""
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
ZDTT automatically pulls these docstrings into the `help` system.
|
||||||
|
|
||||||
|
### Combine args into a string
|
||||||
|
|
||||||
|
```python
|
||||||
|
expr = " ".join(args)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use subprocess safely
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
subprocess.run(["ls"])
|
||||||
|
except Exception as e:
|
||||||
|
print("Error:", e)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Read files safely
|
||||||
|
|
||||||
|
Use try/except to avoid crashing the shell.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🟣 Full Plugin Template
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
Plugin Name: <your plugin>
|
||||||
|
Description: <what it does>
|
||||||
|
Author: <you>
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Optional imports (will require trust prompt)
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def cmd_example(args):
|
||||||
|
print("Example plugin working!")
|
||||||
|
|
||||||
|
def register_commands():
|
||||||
|
return {
|
||||||
|
"example": cmd_example
|
||||||
|
}
|
||||||
|
```
|
||||||
268
README.md
268
README.md
@@ -1,6 +1,266 @@
|
|||||||
# ZDTT
|
<img src="https://zdtt.zane.org/zdtt.png" width=100>
|
||||||
My lil terminal project
|
|
||||||
|
|
||||||
The terminal is designed only for debian based (arch linux support in testing) linux. It can be installed on nondebian distros but it is not reccomended and may cause issues.
|
# ZDTT Terminal
|
||||||
|
|
||||||
*ps: partly vibe coded*
|
A Python-based, Linux-first custom shell environment with plugin support, aliases, banners, and a modern command experience.
|
||||||
|
ZDTT wraps your system shell, adds its own built-in commands, and enhances your workflow instead of replacing your OS shell.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
### ✔ Command History
|
||||||
|
|
||||||
|
Up/Down arrows navigate session history using Python’s `readline` module.
|
||||||
|
|
||||||
|
### ✔ Tab Completion
|
||||||
|
|
||||||
|
Auto-complete commands and filesystem paths.
|
||||||
|
|
||||||
|
### ✔ Colorized Prompt
|
||||||
|
|
||||||
|
ZDTT provides a custom prompt with color styling.
|
||||||
|
On Linux: supports full status bar.
|
||||||
|
On macOS: status bar disabled automatically due to OS cursor fight.
|
||||||
|
|
||||||
|
### ✔ Plugin System
|
||||||
|
|
||||||
|
Python-based plugin loader with AST security checks.
|
||||||
|
Plugins can register new ZDTT commands without modifying core files.
|
||||||
|
|
||||||
|
### ✔ Custom Aliases
|
||||||
|
|
||||||
|
Aliases are loaded from `~/.zdtt/aliases` and behave identically to shell shortcuts.
|
||||||
|
|
||||||
|
### ✔ Custom Banner Support
|
||||||
|
|
||||||
|
If `~/.zdtt/banner.txt` exists, it is displayed on launch.
|
||||||
|
|
||||||
|
### ✔ Distro Detection
|
||||||
|
|
||||||
|
ZDTT detects which major family you’re on:
|
||||||
|
- Debian-based
|
||||||
|
- Arch-based
|
||||||
|
- macOS
|
||||||
|
|
||||||
|
Used to determine:
|
||||||
|
- the correct sysfetch tool
|
||||||
|
- correct default package manager names
|
||||||
|
- correct onboarding messages
|
||||||
|
|
||||||
|
### ✔ Native Shell Command Relay
|
||||||
|
|
||||||
|
If a command is not a built-in ZDTT command or plugin command, it is passed directly to your real shell (bash, zsh, etc.).
|
||||||
|
|
||||||
|
### ✔ Status Bar (Linux only)
|
||||||
|
|
||||||
|
A background thread draws a live status bar showing time and system state.
|
||||||
|
Disabled automatically on macOS.
|
||||||
|
|
||||||
|
### ✔ Built-in Commands
|
||||||
|
|
||||||
|
* `help`
|
||||||
|
* `clear`
|
||||||
|
* `about`
|
||||||
|
* `history`
|
||||||
|
* `exit`
|
||||||
|
* `quit`
|
||||||
|
* `sysfetch`
|
||||||
|
* `time`
|
||||||
|
* `statusbar color <name>`
|
||||||
|
* plus plugin commands
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Images
|
||||||
|
|
||||||
|
<img src="https://zdtt.zane.org/image.png">
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Installation
|
||||||
|
|
||||||
|
### Quick Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -O https://zdtt-sources.zane.org/install.sh && chmod +x install.sh && ./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The installer:
|
||||||
|
|
||||||
|
* Detects Debian, Arch, or macOS
|
||||||
|
* Installs Python 3 if needed
|
||||||
|
* Installs ZDTT to ~/.local/bin
|
||||||
|
* Sets up the `zdtt` command
|
||||||
|
|
||||||
|
### Manual Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ZaneThePython/ZDTT
|
||||||
|
cd ZDTT
|
||||||
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Usage
|
||||||
|
|
||||||
|
### Start ZDTT
|
||||||
|
|
||||||
|
```bash
|
||||||
|
zdtt start
|
||||||
|
```
|
||||||
|
|
||||||
|
### Management Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
zdtt update
|
||||||
|
zdtt version
|
||||||
|
zdtt github
|
||||||
|
zdtt uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 Plugin System
|
||||||
|
|
||||||
|
ZDTT supports simple Python plugins stored in:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/plugins/
|
||||||
|
```
|
||||||
|
|
||||||
|
Each plugin must define:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def register_commands():
|
||||||
|
return {"yourcmd": your_function}
|
||||||
|
```
|
||||||
|
|
||||||
|
Plugins are sandboxed using AST:
|
||||||
|
|
||||||
|
* No top-level execution allowed
|
||||||
|
* Only imports, functions, classes permitted
|
||||||
|
* Unsafe plugins are quarantined automatically
|
||||||
|
|
||||||
|
Reload plugins inside ZDTT:
|
||||||
|
|
||||||
|
```
|
||||||
|
plugins reload
|
||||||
|
```
|
||||||
|
|
||||||
|
Install via URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
zps install <url>
|
||||||
|
```
|
||||||
|
|
||||||
|
See:
|
||||||
|
|
||||||
|
* `example_plugin.py`
|
||||||
|
* `PLUGINS.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙ Configuration
|
||||||
|
|
||||||
|
### Aliases
|
||||||
|
|
||||||
|
Store aliases in:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/aliases
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create them live:
|
||||||
|
|
||||||
|
```
|
||||||
|
alias ll=ls -la
|
||||||
|
unalias ll
|
||||||
|
```
|
||||||
|
|
||||||
|
### Banner
|
||||||
|
|
||||||
|
Add a custom banner in:
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.zdtt/banner.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Status Bar Color
|
||||||
|
|
||||||
|
```
|
||||||
|
statusbar color blue
|
||||||
|
```
|
||||||
|
|
||||||
|
Colors supported:
|
||||||
|
`blue red green cyan magenta yellow white black`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🖥 Supported Systems
|
||||||
|
|
||||||
|
### ✔ Full Support
|
||||||
|
|
||||||
|
* Debian-based distros
|
||||||
|
* Arch-based distros
|
||||||
|
* macOS (Status bar disabled automatically)
|
||||||
|
|
||||||
|
### ⚠ Limited Support
|
||||||
|
|
||||||
|
Other distros can run ZDTT but:
|
||||||
|
|
||||||
|
* auto-install may not work
|
||||||
|
* sysfetch may not detect tools
|
||||||
|
* package-manager messages may be incorrect
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠 Development
|
||||||
|
|
||||||
|
ZDTT is written in Python and uses:
|
||||||
|
|
||||||
|
* `readline` for history & completion
|
||||||
|
* `threading` for status bar updates
|
||||||
|
* `ast` for plugin security
|
||||||
|
* `subprocess` for system command execution
|
||||||
|
* `os` and `shutil` for path and environment detection
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
ZDTT/
|
||||||
|
├── terminal.py
|
||||||
|
├── install.sh
|
||||||
|
├── version.txt
|
||||||
|
├── example_plugin.py
|
||||||
|
├── example_aliases
|
||||||
|
├── example_banner.txt
|
||||||
|
├── PLUGINS.md
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🤝 Contributing
|
||||||
|
|
||||||
|
PRs welcome!
|
||||||
|
ZDTT is early in development and evolving quickly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 Links
|
||||||
|
|
||||||
|
* GitHub: [https://github.com/ZaneThePython/ZDTT](https://github.com/ZaneThePython/ZDTT)
|
||||||
|
* Main site: [https://zdtt.zane.org](https://zdtt.zane.org)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💬 Notes
|
||||||
|
|
||||||
|
ZDTT is not a full standalone shell *yet* — it wraps your system shell and enhances it.
|
||||||
|
A full independent shell may come in the future.
|
||||||
|
Plugins may import Python modules, but may not execute code at import time.
|
||||||
|
|
||||||
|
---
|
||||||
|
|||||||
Binary file not shown.
26
index.html
26
index.html
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>ZDTT Terminal</title>
|
<title>ZDTT Terminal</title>
|
||||||
|
<link rel="icon" type="image/png" href="zdtt.png">
|
||||||
<link rel="stylesheet" href="styles.css">
|
<link rel="stylesheet" href="styles.css">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
@@ -12,7 +13,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<header class="hero" id="top">
|
<header class="hero" id="top">
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
<div class="brand">ZDTT</div>
|
<div class="brand">By ZaneDev</div>
|
||||||
<button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" aria-controls="primary-nav">
|
<button class="nav__toggle" type="button" aria-label="Toggle navigation" aria-expanded="false" aria-controls="primary-nav">
|
||||||
<span></span>
|
<span></span>
|
||||||
<span></span>
|
<span></span>
|
||||||
@@ -45,11 +46,11 @@
|
|||||||
<div class="hero__metrics">
|
<div class="hero__metrics">
|
||||||
<div class="metric">
|
<div class="metric">
|
||||||
<p class="metric__label">Current release</p>
|
<p class="metric__label">Current release</p>
|
||||||
<p class="metric__value">v0.1.2.a.2</p>
|
<p class="metric__value">v0.1.2.b.5</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric">
|
<div class="metric">
|
||||||
<p class="metric__label">Supported families</p>
|
<p class="metric__label">Supported families</p>
|
||||||
<p class="metric__value">Debian · Arch</p>
|
<p class="metric__value">Debian · Arch · macOS</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="metric">
|
<div class="metric">
|
||||||
<p class="metric__label">Extension slots</p>
|
<p class="metric__label">Extension slots</p>
|
||||||
@@ -68,11 +69,11 @@
|
|||||||
<div class="feature-grid">
|
<div class="feature-grid">
|
||||||
<article class="card">
|
<article class="card">
|
||||||
<h3>Smart distro detection</h3>
|
<h3>Smart distro detection</h3>
|
||||||
<p>Installer inspects <code>/etc/os-release</code>, package managers, and user overrides to keep Debian and Arch flows tight.</p>
|
<p>Installer inspects <code>/etc/os-release</code>, package managers, and user overrides to keep Debian, macOS, and Arch flows tight.</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="card">
|
<article class="card">
|
||||||
<h3>Always-on status bar</h3>
|
<h3>Always-on status bar</h3>
|
||||||
<p>Background thread renders a live status bar with branding, time, and color themes you can swap on the fly.</p>
|
<p>Background thread renders a live status bar with branding, time, and color themes you can swap on the fly. (unavailable on macOS)</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="card">
|
<article class="card">
|
||||||
<h3>Plugin-friendly core</h3>
|
<h3>Plugin-friendly core</h3>
|
||||||
@@ -90,6 +91,10 @@
|
|||||||
<h3>Graceful fallbacks</h3>
|
<h3>Graceful fallbacks</h3>
|
||||||
<p>Unsupported systems get friendly warnings, opt-in installs, and clear messaging so nothing breaks silently.</p>
|
<p>Unsupported systems get friendly warnings, opt-in installs, and clear messaging so nothing breaks silently.</p>
|
||||||
</article>
|
</article>
|
||||||
|
<article class="card">
|
||||||
|
<h3>Open source</h3>
|
||||||
|
<p>ZDTT is open source and free to use. You can find the source code on <a href="https://github.com/ZaneThePython/ZDTT">GitHub</a>.</p>
|
||||||
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<h3>Follow the prompts</h3>
|
<h3>Follow the prompts</h3>
|
||||||
<p>The script checks your distro, offers overrides, and handles both Debian (<code>apt</code>) and Arch (<code>pacman</code>) flows.</p>
|
<p>The script checks your distro, offers overrides, and handles both Debian (<code>apt</code>), Arch (<code>pacman</code>), and macOS (<code>brew</code>) flows.</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<h3>Launch <code>zdtt</code></h3>
|
<h3>Launch <code>zdtt</code></h3>
|
||||||
@@ -113,7 +118,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
<div class="callout">
|
<div class="callout">
|
||||||
<p><strong>Heads up:</strong> ZDTT is Linux-only. Non-Debian/Arch installs can continue at your own risk—warnings are built in.</p>
|
<p><strong>Heads up:</strong> ZDTT is Linux-only (with eperimental macOS support). Non-Debian/Arch installs can continue at your own risk—warnings are built in.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -157,14 +162,15 @@ Traceback (most recent call last):
|
|||||||
<p>ZDTT thrives on experimentation. Fork it, vibe with it, file PRs, or just send screenshots.</p>
|
<p>ZDTT thrives on experimentation. Fork it, vibe with it, file PRs, or just send screenshots.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="community__actions">
|
<div class="community__actions">
|
||||||
<a class="btn primary" href="mailto:hello@zane.org">Say hello</a>
|
<a class="btn primary" href="mailto:contact@zane.org">Contact us if issues arise</a>
|
||||||
<a class="btn ghost" href="https://github.com/" target="_blank" rel="noreferrer">View source</a>
|
<a class="btn ghost" href="https://github.com/ZaneThePython/ZDTT" target="_blank" rel="noreferrer">View source</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>© <span id="year"></span> ZDTT • Built for Debian + Arch explorers.</p>
|
<p>© <span id="year"></span> - ZBF LLC</p>
|
||||||
|
<p>ZDTT - ZaneDev's Terminal Tools</p>
|
||||||
<a href="#top">Back to top ↑</a>
|
<a href="#top">Back to top ↑</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
236
install.sh
236
install.sh
@@ -72,10 +72,20 @@ if [ -f "$BIN_DIR/zdtt" ] || [ -d "$INSTALL_DIR" ]; then
|
|||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check if running on macOS
|
||||||
|
IS_MAC=false
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
IS_MAC=true
|
||||||
|
DETECTED_DISTRO="mac"
|
||||||
|
echo -e "${GREEN}✓${NC} macOS detected"
|
||||||
|
fi
|
||||||
|
|
||||||
# Check if running on a supported Linux distribution
|
# Check if running on a supported Linux distribution
|
||||||
IS_DEBIAN=false
|
IS_DEBIAN=false
|
||||||
IS_ARCH=false
|
IS_ARCH=false
|
||||||
DETECTED_DISTRO="other"
|
if [ "$IS_MAC" = false ]; then
|
||||||
|
DETECTED_DISTRO="other"
|
||||||
|
fi
|
||||||
|
|
||||||
OS_ID=""
|
OS_ID=""
|
||||||
OS_LIKE=""
|
OS_LIKE=""
|
||||||
@@ -86,7 +96,10 @@ if [ -f /etc/os-release ]; then
|
|||||||
OS_LIKE=$(echo "${ID_LIKE:-}" | tr '[:upper:]' '[:lower:]')
|
OS_LIKE=$(echo "${ID_LIKE:-}" | tr '[:upper:]' '[:lower:]')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /etc/debian_version ]; then
|
if [ "$IS_MAC" = true ]; then
|
||||||
|
# macOS detected, skip Linux detection
|
||||||
|
:
|
||||||
|
elif [ -f /etc/debian_version ]; then
|
||||||
IS_DEBIAN=true
|
IS_DEBIAN=true
|
||||||
DETECTED_DISTRO="debian"
|
DETECTED_DISTRO="debian"
|
||||||
echo -e "${GREEN}✓${NC} Debian-based Linux detected"
|
echo -e "${GREEN}✓${NC} Debian-based Linux detected"
|
||||||
@@ -133,25 +146,35 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Detected distribution: ${DETECTED_DISTRO}"
|
echo "Detected distribution: ${DETECTED_DISTRO}"
|
||||||
read -p "Override detection? (debian/arch/other, Enter to keep): " -r USER_OVERRIDE
|
read -p "Override detection? (debian/arch/mac/other, Enter to keep): " -r USER_OVERRIDE
|
||||||
USER_OVERRIDE=$(echo "$USER_OVERRIDE" | tr '[:upper:]' '[:lower:]')
|
USER_OVERRIDE=$(echo "$USER_OVERRIDE" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
case "$USER_OVERRIDE" in
|
case "$USER_OVERRIDE" in
|
||||||
debian)
|
debian)
|
||||||
IS_DEBIAN=true
|
IS_DEBIAN=true
|
||||||
IS_ARCH=false
|
IS_ARCH=false
|
||||||
|
IS_MAC=false
|
||||||
DETECTED_DISTRO="debian"
|
DETECTED_DISTRO="debian"
|
||||||
echo "Override applied: Debian-based system selected."
|
echo "Override applied: Debian-based system selected."
|
||||||
;;
|
;;
|
||||||
arch)
|
arch)
|
||||||
IS_DEBIAN=false
|
IS_DEBIAN=false
|
||||||
IS_ARCH=true
|
IS_ARCH=true
|
||||||
|
IS_MAC=false
|
||||||
DETECTED_DISTRO="arch"
|
DETECTED_DISTRO="arch"
|
||||||
echo "Override applied: Arch-based system selected."
|
echo "Override applied: Arch-based system selected."
|
||||||
;;
|
;;
|
||||||
|
mac)
|
||||||
|
IS_DEBIAN=false
|
||||||
|
IS_ARCH=false
|
||||||
|
IS_MAC=true
|
||||||
|
DETECTED_DISTRO="mac"
|
||||||
|
echo "Override applied: macOS selected."
|
||||||
|
;;
|
||||||
other)
|
other)
|
||||||
IS_DEBIAN=false
|
IS_DEBIAN=false
|
||||||
IS_ARCH=false
|
IS_ARCH=false
|
||||||
|
IS_MAC=false
|
||||||
DETECTED_DISTRO="other"
|
DETECTED_DISTRO="other"
|
||||||
echo "Override applied: Unsupported/Other selected."
|
echo "Override applied: Unsupported/Other selected."
|
||||||
;;
|
;;
|
||||||
@@ -168,7 +191,90 @@ if ! command -v python3 &> /dev/null; then
|
|||||||
echo -e "${RED}✗${NC} Python 3 is not installed"
|
echo -e "${RED}✗${NC} Python 3 is not installed"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [ "$IS_DEBIAN" = true ]; then
|
if [ "$IS_MAC" = true ]; then
|
||||||
|
echo "Checking for Homebrew..."
|
||||||
|
BREW_PATH=""
|
||||||
|
if command -v brew &> /dev/null; then
|
||||||
|
BREW_PATH="brew"
|
||||||
|
elif [ -f "/opt/homebrew/bin/brew" ]; then
|
||||||
|
BREW_PATH="/opt/homebrew/bin/brew"
|
||||||
|
elif [ -f "/usr/local/bin/brew" ]; then
|
||||||
|
BREW_PATH="/usr/local/bin/brew"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$BREW_PATH" ]; then
|
||||||
|
echo "Installing Python 3 via Homebrew..."
|
||||||
|
$BREW_PATH install python3
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "${RED}Failed to install Python 3${NC}"
|
||||||
|
echo "Please install Python 3 manually: $BREW_PATH install python3"
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} Python 3 installed successfully"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Homebrew is not installed.${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Homebrew is required for package management on macOS."
|
||||||
|
echo ""
|
||||||
|
read -p "Would you like to install Homebrew now? (yes/no): " -r
|
||||||
|
echo ""
|
||||||
|
if [[ $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
|
||||||
|
echo "Installing Homebrew..."
|
||||||
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}✓${NC} Homebrew installed successfully"
|
||||||
|
echo ""
|
||||||
|
echo "Adding Homebrew to PATH..."
|
||||||
|
# Add Homebrew to PATH for this session
|
||||||
|
if [ -d "/opt/homebrew/bin" ]; then
|
||||||
|
export PATH="/opt/homebrew/bin:$PATH"
|
||||||
|
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||||
|
elif [ -d "/usr/local/bin" ]; then
|
||||||
|
export PATH="/usr/local/bin:$PATH"
|
||||||
|
eval "$(/usr/local/bin/brew shellenv)"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "Installing Python 3..."
|
||||||
|
brew install python3
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo -e "${RED}Failed to install Python 3${NC}"
|
||||||
|
echo "Please install Python 3 manually: brew install python3"
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}✓${NC} Python 3 installed successfully"
|
||||||
|
else
|
||||||
|
echo -e "${RED}Failed to install Homebrew${NC}"
|
||||||
|
echo "Please install Homebrew manually:"
|
||||||
|
echo " /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${RED}Python 3 is required but cannot be installed without Homebrew.${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Please install Homebrew and Python 3 manually:"
|
||||||
|
echo " /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
|
||||||
|
echo " brew install python3"
|
||||||
|
echo ""
|
||||||
|
echo "Press any key to exit..."
|
||||||
|
read -n 1 -s -r
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "$IS_DEBIAN" = true ]; then
|
||||||
echo "Installing Python 3..."
|
echo "Installing Python 3..."
|
||||||
|
|
||||||
# Update package list and install Python 3
|
# Update package list and install Python 3
|
||||||
@@ -207,6 +313,7 @@ if ! command -v python3 &> /dev/null; then
|
|||||||
echo "Please install Python 3 manually using your package manager:"
|
echo "Please install Python 3 manually using your package manager:"
|
||||||
echo " • Debian/Ubuntu: sudo apt-get install python3"
|
echo " • Debian/Ubuntu: sudo apt-get install python3"
|
||||||
echo " • Arch/Manjaro: sudo pacman -S python"
|
echo " • Arch/Manjaro: sudo pacman -S python"
|
||||||
|
echo " • macOS: brew install python3"
|
||||||
echo " • Fedora: sudo dnf install python3"
|
echo " • Fedora: sudo dnf install python3"
|
||||||
echo " • openSUSE: sudo zypper install python3"
|
echo " • openSUSE: sudo zypper install python3"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -321,9 +428,10 @@ fi
|
|||||||
|
|
||||||
# Create the zdtt wrapper script
|
# Create the zdtt wrapper script
|
||||||
cat > "$BIN_DIR/zdtt" << 'EOF'
|
cat > "$BIN_DIR/zdtt" << 'EOF'
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
#
|
#
|
||||||
# ZDTT Terminal Wrapper
|
# ZDTT Terminal Wrapper
|
||||||
|
# Compatible with both bash and zsh
|
||||||
#
|
#
|
||||||
|
|
||||||
ZDTT_DIR="$HOME/.local/share/zdtt"
|
ZDTT_DIR="$HOME/.local/share/zdtt"
|
||||||
@@ -335,6 +443,12 @@ case "$1" in
|
|||||||
python3 "$ZDTT_DIR/terminal.py"
|
python3 "$ZDTT_DIR/terminal.py"
|
||||||
;;
|
;;
|
||||||
update)
|
update)
|
||||||
|
# Check for auto-update flag
|
||||||
|
AUTO_UPDATE=false
|
||||||
|
if [[ "$2" == "--auto" ]] || [[ "$2" == "--yes" ]]; then
|
||||||
|
AUTO_UPDATE=true
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Checking for updates..."
|
echo "Checking for updates..."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -369,8 +483,16 @@ case "$1" in
|
|||||||
else
|
else
|
||||||
echo "🔔 Update available!"
|
echo "🔔 Update available!"
|
||||||
echo ""
|
echo ""
|
||||||
read -p "Do you want to update now? (yes/no): " -r
|
|
||||||
echo ""
|
# Auto-update if flag is set, otherwise prompt
|
||||||
|
if [ "$AUTO_UPDATE" = true ]; then
|
||||||
|
REPLY="yes"
|
||||||
|
echo "Auto-updating..."
|
||||||
|
echo ""
|
||||||
|
else
|
||||||
|
read -p "Do you want to update now? (yes/no): " -r
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
|
if [[ $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then
|
||||||
echo "Updating ZDTT Terminal..."
|
echo "Updating ZDTT Terminal..."
|
||||||
@@ -461,6 +583,29 @@ case "$1" in
|
|||||||
echo " • Plugin system"
|
echo " • Plugin system"
|
||||||
echo " • Native command support"
|
echo " • Native command support"
|
||||||
;;
|
;;
|
||||||
|
github)
|
||||||
|
GITHUB_URL="https://github.com/ZaneThePython/ZDTT"
|
||||||
|
echo "Opening ZDTT GitHub repository..."
|
||||||
|
|
||||||
|
# Detect platform and use appropriate command to open URL
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
# macOS
|
||||||
|
open "$GITHUB_URL"
|
||||||
|
elif command -v xdg-open &> /dev/null; then
|
||||||
|
# Linux (most distributions)
|
||||||
|
xdg-open "$GITHUB_URL"
|
||||||
|
elif command -v x-www-browser &> /dev/null; then
|
||||||
|
# Linux (Debian/Ubuntu fallback)
|
||||||
|
x-www-browser "$GITHUB_URL"
|
||||||
|
elif command -v gnome-open &> /dev/null; then
|
||||||
|
# Linux (GNOME fallback)
|
||||||
|
gnome-open "$GITHUB_URL"
|
||||||
|
else
|
||||||
|
# Fallback: print URL and let user open manually
|
||||||
|
echo "Please open this URL in your browser:"
|
||||||
|
echo "$GITHUB_URL"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ZDTT Terminal"
|
echo "ZDTT Terminal"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -469,6 +614,7 @@ case "$1" in
|
|||||||
echo " zdtt update - Check for and install updates"
|
echo " zdtt update - Check for and install updates"
|
||||||
echo " zdtt installer - Run installer (for updates/reinstall)"
|
echo " zdtt installer - Run installer (for updates/reinstall)"
|
||||||
echo " zdtt version - Display version information"
|
echo " zdtt version - Display version information"
|
||||||
|
echo " zdtt github - Open ZDTT GitHub repository"
|
||||||
echo " zdtt uninstall - Uninstall ZDTT Terminal"
|
echo " zdtt uninstall - Uninstall ZDTT Terminal"
|
||||||
echo ""
|
echo ""
|
||||||
;;
|
;;
|
||||||
@@ -484,22 +630,81 @@ if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e "${YELLOW}Warning: $HOME/.local/bin is not in your PATH${NC}"
|
echo -e "${YELLOW}Warning: $HOME/.local/bin is not in your PATH${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To use the 'zdtt' command, add the following line to your ~/.bashrc:"
|
|
||||||
|
# Detect user's default shell (not the script's shell)
|
||||||
|
# Priority: 1) Check if running in zsh, 2) Check if .zshrc exists, 3) Check $SHELL, 4) Check /etc/passwd, 5) Default to bash
|
||||||
|
SHELL_CONFIG="$HOME/.bashrc"
|
||||||
|
SHELL_NAME="bash"
|
||||||
|
|
||||||
|
# Check if running in zsh (most reliable - immediate detection)
|
||||||
|
if [[ -n "$ZSH_VERSION" ]]; then
|
||||||
|
SHELL_CONFIG="$HOME/.zshrc"
|
||||||
|
SHELL_NAME="zsh"
|
||||||
|
# Check if .zshrc exists (strong indicator user uses zsh)
|
||||||
|
elif [ -f "$HOME/.zshrc" ]; then
|
||||||
|
SHELL_CONFIG="$HOME/.zshrc"
|
||||||
|
SHELL_NAME="zsh"
|
||||||
|
# Check $SHELL environment variable
|
||||||
|
elif [[ -n "$SHELL" ]] && [[ "$SHELL" == *"zsh"* ]]; then
|
||||||
|
SHELL_CONFIG="$HOME/.zshrc"
|
||||||
|
SHELL_NAME="zsh"
|
||||||
|
# Check user's default shell from /etc/passwd
|
||||||
|
else
|
||||||
|
USER_SHELL=""
|
||||||
|
if command -v getent &> /dev/null; then
|
||||||
|
USER_SHELL=$(getent passwd "$USER" 2>/dev/null | cut -d: -f7)
|
||||||
|
elif [ -f /etc/passwd ]; then
|
||||||
|
USER_SHELL=$(grep "^$USER:" /etc/passwd 2>/dev/null | cut -d: -f7)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$USER_SHELL" ]] && [[ "$USER_SHELL" == *"zsh"* ]]; then
|
||||||
|
SHELL_CONFIG="$HOME/.zshrc"
|
||||||
|
SHELL_NAME="zsh"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Detected shell: ${SHELL_NAME}${NC}"
|
||||||
|
echo -e "Config file: ${SHELL_CONFIG}"
|
||||||
|
echo ""
|
||||||
|
echo "To use the 'zdtt' command, add the following line to your $SHELL_CONFIG:"
|
||||||
echo ""
|
echo ""
|
||||||
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
|
||||||
echo ""
|
echo ""
|
||||||
echo "Then run: source ~/.bashrc"
|
echo "Then run: source $SHELL_CONFIG"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Ask if user wants to add it automatically
|
# Ask if user wants to add it automatically
|
||||||
read -p "Would you like to add it to your ~/.bashrc now? (y/n) " -n 1 -r
|
read -p "Would you like to add it to your $SHELL_CONFIG now? (y/n) " -n 1 -r
|
||||||
echo ""
|
echo ""
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
echo "" >> "$HOME/.bashrc"
|
# Create the config file if it doesn't exist
|
||||||
echo "# Added by ZDTT Terminal installer" >> "$HOME/.bashrc"
|
if [ ! -f "$SHELL_CONFIG" ]; then
|
||||||
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$HOME/.bashrc"
|
touch "$SHELL_CONFIG"
|
||||||
echo -e "${GREEN}✓${NC} Added to ~/.bashrc"
|
fi
|
||||||
echo "Please run: source ~/.bashrc"
|
|
||||||
|
# Check if the PATH line already exists (check for various formats)
|
||||||
|
PATH_ALREADY_SET=false
|
||||||
|
if grep -q '\.local/bin' "$SHELL_CONFIG" 2>/dev/null; then
|
||||||
|
PATH_ALREADY_SET=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PATH_ALREADY_SET" = false ]; then
|
||||||
|
echo "" >> "$SHELL_CONFIG"
|
||||||
|
echo "# Added by ZDTT Terminal installer" >> "$SHELL_CONFIG"
|
||||||
|
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$SHELL_CONFIG"
|
||||||
|
echo -e "${GREEN}✓${NC} Added to $SHELL_CONFIG"
|
||||||
|
echo ""
|
||||||
|
echo "To apply the changes, run:"
|
||||||
|
echo " source $SHELL_CONFIG"
|
||||||
|
echo ""
|
||||||
|
echo "Or open a new terminal window."
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✓${NC} PATH already configured in $SHELL_CONFIG"
|
||||||
|
echo ""
|
||||||
|
echo "If 'zdtt' command is not available, run:"
|
||||||
|
echo " source $SHELL_CONFIG"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${GREEN}✓${NC} ~/.local/bin is already in your PATH"
|
echo -e "${GREEN}✓${NC} ~/.local/bin is already in your PATH"
|
||||||
@@ -515,3 +720,4 @@ echo " zdtt start"
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Press any key to exit..."
|
echo "Press any key to exit..."
|
||||||
read -n 1 -s -r
|
read -n 1 -s -r
|
||||||
|
|
||||||
|
|||||||
42
script.js
42
script.js
@@ -72,4 +72,46 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Smooth scroll for anchor links
|
||||||
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||||
|
anchor.addEventListener('click', function (e) {
|
||||||
|
const href = this.getAttribute('href');
|
||||||
|
if (href === '#' || href === '#top') return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
const target = document.querySelector(href);
|
||||||
|
if (target) {
|
||||||
|
target.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'start'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Intersection Observer for fade-in animations
|
||||||
|
const observerOptions = {
|
||||||
|
threshold: 0.1,
|
||||||
|
rootMargin: '0px 0px -50px 0px'
|
||||||
|
};
|
||||||
|
|
||||||
|
const observer = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.style.opacity = '1';
|
||||||
|
entry.target.style.transform = 'translateY(0)';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, observerOptions);
|
||||||
|
|
||||||
|
// Observe sections and cards for fade-in effect (exclude hero section)
|
||||||
|
const animatedElements = document.querySelectorAll('.section:not(.hero), .card, .metric, figure, .install-steps li');
|
||||||
|
animatedElements.forEach(el => {
|
||||||
|
el.style.opacity = '0';
|
||||||
|
el.style.transform = 'translateY(20px)';
|
||||||
|
el.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||||
|
observer.observe(el);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
340
styles.css
340
styles.css
@@ -4,12 +4,14 @@
|
|||||||
--bg: #05060a;
|
--bg: #05060a;
|
||||||
--bg-alt: #0e1018;
|
--bg-alt: #0e1018;
|
||||||
--card: #121422;
|
--card: #121422;
|
||||||
--card-border: rgba(255, 255, 255, 0.08);
|
--card-border: rgba(255, 255, 255, 0.12);
|
||||||
--text: #f5f6fd;
|
--text: #f5f6fd;
|
||||||
--muted: #9aa2c4;
|
--muted: #9aa2c4;
|
||||||
--accent: #4dd5ff;
|
--accent: #4dd5ff;
|
||||||
--accent-strong: #6d84ff;
|
--accent-strong: #6d84ff;
|
||||||
|
--accent-glow: rgba(77, 213, 255, 0.4);
|
||||||
--shadow: 0 18px 45px rgba(4, 6, 11, 0.6);
|
--shadow: 0 18px 45px rgba(4, 6, 11, 0.6);
|
||||||
|
--shadow-glow: 0 0 30px rgba(77, 213, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
*,
|
||||||
@@ -18,15 +20,43 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: radial-gradient(circle at top, rgba(77, 213, 255, 0.12), transparent 55%),
|
background:
|
||||||
radial-gradient(circle at 20% 20%, rgba(109, 132, 255, 0.25), transparent 35%),
|
radial-gradient(circle at 0% 0%, rgba(77, 213, 255, 0.15), transparent 50%),
|
||||||
var(--bg);
|
radial-gradient(circle at 100% 0%, rgba(109, 132, 255, 0.2), transparent 50%),
|
||||||
|
radial-gradient(circle at 50% 100%, rgba(77, 213, 255, 0.08), transparent 60%),
|
||||||
|
var(--bg);
|
||||||
|
background-attachment: fixed;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
position: relative;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 20% 30%, rgba(77, 213, 255, 0.03), transparent 50%),
|
||||||
|
radial-gradient(circle at 80% 70%, rgba(109, 132, 255, 0.03), transparent 50%);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > * {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -56,6 +86,27 @@ button:focus-visible {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -50%;
|
||||||
|
right: -20%;
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
background: radial-gradient(circle, rgba(77, 213, 255, 0.1), transparent 70%);
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(60px);
|
||||||
|
pointer-events: none;
|
||||||
|
animation: pulse 8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { transform: scale(1) translate(0, 0); opacity: 0.6; }
|
||||||
|
50% { transform: scale(1.2) translate(-10%, 10%); opacity: 0.8; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
@@ -68,6 +119,12 @@ button:focus-visible {
|
|||||||
.brand {
|
.brand {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
text-shadow: 0 0 20px var(--accent-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__links {
|
.nav__links {
|
||||||
@@ -79,14 +136,32 @@ button:focus-visible {
|
|||||||
.nav__links a {
|
.nav__links a {
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: color 0.2s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav__links a::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, var(--accent), var(--accent-strong));
|
||||||
|
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 0 0 10px var(--accent-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__links a:hover {
|
.nav__links a:hover {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav__links a:hover::after {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.nav__toggle {
|
.nav__toggle {
|
||||||
display: none;
|
display: none;
|
||||||
background: none;
|
background: none;
|
||||||
@@ -119,6 +194,11 @@ h1 {
|
|||||||
font-size: clamp(2.7rem, 5vw, 4.8rem);
|
font-size: clamp(2.7rem, 5vw, 4.8rem);
|
||||||
margin: 0 0 1rem;
|
margin: 0 0 1rem;
|
||||||
line-height: 1.05;
|
line-height: 1.05;
|
||||||
|
background: linear-gradient(135deg, var(--text) 0%, var(--accent) 50%, var(--accent-strong) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
filter: drop-shadow(0 0 20px rgba(77, 213, 255, 0.3));
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@@ -149,8 +229,28 @@ h3 {
|
|||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: width 0.6s, height 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover::before {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:focus-visible {
|
.btn:focus-visible {
|
||||||
@@ -163,32 +263,51 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn.primary {
|
.btn.primary {
|
||||||
background: linear-gradient(90deg, var(--accent-strong), var(--accent));
|
background: linear-gradient(135deg, var(--accent-strong), var(--accent));
|
||||||
color: #05060a;
|
color: #05060a;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: 0 15px 40px rgba(77, 213, 255, 0.3);
|
box-shadow: 0 15px 40px rgba(77, 213, 255, 0.3), 0 0 20px rgba(77, 213, 255, 0.2);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.primary:hover {
|
||||||
|
transform: translateY(-2px) scale(1.02);
|
||||||
|
box-shadow: 0 20px 50px rgba(77, 213, 255, 0.4), 0 0 30px rgba(77, 213, 255, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn.ghost {
|
.btn.ghost {
|
||||||
border-color: rgba(255, 255, 255, 0.2);
|
border-color: rgba(255, 255, 255, 0.25);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
background: transparent;
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:hover {
|
.btn.ghost:hover {
|
||||||
transform: translateY(-1px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 12px 30px rgba(109, 132, 255, 0.25);
|
border-color: rgba(77, 213, 255, 0.5);
|
||||||
|
background: rgba(77, 213, 255, 0.1);
|
||||||
|
box-shadow: 0 10px 30px rgba(77, 213, 255, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.install-command {
|
.install-command {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
background: rgba(18, 20, 34, 0.7);
|
background: rgba(18, 20, 34, 0.8);
|
||||||
border: 1px solid var(--card-border);
|
border: 1px solid var(--card-border);
|
||||||
font-family: 'JetBrains Mono', 'Space Grotesk', monospace;
|
font-family: 'JetBrains Mono', 'Space Grotesk', monospace;
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-command:hover {
|
||||||
|
border-color: rgba(77, 213, 255, 0.3);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 0 20px rgba(77, 213, 255, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero__metrics {
|
.hero__metrics {
|
||||||
@@ -201,7 +320,32 @@ h3 {
|
|||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
border: 1px solid var(--card-border);
|
border: 1px solid var(--card-border);
|
||||||
background: rgba(5, 6, 10, 0.55);
|
background: rgba(5, 6, 10, 0.6);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.1), transparent);
|
||||||
|
transition: left 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
border-color: rgba(77, 213, 255, 0.3);
|
||||||
|
box-shadow: 0 10px 30px rgba(77, 213, 255, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric:hover::before {
|
||||||
|
left: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.metric__label {
|
.metric__label {
|
||||||
@@ -239,6 +383,40 @@ h3 {
|
|||||||
background: var(--card);
|
background: var(--card);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
min-height: 10rem;
|
min-height: 10rem;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: transform 0.6s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
border-color: rgba(77, 213, 255, 0.4);
|
||||||
|
box-shadow: 0 20px 50px rgba(77, 213, 255, 0.2), var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover::before {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card h3 {
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover h3 {
|
||||||
|
color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card p {
|
.card p {
|
||||||
@@ -262,10 +440,19 @@ h3 {
|
|||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
border: 1px solid var(--card-border);
|
border: 1px solid var(--card-border);
|
||||||
background: rgba(5, 6, 10, 0.5);
|
background: rgba(5, 6, 10, 0.6);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
counter-increment: install-step;
|
counter-increment: install-step;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 4.5rem;
|
padding-left: 4.5rem;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-steps li:hover {
|
||||||
|
transform: translateX(8px);
|
||||||
|
border-color: rgba(77, 213, 255, 0.3);
|
||||||
|
background: rgba(5, 6, 10, 0.7);
|
||||||
|
box-shadow: 0 10px 30px rgba(77, 213, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.install-steps li::before {
|
.install-steps li::before {
|
||||||
@@ -281,6 +468,14 @@ h3 {
|
|||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 0 15px rgba(77, 213, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.install-steps li:hover::before {
|
||||||
|
background: rgba(77, 213, 255, 0.3);
|
||||||
|
box-shadow: 0 0 25px rgba(77, 213, 255, 0.5);
|
||||||
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.callout {
|
.callout {
|
||||||
@@ -289,6 +484,14 @@ h3 {
|
|||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
background: rgba(255, 196, 87, 0.12);
|
background: rgba(255, 196, 87, 0.12);
|
||||||
border: 1px solid rgba(255, 196, 87, 0.35);
|
border: 1px solid rgba(255, 196, 87, 0.35);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 8px 32px rgba(255, 196, 87, 0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout:hover {
|
||||||
|
border-color: rgba(255, 196, 87, 0.5);
|
||||||
|
box-shadow: 0 8px 32px rgba(255, 196, 87, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.showcase__grid {
|
.showcase__grid {
|
||||||
@@ -303,7 +506,33 @@ figure {
|
|||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background: rgba(9, 10, 18, 0.8);
|
background: rgba(9, 10, 18, 0.8);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
min-height: 15rem;
|
min-height: 15rem;
|
||||||
|
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -50%;
|
||||||
|
left: -50%;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
background: radial-gradient(circle, rgba(77, 213, 255, 0.1), transparent 70%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure:hover {
|
||||||
|
transform: translateY(-8px) scale(1.02);
|
||||||
|
border-color: rgba(77, 213, 255, 0.4);
|
||||||
|
box-shadow: 0 20px 50px rgba(77, 213, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
figure:hover::before {
|
||||||
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
figcaption {
|
figcaption {
|
||||||
@@ -313,22 +542,55 @@ figcaption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
background: rgba(5, 6, 10, 0.65);
|
background: rgba(5, 6, 10, 0.8);
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
|
border: 1px solid rgba(77, 213, 255, 0.1);
|
||||||
|
box-shadow: inset 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
position: relative;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
pre::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.3), transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.statusbar-demo {
|
.statusbar-demo {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
background: linear-gradient(90deg, var(--accent-strong), var(--accent));
|
background: linear-gradient(135deg, var(--accent-strong), var(--accent));
|
||||||
color: #05060a;
|
color: #05060a;
|
||||||
padding: 0.65rem 1rem;
|
padding: 0.65rem 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
box-shadow: 0 4px 20px rgba(77, 213, 255, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusbar-demo::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: -100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
|
||||||
|
animation: shimmer 3s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% { left: -100%; }
|
||||||
|
100% { left: 100%; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.community__actions {
|
.community__actions {
|
||||||
@@ -340,7 +602,7 @@ pre {
|
|||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
padding: 2rem clamp(1.5rem, 5vw, 5rem);
|
padding: 2rem clamp(1.5rem, 5vw, 5rem);
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -348,6 +610,28 @@ pre {
|
|||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
|
background: rgba(5, 6, 10, 0.5);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(77, 213, 255, 0.3), transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer a:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 10px var(--accent-glow);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
@@ -365,9 +649,27 @@ pre {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 1rem 0 0;
|
padding: 1rem 0 0;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
background: rgba(5, 6, 10, 0.95);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
border: 1px solid var(--card-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav__links.is-open {
|
.nav__links.is-open {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
animation: slideDown 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1195
terminal.py
1195
terminal.py
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
|||||||
0.1.2.a.2
|
0.1.2.b.5
|
||||||
Reference in New Issue
Block a user