Spaces:
Running
Running
Upload folder using huggingface_hub
Browse files- .gitignore +14 -0
- README.md +781 -12
- __init__.py +0 -0
- app copy.py +238 -0
- app.py +227 -0
- css.css +157 -0
- requirements.txt +1 -0
- space.py +350 -0
- src/.gitignore +14 -0
- src/.vscode/launch.json +29 -0
- src/LICENSES/Apache.txt +201 -0
- src/LICENSES/MIT.txt +21 -0
- src/README.md +781 -0
- src/assets/logo.webp +0 -0
- src/backend/gradio_creditspanel/__init__.py +4 -0
- src/backend/gradio_creditspanel/creditspanel.py +260 -0
- src/backend/gradio_creditspanel/templates/component/index.js +0 -0
- src/backend/gradio_creditspanel/templates/component/style.css +1 -0
- src/backend/gradio_creditspanel/templates/example/index.js +97 -0
- src/backend/gradio_creditspanel/templates/example/style.css +1 -0
- src/demo/__init__.py +0 -0
- src/demo/app copy.py +238 -0
- src/demo/app.py +227 -0
- src/demo/css.css +157 -0
- src/demo/requirements.txt +1 -0
- src/demo/space.py +350 -0
- src/frontend/Example.svelte +20 -0
- src/frontend/Index.svelte +389 -0
- src/frontend/gradio.config.js +9 -0
- src/frontend/package-lock.json +0 -0
- src/frontend/package.json +46 -0
- src/frontend/shared/MatrixEffect.svelte +192 -0
- src/frontend/shared/ScrollEffect.svelte +108 -0
- src/frontend/shared/StarWarsEffect.svelte +156 -0
- src/frontend/tsconfig.json +14 -0
- src/package-lock.json +6 -0
- src/pyproject.toml +51 -0
.gitignore
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.eggs/
|
| 2 |
+
dist/
|
| 3 |
+
.vscode/
|
| 4 |
+
*.pyc
|
| 5 |
+
__pycache__/
|
| 6 |
+
*.py[cod]
|
| 7 |
+
*$py.class
|
| 8 |
+
__tmp/*
|
| 9 |
+
*.pyi
|
| 10 |
+
.mypycache
|
| 11 |
+
.ruff_cache
|
| 12 |
+
node_modules
|
| 13 |
+
backend/**/templates/
|
| 14 |
+
README_TEMPLATE.md
|
README.md
CHANGED
|
@@ -1,12 +1,781 @@
|
|
| 1 |
-
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
---
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
tags: [gradio-custom-component, HTML]
|
| 3 |
+
title: gradio_creditspanel
|
| 4 |
+
short_description: Credits Panel for Gradio UI
|
| 5 |
+
colorFrom: blue
|
| 6 |
+
colorTo: yellow
|
| 7 |
+
sdk: gradio
|
| 8 |
+
pinned: false
|
| 9 |
+
app_file: space.py
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# `gradio_creditspanel`
|
| 13 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20blue"> <a href="https://huggingface.co/spaces/elismasilva/gradio_creditspanel"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Demo-blue"></a><p><span>💻 <a href='https://github.com/DEVAIEXP/gradio_component_creditspanel'>Component GitHub Code</a></span></p>
|
| 14 |
+
|
| 15 |
+
Credits Panel for Gradio UI
|
| 16 |
+
|
| 17 |
+
## Installation
|
| 18 |
+
|
| 19 |
+
```bash
|
| 20 |
+
pip install gradio_creditspanel
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
## Usage
|
| 24 |
+
|
| 25 |
+
```python
|
| 26 |
+
"""
|
| 27 |
+
app.py
|
| 28 |
+
|
| 29 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 30 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 31 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 32 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
import gradio as gr
|
| 36 |
+
from gradio_creditspanel import CreditsPanel
|
| 37 |
+
import os
|
| 38 |
+
|
| 39 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 40 |
+
# This section prepares all necessary assets and data for the demo.
|
| 41 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 42 |
+
|
| 43 |
+
def setup_demo_files():
|
| 44 |
+
"""
|
| 45 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 46 |
+
This makes the application self-contained and easy to run.
|
| 47 |
+
"""
|
| 48 |
+
# Create dummy license files
|
| 49 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 50 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 51 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 52 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 53 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 54 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 55 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 56 |
+
|
| 57 |
+
# Create a placeholder logo if it doesn't exist
|
| 58 |
+
os.makedirs("assets", exist_ok=True)
|
| 59 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 60 |
+
with open("./assets/logo.webp", "w") as f:
|
| 61 |
+
f.write("Placeholder WebP logo")
|
| 62 |
+
|
| 63 |
+
# Initial data for the credits roll
|
| 64 |
+
credits_list = [
|
| 65 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 66 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 67 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 68 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 69 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 70 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 71 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 72 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 73 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 74 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 75 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 76 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 77 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 78 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 79 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
# Paths to license files
|
| 83 |
+
license_paths = {
|
| 84 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 85 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 89 |
+
DEFAULT_SPEEDS = {
|
| 90 |
+
"scroll": 40.0,
|
| 91 |
+
"starwars": 80.0,
|
| 92 |
+
"matrix": 40.0
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 96 |
+
# These functions define the application's interactive logic.
|
| 97 |
+
|
| 98 |
+
def update_panel(
|
| 99 |
+
effect: str, speed: float, base_font_size: float,
|
| 100 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 101 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 102 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 103 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 104 |
+
scroll_name_color: str | None
|
| 105 |
+
) -> dict:
|
| 106 |
+
"""
|
| 107 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 108 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 109 |
+
"""
|
| 110 |
+
return gr.update(
|
| 111 |
+
visible=True,
|
| 112 |
+
effect=effect,
|
| 113 |
+
speed=speed,
|
| 114 |
+
base_font_size=base_font_size,
|
| 115 |
+
intro_title=intro_title,
|
| 116 |
+
intro_subtitle=intro_subtitle,
|
| 117 |
+
sidebar_position=sidebar_position,
|
| 118 |
+
show_logo=show_logo,
|
| 119 |
+
show_licenses=show_licenses,
|
| 120 |
+
logo_position=logo_position,
|
| 121 |
+
logo_sizing=logo_sizing,
|
| 122 |
+
logo_width=logo_width,
|
| 123 |
+
logo_height=logo_height,
|
| 124 |
+
scroll_background_color=scroll_background_color,
|
| 125 |
+
scroll_title_color=scroll_title_color,
|
| 126 |
+
scroll_name_color=scroll_name_color,
|
| 127 |
+
value=credits_list # The list of credits to display
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 131 |
+
"""
|
| 132 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 133 |
+
animation effect is changed.
|
| 134 |
+
"""
|
| 135 |
+
font_size = 1.5
|
| 136 |
+
if effect == "starwars":
|
| 137 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 138 |
+
|
| 139 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 140 |
+
return speed, font_size
|
| 141 |
+
|
| 142 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 143 |
+
# This section constructs the user interface using gr.Blocks.
|
| 144 |
+
|
| 145 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 146 |
+
gr.Markdown(
|
| 147 |
+
"""
|
| 148 |
+
# Interactive CreditsPanel Demo
|
| 149 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 150 |
+
"""
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
with gr.Sidebar(position="right"):
|
| 154 |
+
gr.Markdown("### Effects Settings")
|
| 155 |
+
effect_radio = gr.Radio(
|
| 156 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 157 |
+
info="Select the visual style for the credits."
|
| 158 |
+
)
|
| 159 |
+
speed_slider = gr.Slider(
|
| 160 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 161 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 162 |
+
)
|
| 163 |
+
font_size_slider = gr.Slider(
|
| 164 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 165 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
gr.Markdown("### Intro Text")
|
| 169 |
+
intro_title_input = gr.Textbox(
|
| 170 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 171 |
+
)
|
| 172 |
+
intro_subtitle_input = gr.Textbox(
|
| 173 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
gr.Markdown("### Layout & Visibility")
|
| 177 |
+
sidebar_position_radio = gr.Radio(
|
| 178 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 179 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 180 |
+
)
|
| 181 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 182 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 183 |
+
|
| 184 |
+
gr.Markdown("### Logo Customization")
|
| 185 |
+
logo_position_radio = gr.Radio(
|
| 186 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 187 |
+
)
|
| 188 |
+
logo_sizing_radio = gr.Radio(
|
| 189 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 190 |
+
)
|
| 191 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 192 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 193 |
+
|
| 194 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 195 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 196 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 197 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 198 |
+
|
| 199 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 200 |
+
panel = CreditsPanel(
|
| 201 |
+
credits=credits_list,
|
| 202 |
+
licenses=license_paths,
|
| 203 |
+
effect="scroll",
|
| 204 |
+
height=500,
|
| 205 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 206 |
+
base_font_size=1.5,
|
| 207 |
+
intro_title="Gradio",
|
| 208 |
+
intro_subtitle="The best UI framework",
|
| 209 |
+
sidebar_position="right",
|
| 210 |
+
logo_path="./assets/logo.webp",
|
| 211 |
+
show_logo=True,
|
| 212 |
+
show_licenses=True,
|
| 213 |
+
logo_position="center",
|
| 214 |
+
logo_sizing="resize",
|
| 215 |
+
logo_width="200px",
|
| 216 |
+
logo_height="100px",
|
| 217 |
+
scroll_background_color="#000000",
|
| 218 |
+
scroll_title_color="#FFFFFF",
|
| 219 |
+
scroll_name_color="#FFFFFF",
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
# List of all input components that should trigger a panel update
|
| 223 |
+
inputs = [
|
| 224 |
+
effect_radio, speed_slider, font_size_slider,
|
| 225 |
+
intro_title_input, intro_subtitle_input,
|
| 226 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 227 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 228 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 229 |
+
]
|
| 230 |
+
|
| 231 |
+
# --- 4. EVENT BINDING ---
|
| 232 |
+
# Connect the UI controls to the handler functions.
|
| 233 |
+
|
| 234 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 235 |
+
effect_radio.change(
|
| 236 |
+
fn=update_ui_on_effect_change,
|
| 237 |
+
inputs=effect_radio,
|
| 238 |
+
outputs=[speed_slider, font_size_slider]
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
# General event: any change in an input control updates the main panel
|
| 242 |
+
for input_component in inputs:
|
| 243 |
+
input_component.change(
|
| 244 |
+
fn=update_panel,
|
| 245 |
+
inputs=inputs,
|
| 246 |
+
outputs=panel
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
# --- 5. APP LAUNCH ---
|
| 250 |
+
if __name__ == "__main__":
|
| 251 |
+
setup_demo_files()
|
| 252 |
+
demo.launch()
|
| 253 |
+
```
|
| 254 |
+
|
| 255 |
+
## `CreditsPanel`
|
| 256 |
+
|
| 257 |
+
### Initialization
|
| 258 |
+
|
| 259 |
+
<table>
|
| 260 |
+
<thead>
|
| 261 |
+
<tr>
|
| 262 |
+
<th align="left">name</th>
|
| 263 |
+
<th align="left" style="width: 25%;">type</th>
|
| 264 |
+
<th align="left">default</th>
|
| 265 |
+
<th align="left">description</th>
|
| 266 |
+
</tr>
|
| 267 |
+
</thead>
|
| 268 |
+
<tbody>
|
| 269 |
+
<tr>
|
| 270 |
+
<td align="left"><code>value</code></td>
|
| 271 |
+
<td align="left" style="width: 25%;">
|
| 272 |
+
|
| 273 |
+
```python
|
| 274 |
+
Any
|
| 275 |
+
```
|
| 276 |
+
|
| 277 |
+
</td>
|
| 278 |
+
<td align="left"><code>None</code></td>
|
| 279 |
+
<td align="left">None</td>
|
| 280 |
+
</tr>
|
| 281 |
+
|
| 282 |
+
<tr>
|
| 283 |
+
<td align="left"><code>credits</code></td>
|
| 284 |
+
<td align="left" style="width: 25%;">
|
| 285 |
+
|
| 286 |
+
```python
|
| 287 |
+
typing.Union[
|
| 288 |
+
typing.List[typing.Dict[str, str]],
|
| 289 |
+
typing.Callable,
|
| 290 |
+
NoneType,
|
| 291 |
+
][
|
| 292 |
+
typing.List[typing.Dict[str, str]][
|
| 293 |
+
typing.Dict[str, str][str, str]
|
| 294 |
+
],
|
| 295 |
+
Callable,
|
| 296 |
+
None,
|
| 297 |
+
]
|
| 298 |
+
```
|
| 299 |
+
|
| 300 |
+
</td>
|
| 301 |
+
<td align="left"><code>None</code></td>
|
| 302 |
+
<td align="left">None</td>
|
| 303 |
+
</tr>
|
| 304 |
+
|
| 305 |
+
<tr>
|
| 306 |
+
<td align="left"><code>height</code></td>
|
| 307 |
+
<td align="left" style="width: 25%;">
|
| 308 |
+
|
| 309 |
+
```python
|
| 310 |
+
int | str | None
|
| 311 |
+
```
|
| 312 |
+
|
| 313 |
+
</td>
|
| 314 |
+
<td align="left"><code>None</code></td>
|
| 315 |
+
<td align="left">None</td>
|
| 316 |
+
</tr>
|
| 317 |
+
|
| 318 |
+
<tr>
|
| 319 |
+
<td align="left"><code>width</code></td>
|
| 320 |
+
<td align="left" style="width: 25%;">
|
| 321 |
+
|
| 322 |
+
```python
|
| 323 |
+
int | str | None
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
</td>
|
| 327 |
+
<td align="left"><code>None</code></td>
|
| 328 |
+
<td align="left">None</td>
|
| 329 |
+
</tr>
|
| 330 |
+
|
| 331 |
+
<tr>
|
| 332 |
+
<td align="left"><code>licenses</code></td>
|
| 333 |
+
<td align="left" style="width: 25%;">
|
| 334 |
+
|
| 335 |
+
```python
|
| 336 |
+
typing.Optional[typing.Dict[str, str | pathlib.Path]][
|
| 337 |
+
typing.Dict[str, str | pathlib.Path][
|
| 338 |
+
str, str | pathlib.Path
|
| 339 |
+
],
|
| 340 |
+
None,
|
| 341 |
+
]
|
| 342 |
+
```
|
| 343 |
+
|
| 344 |
+
</td>
|
| 345 |
+
<td align="left"><code>None</code></td>
|
| 346 |
+
<td align="left">None</td>
|
| 347 |
+
</tr>
|
| 348 |
+
|
| 349 |
+
<tr>
|
| 350 |
+
<td align="left"><code>effect</code></td>
|
| 351 |
+
<td align="left" style="width: 25%;">
|
| 352 |
+
|
| 353 |
+
```python
|
| 354 |
+
"scroll" | "starwars" | "matrix"
|
| 355 |
+
```
|
| 356 |
+
|
| 357 |
+
</td>
|
| 358 |
+
<td align="left"><code>"scroll"</code></td>
|
| 359 |
+
<td align="left">None</td>
|
| 360 |
+
</tr>
|
| 361 |
+
|
| 362 |
+
<tr>
|
| 363 |
+
<td align="left"><code>speed</code></td>
|
| 364 |
+
<td align="left" style="width: 25%;">
|
| 365 |
+
|
| 366 |
+
```python
|
| 367 |
+
float
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
</td>
|
| 371 |
+
<td align="left"><code>40.0</code></td>
|
| 372 |
+
<td align="left">None</td>
|
| 373 |
+
</tr>
|
| 374 |
+
|
| 375 |
+
<tr>
|
| 376 |
+
<td align="left"><code>base_font_size</code></td>
|
| 377 |
+
<td align="left" style="width: 25%;">
|
| 378 |
+
|
| 379 |
+
```python
|
| 380 |
+
float
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
</td>
|
| 384 |
+
<td align="left"><code>1.5</code></td>
|
| 385 |
+
<td align="left">None</td>
|
| 386 |
+
</tr>
|
| 387 |
+
|
| 388 |
+
<tr>
|
| 389 |
+
<td align="left"><code>intro_title</code></td>
|
| 390 |
+
<td align="left" style="width: 25%;">
|
| 391 |
+
|
| 392 |
+
```python
|
| 393 |
+
str | None
|
| 394 |
+
```
|
| 395 |
+
|
| 396 |
+
</td>
|
| 397 |
+
<td align="left"><code>None</code></td>
|
| 398 |
+
<td align="left">None</td>
|
| 399 |
+
</tr>
|
| 400 |
+
|
| 401 |
+
<tr>
|
| 402 |
+
<td align="left"><code>intro_subtitle</code></td>
|
| 403 |
+
<td align="left" style="width: 25%;">
|
| 404 |
+
|
| 405 |
+
```python
|
| 406 |
+
str | None
|
| 407 |
+
```
|
| 408 |
+
|
| 409 |
+
</td>
|
| 410 |
+
<td align="left"><code>None</code></td>
|
| 411 |
+
<td align="left">None</td>
|
| 412 |
+
</tr>
|
| 413 |
+
|
| 414 |
+
<tr>
|
| 415 |
+
<td align="left"><code>sidebar_position</code></td>
|
| 416 |
+
<td align="left" style="width: 25%;">
|
| 417 |
+
|
| 418 |
+
```python
|
| 419 |
+
"right" | "bottom"
|
| 420 |
+
```
|
| 421 |
+
|
| 422 |
+
</td>
|
| 423 |
+
<td align="left"><code>"right"</code></td>
|
| 424 |
+
<td align="left">None</td>
|
| 425 |
+
</tr>
|
| 426 |
+
|
| 427 |
+
<tr>
|
| 428 |
+
<td align="left"><code>logo_path</code></td>
|
| 429 |
+
<td align="left" style="width: 25%;">
|
| 430 |
+
|
| 431 |
+
```python
|
| 432 |
+
str | pathlib.Path | None
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
</td>
|
| 436 |
+
<td align="left"><code>None</code></td>
|
| 437 |
+
<td align="left">None</td>
|
| 438 |
+
</tr>
|
| 439 |
+
|
| 440 |
+
<tr>
|
| 441 |
+
<td align="left"><code>show_logo</code></td>
|
| 442 |
+
<td align="left" style="width: 25%;">
|
| 443 |
+
|
| 444 |
+
```python
|
| 445 |
+
bool
|
| 446 |
+
```
|
| 447 |
+
|
| 448 |
+
</td>
|
| 449 |
+
<td align="left"><code>True</code></td>
|
| 450 |
+
<td align="left">None</td>
|
| 451 |
+
</tr>
|
| 452 |
+
|
| 453 |
+
<tr>
|
| 454 |
+
<td align="left"><code>show_licenses</code></td>
|
| 455 |
+
<td align="left" style="width: 25%;">
|
| 456 |
+
|
| 457 |
+
```python
|
| 458 |
+
bool
|
| 459 |
+
```
|
| 460 |
+
|
| 461 |
+
</td>
|
| 462 |
+
<td align="left"><code>True</code></td>
|
| 463 |
+
<td align="left">None</td>
|
| 464 |
+
</tr>
|
| 465 |
+
|
| 466 |
+
<tr>
|
| 467 |
+
<td align="left"><code>logo_position</code></td>
|
| 468 |
+
<td align="left" style="width: 25%;">
|
| 469 |
+
|
| 470 |
+
```python
|
| 471 |
+
"center" | "left" | "right"
|
| 472 |
+
```
|
| 473 |
+
|
| 474 |
+
</td>
|
| 475 |
+
<td align="left"><code>"center"</code></td>
|
| 476 |
+
<td align="left">None</td>
|
| 477 |
+
</tr>
|
| 478 |
+
|
| 479 |
+
<tr>
|
| 480 |
+
<td align="left"><code>logo_sizing</code></td>
|
| 481 |
+
<td align="left" style="width: 25%;">
|
| 482 |
+
|
| 483 |
+
```python
|
| 484 |
+
"stretch" | "crop" | "resize"
|
| 485 |
+
```
|
| 486 |
+
|
| 487 |
+
</td>
|
| 488 |
+
<td align="left"><code>"resize"</code></td>
|
| 489 |
+
<td align="left">None</td>
|
| 490 |
+
</tr>
|
| 491 |
+
|
| 492 |
+
<tr>
|
| 493 |
+
<td align="left"><code>logo_width</code></td>
|
| 494 |
+
<td align="left" style="width: 25%;">
|
| 495 |
+
|
| 496 |
+
```python
|
| 497 |
+
int | str | None
|
| 498 |
+
```
|
| 499 |
+
|
| 500 |
+
</td>
|
| 501 |
+
<td align="left"><code>None</code></td>
|
| 502 |
+
<td align="left">None</td>
|
| 503 |
+
</tr>
|
| 504 |
+
|
| 505 |
+
<tr>
|
| 506 |
+
<td align="left"><code>logo_height</code></td>
|
| 507 |
+
<td align="left" style="width: 25%;">
|
| 508 |
+
|
| 509 |
+
```python
|
| 510 |
+
int | str | None
|
| 511 |
+
```
|
| 512 |
+
|
| 513 |
+
</td>
|
| 514 |
+
<td align="left"><code>None</code></td>
|
| 515 |
+
<td align="left">None</td>
|
| 516 |
+
</tr>
|
| 517 |
+
|
| 518 |
+
<tr>
|
| 519 |
+
<td align="left"><code>scroll_background_color</code></td>
|
| 520 |
+
<td align="left" style="width: 25%;">
|
| 521 |
+
|
| 522 |
+
```python
|
| 523 |
+
str | None
|
| 524 |
+
```
|
| 525 |
+
|
| 526 |
+
</td>
|
| 527 |
+
<td align="left"><code>None</code></td>
|
| 528 |
+
<td align="left">None</td>
|
| 529 |
+
</tr>
|
| 530 |
+
|
| 531 |
+
<tr>
|
| 532 |
+
<td align="left"><code>scroll_title_color</code></td>
|
| 533 |
+
<td align="left" style="width: 25%;">
|
| 534 |
+
|
| 535 |
+
```python
|
| 536 |
+
str | None
|
| 537 |
+
```
|
| 538 |
+
|
| 539 |
+
</td>
|
| 540 |
+
<td align="left"><code>None</code></td>
|
| 541 |
+
<td align="left">None</td>
|
| 542 |
+
</tr>
|
| 543 |
+
|
| 544 |
+
<tr>
|
| 545 |
+
<td align="left"><code>scroll_name_color</code></td>
|
| 546 |
+
<td align="left" style="width: 25%;">
|
| 547 |
+
|
| 548 |
+
```python
|
| 549 |
+
str | None
|
| 550 |
+
```
|
| 551 |
+
|
| 552 |
+
</td>
|
| 553 |
+
<td align="left"><code>None</code></td>
|
| 554 |
+
<td align="left">None</td>
|
| 555 |
+
</tr>
|
| 556 |
+
|
| 557 |
+
<tr>
|
| 558 |
+
<td align="left"><code>label</code></td>
|
| 559 |
+
<td align="left" style="width: 25%;">
|
| 560 |
+
|
| 561 |
+
```python
|
| 562 |
+
str | gradio.i18n.I18nData | None
|
| 563 |
+
```
|
| 564 |
+
|
| 565 |
+
</td>
|
| 566 |
+
<td align="left"><code>None</code></td>
|
| 567 |
+
<td align="left">None</td>
|
| 568 |
+
</tr>
|
| 569 |
+
|
| 570 |
+
<tr>
|
| 571 |
+
<td align="left"><code>every</code></td>
|
| 572 |
+
<td align="left" style="width: 25%;">
|
| 573 |
+
|
| 574 |
+
```python
|
| 575 |
+
float | None
|
| 576 |
+
```
|
| 577 |
+
|
| 578 |
+
</td>
|
| 579 |
+
<td align="left"><code>None</code></td>
|
| 580 |
+
<td align="left">None</td>
|
| 581 |
+
</tr>
|
| 582 |
+
|
| 583 |
+
<tr>
|
| 584 |
+
<td align="left"><code>inputs</code></td>
|
| 585 |
+
<td align="left" style="width: 25%;">
|
| 586 |
+
|
| 587 |
+
```python
|
| 588 |
+
typing.Union[
|
| 589 |
+
gradio.components.base.Component,
|
| 590 |
+
typing.Sequence[gradio.components.base.Component],
|
| 591 |
+
set[gradio.components.base.Component],
|
| 592 |
+
NoneType,
|
| 593 |
+
][
|
| 594 |
+
gradio.components.base.Component,
|
| 595 |
+
typing.Sequence[gradio.components.base.Component][
|
| 596 |
+
gradio.components.base.Component
|
| 597 |
+
],
|
| 598 |
+
set[gradio.components.base.Component],
|
| 599 |
+
None,
|
| 600 |
+
]
|
| 601 |
+
```
|
| 602 |
+
|
| 603 |
+
</td>
|
| 604 |
+
<td align="left"><code>None</code></td>
|
| 605 |
+
<td align="left">None</td>
|
| 606 |
+
</tr>
|
| 607 |
+
|
| 608 |
+
<tr>
|
| 609 |
+
<td align="left"><code>show_label</code></td>
|
| 610 |
+
<td align="left" style="width: 25%;">
|
| 611 |
+
|
| 612 |
+
```python
|
| 613 |
+
bool
|
| 614 |
+
```
|
| 615 |
+
|
| 616 |
+
</td>
|
| 617 |
+
<td align="left"><code>False</code></td>
|
| 618 |
+
<td align="left">None</td>
|
| 619 |
+
</tr>
|
| 620 |
+
|
| 621 |
+
<tr>
|
| 622 |
+
<td align="left"><code>container</code></td>
|
| 623 |
+
<td align="left" style="width: 25%;">
|
| 624 |
+
|
| 625 |
+
```python
|
| 626 |
+
bool
|
| 627 |
+
```
|
| 628 |
+
|
| 629 |
+
</td>
|
| 630 |
+
<td align="left"><code>True</code></td>
|
| 631 |
+
<td align="left">None</td>
|
| 632 |
+
</tr>
|
| 633 |
+
|
| 634 |
+
<tr>
|
| 635 |
+
<td align="left"><code>scale</code></td>
|
| 636 |
+
<td align="left" style="width: 25%;">
|
| 637 |
+
|
| 638 |
+
```python
|
| 639 |
+
int | None
|
| 640 |
+
```
|
| 641 |
+
|
| 642 |
+
</td>
|
| 643 |
+
<td align="left"><code>None</code></td>
|
| 644 |
+
<td align="left">None</td>
|
| 645 |
+
</tr>
|
| 646 |
+
|
| 647 |
+
<tr>
|
| 648 |
+
<td align="left"><code>min_width</code></td>
|
| 649 |
+
<td align="left" style="width: 25%;">
|
| 650 |
+
|
| 651 |
+
```python
|
| 652 |
+
int
|
| 653 |
+
```
|
| 654 |
+
|
| 655 |
+
</td>
|
| 656 |
+
<td align="left"><code>160</code></td>
|
| 657 |
+
<td align="left">None</td>
|
| 658 |
+
</tr>
|
| 659 |
+
|
| 660 |
+
<tr>
|
| 661 |
+
<td align="left"><code>interactive</code></td>
|
| 662 |
+
<td align="left" style="width: 25%;">
|
| 663 |
+
|
| 664 |
+
```python
|
| 665 |
+
bool | None
|
| 666 |
+
```
|
| 667 |
+
|
| 668 |
+
</td>
|
| 669 |
+
<td align="left"><code>None</code></td>
|
| 670 |
+
<td align="left">None</td>
|
| 671 |
+
</tr>
|
| 672 |
+
|
| 673 |
+
<tr>
|
| 674 |
+
<td align="left"><code>visible</code></td>
|
| 675 |
+
<td align="left" style="width: 25%;">
|
| 676 |
+
|
| 677 |
+
```python
|
| 678 |
+
bool
|
| 679 |
+
```
|
| 680 |
+
|
| 681 |
+
</td>
|
| 682 |
+
<td align="left"><code>True</code></td>
|
| 683 |
+
<td align="left">None</td>
|
| 684 |
+
</tr>
|
| 685 |
+
|
| 686 |
+
<tr>
|
| 687 |
+
<td align="left"><code>elem_id</code></td>
|
| 688 |
+
<td align="left" style="width: 25%;">
|
| 689 |
+
|
| 690 |
+
```python
|
| 691 |
+
str | None
|
| 692 |
+
```
|
| 693 |
+
|
| 694 |
+
</td>
|
| 695 |
+
<td align="left"><code>None</code></td>
|
| 696 |
+
<td align="left">None</td>
|
| 697 |
+
</tr>
|
| 698 |
+
|
| 699 |
+
<tr>
|
| 700 |
+
<td align="left"><code>elem_classes</code></td>
|
| 701 |
+
<td align="left" style="width: 25%;">
|
| 702 |
+
|
| 703 |
+
```python
|
| 704 |
+
list[str] | str | None
|
| 705 |
+
```
|
| 706 |
+
|
| 707 |
+
</td>
|
| 708 |
+
<td align="left"><code>None</code></td>
|
| 709 |
+
<td align="left">None</td>
|
| 710 |
+
</tr>
|
| 711 |
+
|
| 712 |
+
<tr>
|
| 713 |
+
<td align="left"><code>render</code></td>
|
| 714 |
+
<td align="left" style="width: 25%;">
|
| 715 |
+
|
| 716 |
+
```python
|
| 717 |
+
bool
|
| 718 |
+
```
|
| 719 |
+
|
| 720 |
+
</td>
|
| 721 |
+
<td align="left"><code>True</code></td>
|
| 722 |
+
<td align="left">None</td>
|
| 723 |
+
</tr>
|
| 724 |
+
|
| 725 |
+
<tr>
|
| 726 |
+
<td align="left"><code>key</code></td>
|
| 727 |
+
<td align="left" style="width: 25%;">
|
| 728 |
+
|
| 729 |
+
```python
|
| 730 |
+
int | str | tuple[int | str, Ellipsis] | None
|
| 731 |
+
```
|
| 732 |
+
|
| 733 |
+
</td>
|
| 734 |
+
<td align="left"><code>None</code></td>
|
| 735 |
+
<td align="left">None</td>
|
| 736 |
+
</tr>
|
| 737 |
+
|
| 738 |
+
<tr>
|
| 739 |
+
<td align="left"><code>preserved_by_key</code></td>
|
| 740 |
+
<td align="left" style="width: 25%;">
|
| 741 |
+
|
| 742 |
+
```python
|
| 743 |
+
list[str] | str | None
|
| 744 |
+
```
|
| 745 |
+
|
| 746 |
+
</td>
|
| 747 |
+
<td align="left"><code>"value"</code></td>
|
| 748 |
+
<td align="left">None</td>
|
| 749 |
+
</tr>
|
| 750 |
+
</tbody></table>
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
### Events
|
| 754 |
+
|
| 755 |
+
| name | description |
|
| 756 |
+
|:-----|:------------|
|
| 757 |
+
| `change` | Triggered when the value of the CreditsPanel changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
|
| 758 |
+
|
| 759 |
+
|
| 760 |
+
|
| 761 |
+
### User function
|
| 762 |
+
|
| 763 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
| 764 |
+
|
| 765 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
| 766 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
| 767 |
+
|
| 768 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
| 769 |
+
|
| 770 |
+
- **As output:** Is passed, dict[str, Any] | None: The input payload, returned unchanged.
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
```python
|
| 774 |
+
def predict(
|
| 775 |
+
value: typing.Optional[typing.Dict[str, typing.Any]][
|
| 776 |
+
typing.Dict[str, typing.Any][str, Any], None
|
| 777 |
+
]
|
| 778 |
+
) -> Any:
|
| 779 |
+
return value
|
| 780 |
+
```
|
| 781 |
+
|
__init__.py
ADDED
|
File without changes
|
app copy.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from gradio_creditspanel import CreditsPanel
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# Create dummy license files
|
| 6 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 7 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 8 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 9 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 10 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 11 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 12 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 13 |
+
|
| 14 |
+
# Create assets directory for logo
|
| 15 |
+
os.makedirs("assets", exist_ok=True)
|
| 16 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 17 |
+
print("Warning: ./assets/logo.webp not found. Creating placeholder. Replace with a valid WebP image.")
|
| 18 |
+
with open("./assets/logo.webp", "w") as f:
|
| 19 |
+
f.write("Placeholder WebP logo")
|
| 20 |
+
else:
|
| 21 |
+
print("Logo found at ./assets/logo.webp")
|
| 22 |
+
|
| 23 |
+
credits_list = [
|
| 24 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 25 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 26 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 27 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 28 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 29 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 30 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 31 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 32 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 33 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 34 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 35 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 36 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 37 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 38 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 39 |
+
{"title": "Cloud Infrastructure Engineer", "name": "Lucas Nguyen"},
|
| 40 |
+
{"title": "Mobile Developer", "name": "Mia Hernandez"},
|
| 41 |
+
{"title": "Performance Engineer", "name": "James Taylor"},
|
| 42 |
+
{"title": "Component Concept", "name": "Your Name"},
|
| 43 |
+
{"title": "Support Engineer", "name": "Charlotte Moore"}
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
license_paths = {
|
| 47 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 48 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
DEFAULT_SPEEDS = {
|
| 52 |
+
"scroll": 40.0,
|
| 53 |
+
"starwars": 80.0,
|
| 54 |
+
"matrix": 40.0
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
def update_panel(
|
| 58 |
+
effect: str,
|
| 59 |
+
speed: float,
|
| 60 |
+
sidebar_position: str,
|
| 61 |
+
show_logo: bool,
|
| 62 |
+
show_licenses: bool,
|
| 63 |
+
logo_position: str,
|
| 64 |
+
logo_sizing: str,
|
| 65 |
+
logo_width: int | str | None,
|
| 66 |
+
logo_height: int | str | None,
|
| 67 |
+
scroll_background_color: str | None,
|
| 68 |
+
scroll_title_color: str | None,
|
| 69 |
+
scroll_name_color: str | None
|
| 70 |
+
):
|
| 71 |
+
print(f"Updating panel: effect={effect}, speed={speed}, sidebar_position={sidebar_position}, show_logo={show_logo}, show_licenses={show_licenses}, logo_position={logo_position}, logo_sizing={logo_sizing}, logo_width={logo_width}, logo_height={logo_height}")
|
| 72 |
+
return gr.update(
|
| 73 |
+
visible=True,
|
| 74 |
+
effect=effect,
|
| 75 |
+
speed=speed,
|
| 76 |
+
sidebar_position=sidebar_position,
|
| 77 |
+
show_logo=show_logo,
|
| 78 |
+
show_licenses=show_licenses,
|
| 79 |
+
logo_position=logo_position,
|
| 80 |
+
logo_sizing=logo_sizing,
|
| 81 |
+
logo_width=logo_width,
|
| 82 |
+
logo_height=logo_height,
|
| 83 |
+
scroll_background_color=scroll_background_color,
|
| 84 |
+
scroll_title_color=scroll_title_color,
|
| 85 |
+
scroll_name_color=scroll_name_color,
|
| 86 |
+
value=credits_list
|
| 87 |
+
# value={
|
| 88 |
+
# "credits": credits_list,
|
| 89 |
+
# "licenses": license_paths,
|
| 90 |
+
# "effect": effect,
|
| 91 |
+
# "speed": speed,
|
| 92 |
+
# "sidebar_position": sidebar_position,
|
| 93 |
+
# "logo_path": "./assets/logo.webp", # Handled by Gradio's file serving
|
| 94 |
+
# "show_logo": show_logo,
|
| 95 |
+
# "show_licenses": show_licenses,
|
| 96 |
+
# "logo_position": logo_position,
|
| 97 |
+
# "logo_sizing": logo_sizing,
|
| 98 |
+
# "logo_width": logo_width,
|
| 99 |
+
# "logo_height": logo_height,
|
| 100 |
+
# "scroll_background_color": scroll_background_color,
|
| 101 |
+
# "scroll_title_color": scroll_title_color,
|
| 102 |
+
# "scroll_name_color": scroll_name_color
|
| 103 |
+
# }
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
def update_speed_on_effect_change(effect: str):
|
| 107 |
+
"""Update speed_slider to default speed when effect changes."""
|
| 108 |
+
return DEFAULT_SPEEDS.get(effect, 40.0)
|
| 109 |
+
|
| 110 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo", css="") as demo:
|
| 111 |
+
gr.Markdown(
|
| 112 |
+
"""
|
| 113 |
+
# Interactive CreditsPanel Demo
|
| 114 |
+
Use the sidebar controls to customize the credits panel.
|
| 115 |
+
"""
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
with gr.Sidebar(position="right"):
|
| 119 |
+
effect_radio = gr.Radio(
|
| 120 |
+
["scroll", "starwars", "matrix"],
|
| 121 |
+
label="Animation Effect",
|
| 122 |
+
value="scroll",
|
| 123 |
+
info="Select the visual style for the credits."
|
| 124 |
+
)
|
| 125 |
+
speed_slider = gr.Slider(
|
| 126 |
+
minimum=5.0,
|
| 127 |
+
maximum=100.0,
|
| 128 |
+
step=1.0,
|
| 129 |
+
value=DEFAULT_SPEEDS["scroll"],
|
| 130 |
+
label="Animation Speed (seconds)",
|
| 131 |
+
info="Duration of the animation cycle."
|
| 132 |
+
)
|
| 133 |
+
sidebar_position_radio = gr.Radio(
|
| 134 |
+
["right", "bottom"],
|
| 135 |
+
label="Sidebar Position",
|
| 136 |
+
value="right",
|
| 137 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 138 |
+
)
|
| 139 |
+
show_logo_checkbox = gr.Checkbox(
|
| 140 |
+
label="Show Logo",
|
| 141 |
+
value=True,
|
| 142 |
+
info="Toggle the logo panel."
|
| 143 |
+
)
|
| 144 |
+
show_licenses_checkbox = gr.Checkbox(
|
| 145 |
+
label="Show Licenses",
|
| 146 |
+
value=True,
|
| 147 |
+
info="Toggle the licenses sidebar."
|
| 148 |
+
)
|
| 149 |
+
logo_position_radio = gr.Radio(
|
| 150 |
+
["center", "left", "right"],
|
| 151 |
+
label="Logo Position",
|
| 152 |
+
value="center",
|
| 153 |
+
info="Position of the logo in the panel."
|
| 154 |
+
)
|
| 155 |
+
logo_sizing_radio = gr.Radio(
|
| 156 |
+
["stretch", "crop", "resize"],
|
| 157 |
+
label="Logo Sizing",
|
| 158 |
+
value="resize",
|
| 159 |
+
info="How the logo fits in the panel."
|
| 160 |
+
)
|
| 161 |
+
logo_width_input = gr.Textbox(
|
| 162 |
+
label="Logo Width (px or CSS)",
|
| 163 |
+
value="200px",
|
| 164 |
+
info="Width of the logo (e.g., '200px' or '50%')."
|
| 165 |
+
)
|
| 166 |
+
logo_height_input = gr.Textbox(
|
| 167 |
+
label="Logo Height (px or CSS)",
|
| 168 |
+
value="100px",
|
| 169 |
+
info="Height of the logo (e.g., '100px' or '10%')."
|
| 170 |
+
)
|
| 171 |
+
scroll_background_color = gr.ColorPicker(
|
| 172 |
+
label="Scroll Background Color",
|
| 173 |
+
value="#000000",
|
| 174 |
+
info="Background color for ScrollEffect."
|
| 175 |
+
)
|
| 176 |
+
scroll_title_color = gr.ColorPicker(
|
| 177 |
+
label="Scroll Title Color",
|
| 178 |
+
value="#FFFFFF",
|
| 179 |
+
info="Color for title text in ScrollEffect."
|
| 180 |
+
)
|
| 181 |
+
scroll_name_color = gr.ColorPicker(
|
| 182 |
+
label="Scroll Name Color",
|
| 183 |
+
value="#FFFFFF",
|
| 184 |
+
info="Color for name text in ScrollEffect."
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
panel = CreditsPanel(
|
| 188 |
+
credits=credits_list,
|
| 189 |
+
licenses=license_paths,
|
| 190 |
+
effect="scroll",
|
| 191 |
+
height=500,
|
| 192 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 193 |
+
sidebar_position="right",
|
| 194 |
+
logo_path="./assets/logo.webp", # Handled by Gradio's file serving
|
| 195 |
+
show_logo=True,
|
| 196 |
+
show_licenses=True,
|
| 197 |
+
logo_position="center",
|
| 198 |
+
logo_sizing="resize",
|
| 199 |
+
logo_width="200px",
|
| 200 |
+
logo_height="100px",
|
| 201 |
+
scroll_background_color="#000000",
|
| 202 |
+
scroll_title_color="#FFFFFF",
|
| 203 |
+
scroll_name_color="#FFFFFF",
|
| 204 |
+
visible=True
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
inputs = [
|
| 208 |
+
effect_radio,
|
| 209 |
+
speed_slider,
|
| 210 |
+
sidebar_position_radio,
|
| 211 |
+
show_logo_checkbox,
|
| 212 |
+
show_licenses_checkbox,
|
| 213 |
+
logo_position_radio,
|
| 214 |
+
logo_sizing_radio,
|
| 215 |
+
logo_width_input,
|
| 216 |
+
logo_height_input,
|
| 217 |
+
scroll_background_color,
|
| 218 |
+
scroll_title_color,
|
| 219 |
+
scroll_name_color
|
| 220 |
+
]
|
| 221 |
+
|
| 222 |
+
# Update speed when effect changes
|
| 223 |
+
effect_radio.change(
|
| 224 |
+
fn=update_speed_on_effect_change,
|
| 225 |
+
inputs=effect_radio,
|
| 226 |
+
outputs=speed_slider
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
# Update panel for all inputs
|
| 230 |
+
for input_component in inputs:
|
| 231 |
+
input_component.change(
|
| 232 |
+
fn=update_panel,
|
| 233 |
+
inputs=inputs,
|
| 234 |
+
outputs=panel
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
if __name__ == "__main__":
|
| 238 |
+
demo.launch(debug=True, share=False)
|
app.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
app.py
|
| 3 |
+
|
| 4 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 5 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 6 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 7 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import gradio as gr
|
| 11 |
+
from gradio_creditspanel import CreditsPanel
|
| 12 |
+
import os
|
| 13 |
+
|
| 14 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 15 |
+
# This section prepares all necessary assets and data for the demo.
|
| 16 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 17 |
+
|
| 18 |
+
def setup_demo_files():
|
| 19 |
+
"""
|
| 20 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 21 |
+
This makes the application self-contained and easy to run.
|
| 22 |
+
"""
|
| 23 |
+
# Create dummy license files
|
| 24 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 25 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 26 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 27 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 28 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 29 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 30 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 31 |
+
|
| 32 |
+
# Create a placeholder logo if it doesn't exist
|
| 33 |
+
os.makedirs("assets", exist_ok=True)
|
| 34 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 35 |
+
with open("./assets/logo.webp", "w") as f:
|
| 36 |
+
f.write("Placeholder WebP logo")
|
| 37 |
+
|
| 38 |
+
# Initial data for the credits roll
|
| 39 |
+
credits_list = [
|
| 40 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 41 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 42 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 43 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 44 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 45 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 46 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 47 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 48 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 49 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 50 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 51 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 52 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 53 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 54 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
# Paths to license files
|
| 58 |
+
license_paths = {
|
| 59 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 60 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 64 |
+
DEFAULT_SPEEDS = {
|
| 65 |
+
"scroll": 40.0,
|
| 66 |
+
"starwars": 80.0,
|
| 67 |
+
"matrix": 40.0
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 71 |
+
# These functions define the application's interactive logic.
|
| 72 |
+
|
| 73 |
+
def update_panel(
|
| 74 |
+
effect: str, speed: float, base_font_size: float,
|
| 75 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 76 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 77 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 78 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 79 |
+
scroll_name_color: str | None
|
| 80 |
+
) -> dict:
|
| 81 |
+
"""
|
| 82 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 83 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 84 |
+
"""
|
| 85 |
+
return gr.update(
|
| 86 |
+
visible=True,
|
| 87 |
+
effect=effect,
|
| 88 |
+
speed=speed,
|
| 89 |
+
base_font_size=base_font_size,
|
| 90 |
+
intro_title=intro_title,
|
| 91 |
+
intro_subtitle=intro_subtitle,
|
| 92 |
+
sidebar_position=sidebar_position,
|
| 93 |
+
show_logo=show_logo,
|
| 94 |
+
show_licenses=show_licenses,
|
| 95 |
+
logo_position=logo_position,
|
| 96 |
+
logo_sizing=logo_sizing,
|
| 97 |
+
logo_width=logo_width,
|
| 98 |
+
logo_height=logo_height,
|
| 99 |
+
scroll_background_color=scroll_background_color,
|
| 100 |
+
scroll_title_color=scroll_title_color,
|
| 101 |
+
scroll_name_color=scroll_name_color,
|
| 102 |
+
value=credits_list # The list of credits to display
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 106 |
+
"""
|
| 107 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 108 |
+
animation effect is changed.
|
| 109 |
+
"""
|
| 110 |
+
font_size = 1.5
|
| 111 |
+
if effect == "starwars":
|
| 112 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 113 |
+
|
| 114 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 115 |
+
return speed, font_size
|
| 116 |
+
|
| 117 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 118 |
+
# This section constructs the user interface using gr.Blocks.
|
| 119 |
+
|
| 120 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 121 |
+
gr.Markdown(
|
| 122 |
+
"""
|
| 123 |
+
# Interactive CreditsPanel Demo
|
| 124 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 125 |
+
"""
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
with gr.Sidebar(position="right"):
|
| 129 |
+
gr.Markdown("### Effects Settings")
|
| 130 |
+
effect_radio = gr.Radio(
|
| 131 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 132 |
+
info="Select the visual style for the credits."
|
| 133 |
+
)
|
| 134 |
+
speed_slider = gr.Slider(
|
| 135 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 136 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 137 |
+
)
|
| 138 |
+
font_size_slider = gr.Slider(
|
| 139 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 140 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
gr.Markdown("### Intro Text")
|
| 144 |
+
intro_title_input = gr.Textbox(
|
| 145 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 146 |
+
)
|
| 147 |
+
intro_subtitle_input = gr.Textbox(
|
| 148 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
gr.Markdown("### Layout & Visibility")
|
| 152 |
+
sidebar_position_radio = gr.Radio(
|
| 153 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 154 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 155 |
+
)
|
| 156 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 157 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 158 |
+
|
| 159 |
+
gr.Markdown("### Logo Customization")
|
| 160 |
+
logo_position_radio = gr.Radio(
|
| 161 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 162 |
+
)
|
| 163 |
+
logo_sizing_radio = gr.Radio(
|
| 164 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 165 |
+
)
|
| 166 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 167 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 168 |
+
|
| 169 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 170 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 171 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 172 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 173 |
+
|
| 174 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 175 |
+
panel = CreditsPanel(
|
| 176 |
+
credits=credits_list,
|
| 177 |
+
licenses=license_paths,
|
| 178 |
+
effect="scroll",
|
| 179 |
+
height=500,
|
| 180 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 181 |
+
base_font_size=1.5,
|
| 182 |
+
intro_title="Gradio",
|
| 183 |
+
intro_subtitle="The best UI framework",
|
| 184 |
+
sidebar_position="right",
|
| 185 |
+
logo_path="./assets/logo.webp",
|
| 186 |
+
show_logo=True,
|
| 187 |
+
show_licenses=True,
|
| 188 |
+
logo_position="center",
|
| 189 |
+
logo_sizing="resize",
|
| 190 |
+
logo_width="200px",
|
| 191 |
+
logo_height="100px",
|
| 192 |
+
scroll_background_color="#000000",
|
| 193 |
+
scroll_title_color="#FFFFFF",
|
| 194 |
+
scroll_name_color="#FFFFFF",
|
| 195 |
+
)
|
| 196 |
+
|
| 197 |
+
# List of all input components that should trigger a panel update
|
| 198 |
+
inputs = [
|
| 199 |
+
effect_radio, speed_slider, font_size_slider,
|
| 200 |
+
intro_title_input, intro_subtitle_input,
|
| 201 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 202 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 203 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
# --- 4. EVENT BINDING ---
|
| 207 |
+
# Connect the UI controls to the handler functions.
|
| 208 |
+
|
| 209 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 210 |
+
effect_radio.change(
|
| 211 |
+
fn=update_ui_on_effect_change,
|
| 212 |
+
inputs=effect_radio,
|
| 213 |
+
outputs=[speed_slider, font_size_slider]
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
# General event: any change in an input control updates the main panel
|
| 217 |
+
for input_component in inputs:
|
| 218 |
+
input_component.change(
|
| 219 |
+
fn=update_panel,
|
| 220 |
+
inputs=inputs,
|
| 221 |
+
outputs=panel
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
# --- 5. APP LAUNCH ---
|
| 225 |
+
if __name__ == "__main__":
|
| 226 |
+
setup_demo_files()
|
| 227 |
+
demo.launch()
|
css.css
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
html {
|
| 2 |
+
font-family: Inter;
|
| 3 |
+
font-size: 16px;
|
| 4 |
+
font-weight: 400;
|
| 5 |
+
line-height: 1.5;
|
| 6 |
+
-webkit-text-size-adjust: 100%;
|
| 7 |
+
background: #fff;
|
| 8 |
+
color: #323232;
|
| 9 |
+
-webkit-font-smoothing: antialiased;
|
| 10 |
+
-moz-osx-font-smoothing: grayscale;
|
| 11 |
+
text-rendering: optimizeLegibility;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
:root {
|
| 15 |
+
--space: 1;
|
| 16 |
+
--vspace: calc(var(--space) * 1rem);
|
| 17 |
+
--vspace-0: calc(3 * var(--space) * 1rem);
|
| 18 |
+
--vspace-1: calc(2 * var(--space) * 1rem);
|
| 19 |
+
--vspace-2: calc(1.5 * var(--space) * 1rem);
|
| 20 |
+
--vspace-3: calc(0.5 * var(--space) * 1rem);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.app {
|
| 24 |
+
max-width: 748px !important;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.prose p {
|
| 28 |
+
margin: var(--vspace) 0;
|
| 29 |
+
line-height: var(--vspace * 2);
|
| 30 |
+
font-size: 1rem;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
code {
|
| 34 |
+
font-family: "Inconsolata", sans-serif;
|
| 35 |
+
font-size: 16px;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
h1,
|
| 39 |
+
h1 code {
|
| 40 |
+
font-weight: 400;
|
| 41 |
+
line-height: calc(2.5 / var(--space) * var(--vspace));
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
h1 code {
|
| 45 |
+
background: none;
|
| 46 |
+
border: none;
|
| 47 |
+
letter-spacing: 0.05em;
|
| 48 |
+
padding-bottom: 5px;
|
| 49 |
+
position: relative;
|
| 50 |
+
padding: 0;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
h2 {
|
| 54 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
| 55 |
+
line-height: 1em;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
h3,
|
| 59 |
+
h3 code {
|
| 60 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
| 61 |
+
line-height: 1em;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
h4,
|
| 65 |
+
h5,
|
| 66 |
+
h6 {
|
| 67 |
+
margin: var(--vspace-3) 0 var(--vspace-3) 0;
|
| 68 |
+
line-height: var(--vspace);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.bigtitle,
|
| 72 |
+
h1,
|
| 73 |
+
h1 code {
|
| 74 |
+
font-size: calc(8px * 4.5);
|
| 75 |
+
word-break: break-word;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.title,
|
| 79 |
+
h2,
|
| 80 |
+
h2 code {
|
| 81 |
+
font-size: calc(8px * 3.375);
|
| 82 |
+
font-weight: lighter;
|
| 83 |
+
word-break: break-word;
|
| 84 |
+
border: none;
|
| 85 |
+
background: none;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.subheading1,
|
| 89 |
+
h3,
|
| 90 |
+
h3 code {
|
| 91 |
+
font-size: calc(8px * 1.8);
|
| 92 |
+
font-weight: 600;
|
| 93 |
+
border: none;
|
| 94 |
+
background: none;
|
| 95 |
+
letter-spacing: 0.1em;
|
| 96 |
+
text-transform: uppercase;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
h2 code {
|
| 100 |
+
padding: 0;
|
| 101 |
+
position: relative;
|
| 102 |
+
letter-spacing: 0.05em;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
blockquote {
|
| 106 |
+
font-size: calc(8px * 1.1667);
|
| 107 |
+
font-style: italic;
|
| 108 |
+
line-height: calc(1.1667 * var(--vspace));
|
| 109 |
+
margin: var(--vspace-2) var(--vspace-2);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
.subheading2,
|
| 113 |
+
h4 {
|
| 114 |
+
font-size: calc(8px * 1.4292);
|
| 115 |
+
text-transform: uppercase;
|
| 116 |
+
font-weight: 600;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.subheading3,
|
| 120 |
+
h5 {
|
| 121 |
+
font-size: calc(8px * 1.2917);
|
| 122 |
+
line-height: calc(1.2917 * var(--vspace));
|
| 123 |
+
|
| 124 |
+
font-weight: lighter;
|
| 125 |
+
text-transform: uppercase;
|
| 126 |
+
letter-spacing: 0.15em;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
h6 {
|
| 130 |
+
font-size: calc(8px * 1.1667);
|
| 131 |
+
font-size: 1.1667em;
|
| 132 |
+
font-weight: normal;
|
| 133 |
+
font-style: italic;
|
| 134 |
+
font-family: "le-monde-livre-classic-byol", serif !important;
|
| 135 |
+
letter-spacing: 0px !important;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
#start .md > *:first-child {
|
| 139 |
+
margin-top: 0;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
h2 + h3 {
|
| 143 |
+
margin-top: 0;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.md hr {
|
| 147 |
+
border: none;
|
| 148 |
+
border-top: 1px solid var(--block-border-color);
|
| 149 |
+
margin: var(--vspace-2) 0 var(--vspace-2) 0;
|
| 150 |
+
}
|
| 151 |
+
.prose ul {
|
| 152 |
+
margin: var(--vspace-2) 0 var(--vspace-1) 0;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
.gap {
|
| 156 |
+
gap: 0;
|
| 157 |
+
}
|
requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
gradio_creditspanel
|
space.py
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from app import demo as app
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
_docs = {'CreditsPanel': {'description': 'A Gradio component for displaying credits with customizable visual effects, such as scrolling or Star Wars-style animations.\nSupports displaying a logo, licenses, and configurable text styling.\n\n EVENTS (list): Supported events for the component, currently only `change`.', 'members': {'__init__': {'value': {'type': 'Any', 'default': 'None', 'description': None}, 'credits': {'type': 'typing.Union[\n typing.List[typing.Dict[str, str]],\n typing.Callable,\n NoneType,\n][\n typing.List[typing.Dict[str, str]][\n typing.Dict[str, str][str, str]\n ],\n Callable,\n None,\n]', 'default': 'None', 'description': None}, 'height': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'width': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'licenses': {'type': 'typing.Optional[typing.Dict[str, str | pathlib.Path]][\n typing.Dict[str, str | pathlib.Path][\n str, str | pathlib.Path\n ],\n None,\n]', 'default': 'None', 'description': None}, 'effect': {'type': '"scroll" | "starwars" | "matrix"', 'default': '"scroll"', 'description': None}, 'speed': {'type': 'float', 'default': '40.0', 'description': None}, 'base_font_size': {'type': 'float', 'default': '1.5', 'description': None}, 'intro_title': {'type': 'str | None', 'default': 'None', 'description': None}, 'intro_subtitle': {'type': 'str | None', 'default': 'None', 'description': None}, 'sidebar_position': {'type': '"right" | "bottom"', 'default': '"right"', 'description': None}, 'logo_path': {'type': 'str | pathlib.Path | None', 'default': 'None', 'description': None}, 'show_logo': {'type': 'bool', 'default': 'True', 'description': None}, 'show_licenses': {'type': 'bool', 'default': 'True', 'description': None}, 'logo_position': {'type': '"center" | "left" | "right"', 'default': '"center"', 'description': None}, 'logo_sizing': {'type': '"stretch" | "crop" | "resize"', 'default': '"resize"', 'description': None}, 'logo_width': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'logo_height': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'scroll_background_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'scroll_title_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'scroll_name_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | gradio.i18n.I18nData | None', 'default': 'None', 'description': None}, 'every': {'type': 'float | None', 'default': 'None', 'description': None}, 'inputs': {'type': 'typing.Union[\n gradio.components.base.Component,\n typing.Sequence[gradio.components.base.Component],\n set[gradio.components.base.Component],\n NoneType,\n][\n gradio.components.base.Component,\n typing.Sequence[gradio.components.base.Component][\n gradio.components.base.Component\n ],\n set[gradio.components.base.Component],\n None,\n]', 'default': 'None', 'description': None}, 'show_label': {'type': 'bool', 'default': 'False', 'description': None}, 'container': {'type': 'bool', 'default': 'True', 'description': None}, 'scale': {'type': 'int | None', 'default': 'None', 'description': None}, 'min_width': {'type': 'int', 'default': '160', 'description': None}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': None}, 'visible': {'type': 'bool', 'default': 'True', 'description': None}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': None}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': None}, 'render': {'type': 'bool', 'default': 'True', 'description': None}, 'key': {'type': 'int | str | tuple[int | str, Ellipsis] | None', 'default': 'None', 'description': None}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': None}}, 'postprocess': {'value': {'type': 'Any', 'description': None}}, 'preprocess': {'return': {'type': 'typing.Optional[typing.Dict[str, typing.Any]][\n typing.Dict[str, typing.Any][str, Any], None\n]', 'description': 'Dict[str, Any] | None: The input payload, returned unchanged.'}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the CreditsPanel changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'CreditsPanel': []}}}
|
| 7 |
+
|
| 8 |
+
abs_path = os.path.join(os.path.dirname(__file__), "css.css")
|
| 9 |
+
|
| 10 |
+
with gr.Blocks(
|
| 11 |
+
css=abs_path,
|
| 12 |
+
theme=gr.themes.Ocean(
|
| 13 |
+
font_mono=[
|
| 14 |
+
gr.themes.GoogleFont("Inconsolata"),
|
| 15 |
+
"monospace",
|
| 16 |
+
],
|
| 17 |
+
),
|
| 18 |
+
) as demo:
|
| 19 |
+
gr.Markdown(
|
| 20 |
+
"""
|
| 21 |
+
# `gradio_creditspanel`
|
| 22 |
+
|
| 23 |
+
<div style="display: flex; gap: 7px;">
|
| 24 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
| 25 |
+
</div>
|
| 26 |
+
|
| 27 |
+
Credits Panel for Gradio UI
|
| 28 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 29 |
+
app.render()
|
| 30 |
+
gr.Markdown(
|
| 31 |
+
"""
|
| 32 |
+
## Installation
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
pip install gradio_creditspanel
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
## Usage
|
| 39 |
+
|
| 40 |
+
```python
|
| 41 |
+
\"\"\"
|
| 42 |
+
app.py
|
| 43 |
+
|
| 44 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 45 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 46 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 47 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 48 |
+
\"\"\"
|
| 49 |
+
|
| 50 |
+
import gradio as gr
|
| 51 |
+
from gradio_creditspanel import CreditsPanel
|
| 52 |
+
import os
|
| 53 |
+
|
| 54 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 55 |
+
# This section prepares all necessary assets and data for the demo.
|
| 56 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 57 |
+
|
| 58 |
+
def setup_demo_files():
|
| 59 |
+
\"\"\"
|
| 60 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 61 |
+
This makes the application self-contained and easy to run.
|
| 62 |
+
\"\"\"
|
| 63 |
+
# Create dummy license files
|
| 64 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 65 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 66 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 67 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 68 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 69 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 70 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 71 |
+
|
| 72 |
+
# Create a placeholder logo if it doesn't exist
|
| 73 |
+
os.makedirs("assets", exist_ok=True)
|
| 74 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 75 |
+
with open("./assets/logo.webp", "w") as f:
|
| 76 |
+
f.write("Placeholder WebP logo")
|
| 77 |
+
|
| 78 |
+
# Initial data for the credits roll
|
| 79 |
+
credits_list = [
|
| 80 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 81 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 82 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 83 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 84 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 85 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 86 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 87 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 88 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 89 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 90 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 91 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 92 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 93 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 94 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
# Paths to license files
|
| 98 |
+
license_paths = {
|
| 99 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 100 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 104 |
+
DEFAULT_SPEEDS = {
|
| 105 |
+
"scroll": 40.0,
|
| 106 |
+
"starwars": 80.0,
|
| 107 |
+
"matrix": 40.0
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 111 |
+
# These functions define the application's interactive logic.
|
| 112 |
+
|
| 113 |
+
def update_panel(
|
| 114 |
+
effect: str, speed: float, base_font_size: float,
|
| 115 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 116 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 117 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 118 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 119 |
+
scroll_name_color: str | None
|
| 120 |
+
) -> dict:
|
| 121 |
+
\"\"\"
|
| 122 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 123 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 124 |
+
\"\"\"
|
| 125 |
+
return gr.update(
|
| 126 |
+
visible=True,
|
| 127 |
+
effect=effect,
|
| 128 |
+
speed=speed,
|
| 129 |
+
base_font_size=base_font_size,
|
| 130 |
+
intro_title=intro_title,
|
| 131 |
+
intro_subtitle=intro_subtitle,
|
| 132 |
+
sidebar_position=sidebar_position,
|
| 133 |
+
show_logo=show_logo,
|
| 134 |
+
show_licenses=show_licenses,
|
| 135 |
+
logo_position=logo_position,
|
| 136 |
+
logo_sizing=logo_sizing,
|
| 137 |
+
logo_width=logo_width,
|
| 138 |
+
logo_height=logo_height,
|
| 139 |
+
scroll_background_color=scroll_background_color,
|
| 140 |
+
scroll_title_color=scroll_title_color,
|
| 141 |
+
scroll_name_color=scroll_name_color,
|
| 142 |
+
value=credits_list # The list of credits to display
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 146 |
+
\"\"\"
|
| 147 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 148 |
+
animation effect is changed.
|
| 149 |
+
\"\"\"
|
| 150 |
+
font_size = 1.5
|
| 151 |
+
if effect == "starwars":
|
| 152 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 153 |
+
|
| 154 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 155 |
+
return speed, font_size
|
| 156 |
+
|
| 157 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 158 |
+
# This section constructs the user interface using gr.Blocks.
|
| 159 |
+
|
| 160 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 161 |
+
gr.Markdown(
|
| 162 |
+
\"\"\"
|
| 163 |
+
# Interactive CreditsPanel Demo
|
| 164 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 165 |
+
\"\"\"
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
with gr.Sidebar(position="right"):
|
| 169 |
+
gr.Markdown("### Effects Settings")
|
| 170 |
+
effect_radio = gr.Radio(
|
| 171 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 172 |
+
info="Select the visual style for the credits."
|
| 173 |
+
)
|
| 174 |
+
speed_slider = gr.Slider(
|
| 175 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 176 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 177 |
+
)
|
| 178 |
+
font_size_slider = gr.Slider(
|
| 179 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 180 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
gr.Markdown("### Intro Text")
|
| 184 |
+
intro_title_input = gr.Textbox(
|
| 185 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 186 |
+
)
|
| 187 |
+
intro_subtitle_input = gr.Textbox(
|
| 188 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
gr.Markdown("### Layout & Visibility")
|
| 192 |
+
sidebar_position_radio = gr.Radio(
|
| 193 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 194 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 195 |
+
)
|
| 196 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 197 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 198 |
+
|
| 199 |
+
gr.Markdown("### Logo Customization")
|
| 200 |
+
logo_position_radio = gr.Radio(
|
| 201 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 202 |
+
)
|
| 203 |
+
logo_sizing_radio = gr.Radio(
|
| 204 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 205 |
+
)
|
| 206 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 207 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 208 |
+
|
| 209 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 210 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 211 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 212 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 213 |
+
|
| 214 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 215 |
+
panel = CreditsPanel(
|
| 216 |
+
credits=credits_list,
|
| 217 |
+
licenses=license_paths,
|
| 218 |
+
effect="scroll",
|
| 219 |
+
height=500,
|
| 220 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 221 |
+
base_font_size=1.5,
|
| 222 |
+
intro_title="Gradio",
|
| 223 |
+
intro_subtitle="The best UI framework",
|
| 224 |
+
sidebar_position="right",
|
| 225 |
+
logo_path="./assets/logo.webp",
|
| 226 |
+
show_logo=True,
|
| 227 |
+
show_licenses=True,
|
| 228 |
+
logo_position="center",
|
| 229 |
+
logo_sizing="resize",
|
| 230 |
+
logo_width="200px",
|
| 231 |
+
logo_height="100px",
|
| 232 |
+
scroll_background_color="#000000",
|
| 233 |
+
scroll_title_color="#FFFFFF",
|
| 234 |
+
scroll_name_color="#FFFFFF",
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
# List of all input components that should trigger a panel update
|
| 238 |
+
inputs = [
|
| 239 |
+
effect_radio, speed_slider, font_size_slider,
|
| 240 |
+
intro_title_input, intro_subtitle_input,
|
| 241 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 242 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 243 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 244 |
+
]
|
| 245 |
+
|
| 246 |
+
# --- 4. EVENT BINDING ---
|
| 247 |
+
# Connect the UI controls to the handler functions.
|
| 248 |
+
|
| 249 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 250 |
+
effect_radio.change(
|
| 251 |
+
fn=update_ui_on_effect_change,
|
| 252 |
+
inputs=effect_radio,
|
| 253 |
+
outputs=[speed_slider, font_size_slider]
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
# General event: any change in an input control updates the main panel
|
| 257 |
+
for input_component in inputs:
|
| 258 |
+
input_component.change(
|
| 259 |
+
fn=update_panel,
|
| 260 |
+
inputs=inputs,
|
| 261 |
+
outputs=panel
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
# --- 5. APP LAUNCH ---
|
| 265 |
+
if __name__ == "__main__":
|
| 266 |
+
setup_demo_files()
|
| 267 |
+
demo.launch()
|
| 268 |
+
```
|
| 269 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
gr.Markdown("""
|
| 273 |
+
## `CreditsPanel`
|
| 274 |
+
|
| 275 |
+
### Initialization
|
| 276 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 277 |
+
|
| 278 |
+
gr.ParamViewer(value=_docs["CreditsPanel"]["members"]["__init__"], linkify=[])
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
gr.Markdown("### Events")
|
| 282 |
+
gr.ParamViewer(value=_docs["CreditsPanel"]["events"], linkify=['Event'])
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
gr.Markdown("""
|
| 288 |
+
|
| 289 |
+
### User function
|
| 290 |
+
|
| 291 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
| 292 |
+
|
| 293 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
| 294 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
| 295 |
+
|
| 296 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
| 297 |
+
|
| 298 |
+
- **As input:** Is passed, dict[str, Any] | None: The input payload, returned unchanged.
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
```python
|
| 302 |
+
def predict(
|
| 303 |
+
value: typing.Optional[typing.Dict[str, typing.Any]][
|
| 304 |
+
typing.Dict[str, typing.Any][str, Any], None
|
| 305 |
+
]
|
| 306 |
+
) -> Any:
|
| 307 |
+
return value
|
| 308 |
+
```
|
| 309 |
+
""", elem_classes=["md-custom", "CreditsPanel-user-fn"], header_links=True)
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
demo.load(None, js=r"""function() {
|
| 315 |
+
const refs = {};
|
| 316 |
+
const user_fn_refs = {
|
| 317 |
+
CreditsPanel: [], };
|
| 318 |
+
requestAnimationFrame(() => {
|
| 319 |
+
|
| 320 |
+
Object.entries(user_fn_refs).forEach(([key, refs]) => {
|
| 321 |
+
if (refs.length > 0) {
|
| 322 |
+
const el = document.querySelector(`.${key}-user-fn`);
|
| 323 |
+
if (!el) return;
|
| 324 |
+
refs.forEach(ref => {
|
| 325 |
+
el.innerHTML = el.innerHTML.replace(
|
| 326 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
| 327 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
| 328 |
+
);
|
| 329 |
+
})
|
| 330 |
+
}
|
| 331 |
+
})
|
| 332 |
+
|
| 333 |
+
Object.entries(refs).forEach(([key, refs]) => {
|
| 334 |
+
if (refs.length > 0) {
|
| 335 |
+
const el = document.querySelector(`.${key}`);
|
| 336 |
+
if (!el) return;
|
| 337 |
+
refs.forEach(ref => {
|
| 338 |
+
el.innerHTML = el.innerHTML.replace(
|
| 339 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
| 340 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
| 341 |
+
);
|
| 342 |
+
})
|
| 343 |
+
}
|
| 344 |
+
})
|
| 345 |
+
})
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
""")
|
| 349 |
+
|
| 350 |
+
demo.launch()
|
src/.gitignore
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.eggs/
|
| 2 |
+
dist/
|
| 3 |
+
.vscode/
|
| 4 |
+
*.pyc
|
| 5 |
+
__pycache__/
|
| 6 |
+
*.py[cod]
|
| 7 |
+
*$py.class
|
| 8 |
+
__tmp/*
|
| 9 |
+
*.pyi
|
| 10 |
+
.mypycache
|
| 11 |
+
.ruff_cache
|
| 12 |
+
node_modules
|
| 13 |
+
backend/**/templates/
|
| 14 |
+
README_TEMPLATE.md
|
src/.vscode/launch.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
// Use IntelliSense to learn about possible attributes.
|
| 3 |
+
// Hover to view descriptions of existing attributes.
|
| 4 |
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
| 5 |
+
"version": "0.2.0",
|
| 6 |
+
"configurations": [
|
| 7 |
+
{
|
| 8 |
+
"name": "Python Debugger: Current File",
|
| 9 |
+
"type": "debugpy",
|
| 10 |
+
"request": "launch",
|
| 11 |
+
"program": "${file}",
|
| 12 |
+
"console": "integratedTerminal",
|
| 13 |
+
"justMyCode": false
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"name": "Gradio dev (Python attach)",
|
| 17 |
+
"type": "debugpy",
|
| 18 |
+
"request": "attach",
|
| 19 |
+
"processId": "${command:pickProcess}",
|
| 20 |
+
"justMyCode": false
|
| 21 |
+
},
|
| 22 |
+
{
|
| 23 |
+
"name": "Gradio dev (Svelte attach)",
|
| 24 |
+
"type": "chrome",
|
| 25 |
+
"request": "attach",
|
| 26 |
+
"port": 9222,
|
| 27 |
+
}
|
| 28 |
+
]
|
| 29 |
+
}
|
src/LICENSES/Apache.txt
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
src/LICENSES/MIT.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 Author
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
src/README.md
ADDED
|
@@ -0,0 +1,781 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
tags: [gradio-custom-component, HTML]
|
| 3 |
+
title: gradio_creditspanel
|
| 4 |
+
short_description: Credits Panel for Gradio UI
|
| 5 |
+
colorFrom: blue
|
| 6 |
+
colorTo: yellow
|
| 7 |
+
sdk: gradio
|
| 8 |
+
pinned: false
|
| 9 |
+
app_file: space.py
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# `gradio_creditspanel`
|
| 13 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20blue"> <a href="https://huggingface.co/spaces/elismasilva/gradio_creditspanel"><img src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Demo-blue"></a><p><span>💻 <a href='https://github.com/DEVAIEXP/gradio_component_creditspanel'>Component GitHub Code</a></span></p>
|
| 14 |
+
|
| 15 |
+
Credits Panel for Gradio UI
|
| 16 |
+
|
| 17 |
+
## Installation
|
| 18 |
+
|
| 19 |
+
```bash
|
| 20 |
+
pip install gradio_creditspanel
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
## Usage
|
| 24 |
+
|
| 25 |
+
```python
|
| 26 |
+
"""
|
| 27 |
+
app.py
|
| 28 |
+
|
| 29 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 30 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 31 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 32 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
import gradio as gr
|
| 36 |
+
from gradio_creditspanel import CreditsPanel
|
| 37 |
+
import os
|
| 38 |
+
|
| 39 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 40 |
+
# This section prepares all necessary assets and data for the demo.
|
| 41 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 42 |
+
|
| 43 |
+
def setup_demo_files():
|
| 44 |
+
"""
|
| 45 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 46 |
+
This makes the application self-contained and easy to run.
|
| 47 |
+
"""
|
| 48 |
+
# Create dummy license files
|
| 49 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 50 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 51 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 52 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 53 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 54 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 55 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 56 |
+
|
| 57 |
+
# Create a placeholder logo if it doesn't exist
|
| 58 |
+
os.makedirs("assets", exist_ok=True)
|
| 59 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 60 |
+
with open("./assets/logo.webp", "w") as f:
|
| 61 |
+
f.write("Placeholder WebP logo")
|
| 62 |
+
|
| 63 |
+
# Initial data for the credits roll
|
| 64 |
+
credits_list = [
|
| 65 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 66 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 67 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 68 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 69 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 70 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 71 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 72 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 73 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 74 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 75 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 76 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 77 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 78 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 79 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
# Paths to license files
|
| 83 |
+
license_paths = {
|
| 84 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 85 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 89 |
+
DEFAULT_SPEEDS = {
|
| 90 |
+
"scroll": 40.0,
|
| 91 |
+
"starwars": 80.0,
|
| 92 |
+
"matrix": 40.0
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 96 |
+
# These functions define the application's interactive logic.
|
| 97 |
+
|
| 98 |
+
def update_panel(
|
| 99 |
+
effect: str, speed: float, base_font_size: float,
|
| 100 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 101 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 102 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 103 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 104 |
+
scroll_name_color: str | None
|
| 105 |
+
) -> dict:
|
| 106 |
+
"""
|
| 107 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 108 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 109 |
+
"""
|
| 110 |
+
return gr.update(
|
| 111 |
+
visible=True,
|
| 112 |
+
effect=effect,
|
| 113 |
+
speed=speed,
|
| 114 |
+
base_font_size=base_font_size,
|
| 115 |
+
intro_title=intro_title,
|
| 116 |
+
intro_subtitle=intro_subtitle,
|
| 117 |
+
sidebar_position=sidebar_position,
|
| 118 |
+
show_logo=show_logo,
|
| 119 |
+
show_licenses=show_licenses,
|
| 120 |
+
logo_position=logo_position,
|
| 121 |
+
logo_sizing=logo_sizing,
|
| 122 |
+
logo_width=logo_width,
|
| 123 |
+
logo_height=logo_height,
|
| 124 |
+
scroll_background_color=scroll_background_color,
|
| 125 |
+
scroll_title_color=scroll_title_color,
|
| 126 |
+
scroll_name_color=scroll_name_color,
|
| 127 |
+
value=credits_list # The list of credits to display
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 131 |
+
"""
|
| 132 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 133 |
+
animation effect is changed.
|
| 134 |
+
"""
|
| 135 |
+
font_size = 1.5
|
| 136 |
+
if effect == "starwars":
|
| 137 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 138 |
+
|
| 139 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 140 |
+
return speed, font_size
|
| 141 |
+
|
| 142 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 143 |
+
# This section constructs the user interface using gr.Blocks.
|
| 144 |
+
|
| 145 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 146 |
+
gr.Markdown(
|
| 147 |
+
"""
|
| 148 |
+
# Interactive CreditsPanel Demo
|
| 149 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 150 |
+
"""
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
with gr.Sidebar(position="right"):
|
| 154 |
+
gr.Markdown("### Effects Settings")
|
| 155 |
+
effect_radio = gr.Radio(
|
| 156 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 157 |
+
info="Select the visual style for the credits."
|
| 158 |
+
)
|
| 159 |
+
speed_slider = gr.Slider(
|
| 160 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 161 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 162 |
+
)
|
| 163 |
+
font_size_slider = gr.Slider(
|
| 164 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 165 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
gr.Markdown("### Intro Text")
|
| 169 |
+
intro_title_input = gr.Textbox(
|
| 170 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 171 |
+
)
|
| 172 |
+
intro_subtitle_input = gr.Textbox(
|
| 173 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
gr.Markdown("### Layout & Visibility")
|
| 177 |
+
sidebar_position_radio = gr.Radio(
|
| 178 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 179 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 180 |
+
)
|
| 181 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 182 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 183 |
+
|
| 184 |
+
gr.Markdown("### Logo Customization")
|
| 185 |
+
logo_position_radio = gr.Radio(
|
| 186 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 187 |
+
)
|
| 188 |
+
logo_sizing_radio = gr.Radio(
|
| 189 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 190 |
+
)
|
| 191 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 192 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 193 |
+
|
| 194 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 195 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 196 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 197 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 198 |
+
|
| 199 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 200 |
+
panel = CreditsPanel(
|
| 201 |
+
credits=credits_list,
|
| 202 |
+
licenses=license_paths,
|
| 203 |
+
effect="scroll",
|
| 204 |
+
height=500,
|
| 205 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 206 |
+
base_font_size=1.5,
|
| 207 |
+
intro_title="Gradio",
|
| 208 |
+
intro_subtitle="The best UI framework",
|
| 209 |
+
sidebar_position="right",
|
| 210 |
+
logo_path="./assets/logo.webp",
|
| 211 |
+
show_logo=True,
|
| 212 |
+
show_licenses=True,
|
| 213 |
+
logo_position="center",
|
| 214 |
+
logo_sizing="resize",
|
| 215 |
+
logo_width="200px",
|
| 216 |
+
logo_height="100px",
|
| 217 |
+
scroll_background_color="#000000",
|
| 218 |
+
scroll_title_color="#FFFFFF",
|
| 219 |
+
scroll_name_color="#FFFFFF",
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
# List of all input components that should trigger a panel update
|
| 223 |
+
inputs = [
|
| 224 |
+
effect_radio, speed_slider, font_size_slider,
|
| 225 |
+
intro_title_input, intro_subtitle_input,
|
| 226 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 227 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 228 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 229 |
+
]
|
| 230 |
+
|
| 231 |
+
# --- 4. EVENT BINDING ---
|
| 232 |
+
# Connect the UI controls to the handler functions.
|
| 233 |
+
|
| 234 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 235 |
+
effect_radio.change(
|
| 236 |
+
fn=update_ui_on_effect_change,
|
| 237 |
+
inputs=effect_radio,
|
| 238 |
+
outputs=[speed_slider, font_size_slider]
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
# General event: any change in an input control updates the main panel
|
| 242 |
+
for input_component in inputs:
|
| 243 |
+
input_component.change(
|
| 244 |
+
fn=update_panel,
|
| 245 |
+
inputs=inputs,
|
| 246 |
+
outputs=panel
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
# --- 5. APP LAUNCH ---
|
| 250 |
+
if __name__ == "__main__":
|
| 251 |
+
setup_demo_files()
|
| 252 |
+
demo.launch()
|
| 253 |
+
```
|
| 254 |
+
|
| 255 |
+
## `CreditsPanel`
|
| 256 |
+
|
| 257 |
+
### Initialization
|
| 258 |
+
|
| 259 |
+
<table>
|
| 260 |
+
<thead>
|
| 261 |
+
<tr>
|
| 262 |
+
<th align="left">name</th>
|
| 263 |
+
<th align="left" style="width: 25%;">type</th>
|
| 264 |
+
<th align="left">default</th>
|
| 265 |
+
<th align="left">description</th>
|
| 266 |
+
</tr>
|
| 267 |
+
</thead>
|
| 268 |
+
<tbody>
|
| 269 |
+
<tr>
|
| 270 |
+
<td align="left"><code>value</code></td>
|
| 271 |
+
<td align="left" style="width: 25%;">
|
| 272 |
+
|
| 273 |
+
```python
|
| 274 |
+
Any
|
| 275 |
+
```
|
| 276 |
+
|
| 277 |
+
</td>
|
| 278 |
+
<td align="left"><code>None</code></td>
|
| 279 |
+
<td align="left">None</td>
|
| 280 |
+
</tr>
|
| 281 |
+
|
| 282 |
+
<tr>
|
| 283 |
+
<td align="left"><code>credits</code></td>
|
| 284 |
+
<td align="left" style="width: 25%;">
|
| 285 |
+
|
| 286 |
+
```python
|
| 287 |
+
typing.Union[
|
| 288 |
+
typing.List[typing.Dict[str, str]],
|
| 289 |
+
typing.Callable,
|
| 290 |
+
NoneType,
|
| 291 |
+
][
|
| 292 |
+
typing.List[typing.Dict[str, str]][
|
| 293 |
+
typing.Dict[str, str][str, str]
|
| 294 |
+
],
|
| 295 |
+
Callable,
|
| 296 |
+
None,
|
| 297 |
+
]
|
| 298 |
+
```
|
| 299 |
+
|
| 300 |
+
</td>
|
| 301 |
+
<td align="left"><code>None</code></td>
|
| 302 |
+
<td align="left">None</td>
|
| 303 |
+
</tr>
|
| 304 |
+
|
| 305 |
+
<tr>
|
| 306 |
+
<td align="left"><code>height</code></td>
|
| 307 |
+
<td align="left" style="width: 25%;">
|
| 308 |
+
|
| 309 |
+
```python
|
| 310 |
+
int | str | None
|
| 311 |
+
```
|
| 312 |
+
|
| 313 |
+
</td>
|
| 314 |
+
<td align="left"><code>None</code></td>
|
| 315 |
+
<td align="left">None</td>
|
| 316 |
+
</tr>
|
| 317 |
+
|
| 318 |
+
<tr>
|
| 319 |
+
<td align="left"><code>width</code></td>
|
| 320 |
+
<td align="left" style="width: 25%;">
|
| 321 |
+
|
| 322 |
+
```python
|
| 323 |
+
int | str | None
|
| 324 |
+
```
|
| 325 |
+
|
| 326 |
+
</td>
|
| 327 |
+
<td align="left"><code>None</code></td>
|
| 328 |
+
<td align="left">None</td>
|
| 329 |
+
</tr>
|
| 330 |
+
|
| 331 |
+
<tr>
|
| 332 |
+
<td align="left"><code>licenses</code></td>
|
| 333 |
+
<td align="left" style="width: 25%;">
|
| 334 |
+
|
| 335 |
+
```python
|
| 336 |
+
typing.Optional[typing.Dict[str, str | pathlib.Path]][
|
| 337 |
+
typing.Dict[str, str | pathlib.Path][
|
| 338 |
+
str, str | pathlib.Path
|
| 339 |
+
],
|
| 340 |
+
None,
|
| 341 |
+
]
|
| 342 |
+
```
|
| 343 |
+
|
| 344 |
+
</td>
|
| 345 |
+
<td align="left"><code>None</code></td>
|
| 346 |
+
<td align="left">None</td>
|
| 347 |
+
</tr>
|
| 348 |
+
|
| 349 |
+
<tr>
|
| 350 |
+
<td align="left"><code>effect</code></td>
|
| 351 |
+
<td align="left" style="width: 25%;">
|
| 352 |
+
|
| 353 |
+
```python
|
| 354 |
+
"scroll" | "starwars" | "matrix"
|
| 355 |
+
```
|
| 356 |
+
|
| 357 |
+
</td>
|
| 358 |
+
<td align="left"><code>"scroll"</code></td>
|
| 359 |
+
<td align="left">None</td>
|
| 360 |
+
</tr>
|
| 361 |
+
|
| 362 |
+
<tr>
|
| 363 |
+
<td align="left"><code>speed</code></td>
|
| 364 |
+
<td align="left" style="width: 25%;">
|
| 365 |
+
|
| 366 |
+
```python
|
| 367 |
+
float
|
| 368 |
+
```
|
| 369 |
+
|
| 370 |
+
</td>
|
| 371 |
+
<td align="left"><code>40.0</code></td>
|
| 372 |
+
<td align="left">None</td>
|
| 373 |
+
</tr>
|
| 374 |
+
|
| 375 |
+
<tr>
|
| 376 |
+
<td align="left"><code>base_font_size</code></td>
|
| 377 |
+
<td align="left" style="width: 25%;">
|
| 378 |
+
|
| 379 |
+
```python
|
| 380 |
+
float
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
</td>
|
| 384 |
+
<td align="left"><code>1.5</code></td>
|
| 385 |
+
<td align="left">None</td>
|
| 386 |
+
</tr>
|
| 387 |
+
|
| 388 |
+
<tr>
|
| 389 |
+
<td align="left"><code>intro_title</code></td>
|
| 390 |
+
<td align="left" style="width: 25%;">
|
| 391 |
+
|
| 392 |
+
```python
|
| 393 |
+
str | None
|
| 394 |
+
```
|
| 395 |
+
|
| 396 |
+
</td>
|
| 397 |
+
<td align="left"><code>None</code></td>
|
| 398 |
+
<td align="left">None</td>
|
| 399 |
+
</tr>
|
| 400 |
+
|
| 401 |
+
<tr>
|
| 402 |
+
<td align="left"><code>intro_subtitle</code></td>
|
| 403 |
+
<td align="left" style="width: 25%;">
|
| 404 |
+
|
| 405 |
+
```python
|
| 406 |
+
str | None
|
| 407 |
+
```
|
| 408 |
+
|
| 409 |
+
</td>
|
| 410 |
+
<td align="left"><code>None</code></td>
|
| 411 |
+
<td align="left">None</td>
|
| 412 |
+
</tr>
|
| 413 |
+
|
| 414 |
+
<tr>
|
| 415 |
+
<td align="left"><code>sidebar_position</code></td>
|
| 416 |
+
<td align="left" style="width: 25%;">
|
| 417 |
+
|
| 418 |
+
```python
|
| 419 |
+
"right" | "bottom"
|
| 420 |
+
```
|
| 421 |
+
|
| 422 |
+
</td>
|
| 423 |
+
<td align="left"><code>"right"</code></td>
|
| 424 |
+
<td align="left">None</td>
|
| 425 |
+
</tr>
|
| 426 |
+
|
| 427 |
+
<tr>
|
| 428 |
+
<td align="left"><code>logo_path</code></td>
|
| 429 |
+
<td align="left" style="width: 25%;">
|
| 430 |
+
|
| 431 |
+
```python
|
| 432 |
+
str | pathlib.Path | None
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
</td>
|
| 436 |
+
<td align="left"><code>None</code></td>
|
| 437 |
+
<td align="left">None</td>
|
| 438 |
+
</tr>
|
| 439 |
+
|
| 440 |
+
<tr>
|
| 441 |
+
<td align="left"><code>show_logo</code></td>
|
| 442 |
+
<td align="left" style="width: 25%;">
|
| 443 |
+
|
| 444 |
+
```python
|
| 445 |
+
bool
|
| 446 |
+
```
|
| 447 |
+
|
| 448 |
+
</td>
|
| 449 |
+
<td align="left"><code>True</code></td>
|
| 450 |
+
<td align="left">None</td>
|
| 451 |
+
</tr>
|
| 452 |
+
|
| 453 |
+
<tr>
|
| 454 |
+
<td align="left"><code>show_licenses</code></td>
|
| 455 |
+
<td align="left" style="width: 25%;">
|
| 456 |
+
|
| 457 |
+
```python
|
| 458 |
+
bool
|
| 459 |
+
```
|
| 460 |
+
|
| 461 |
+
</td>
|
| 462 |
+
<td align="left"><code>True</code></td>
|
| 463 |
+
<td align="left">None</td>
|
| 464 |
+
</tr>
|
| 465 |
+
|
| 466 |
+
<tr>
|
| 467 |
+
<td align="left"><code>logo_position</code></td>
|
| 468 |
+
<td align="left" style="width: 25%;">
|
| 469 |
+
|
| 470 |
+
```python
|
| 471 |
+
"center" | "left" | "right"
|
| 472 |
+
```
|
| 473 |
+
|
| 474 |
+
</td>
|
| 475 |
+
<td align="left"><code>"center"</code></td>
|
| 476 |
+
<td align="left">None</td>
|
| 477 |
+
</tr>
|
| 478 |
+
|
| 479 |
+
<tr>
|
| 480 |
+
<td align="left"><code>logo_sizing</code></td>
|
| 481 |
+
<td align="left" style="width: 25%;">
|
| 482 |
+
|
| 483 |
+
```python
|
| 484 |
+
"stretch" | "crop" | "resize"
|
| 485 |
+
```
|
| 486 |
+
|
| 487 |
+
</td>
|
| 488 |
+
<td align="left"><code>"resize"</code></td>
|
| 489 |
+
<td align="left">None</td>
|
| 490 |
+
</tr>
|
| 491 |
+
|
| 492 |
+
<tr>
|
| 493 |
+
<td align="left"><code>logo_width</code></td>
|
| 494 |
+
<td align="left" style="width: 25%;">
|
| 495 |
+
|
| 496 |
+
```python
|
| 497 |
+
int | str | None
|
| 498 |
+
```
|
| 499 |
+
|
| 500 |
+
</td>
|
| 501 |
+
<td align="left"><code>None</code></td>
|
| 502 |
+
<td align="left">None</td>
|
| 503 |
+
</tr>
|
| 504 |
+
|
| 505 |
+
<tr>
|
| 506 |
+
<td align="left"><code>logo_height</code></td>
|
| 507 |
+
<td align="left" style="width: 25%;">
|
| 508 |
+
|
| 509 |
+
```python
|
| 510 |
+
int | str | None
|
| 511 |
+
```
|
| 512 |
+
|
| 513 |
+
</td>
|
| 514 |
+
<td align="left"><code>None</code></td>
|
| 515 |
+
<td align="left">None</td>
|
| 516 |
+
</tr>
|
| 517 |
+
|
| 518 |
+
<tr>
|
| 519 |
+
<td align="left"><code>scroll_background_color</code></td>
|
| 520 |
+
<td align="left" style="width: 25%;">
|
| 521 |
+
|
| 522 |
+
```python
|
| 523 |
+
str | None
|
| 524 |
+
```
|
| 525 |
+
|
| 526 |
+
</td>
|
| 527 |
+
<td align="left"><code>None</code></td>
|
| 528 |
+
<td align="left">None</td>
|
| 529 |
+
</tr>
|
| 530 |
+
|
| 531 |
+
<tr>
|
| 532 |
+
<td align="left"><code>scroll_title_color</code></td>
|
| 533 |
+
<td align="left" style="width: 25%;">
|
| 534 |
+
|
| 535 |
+
```python
|
| 536 |
+
str | None
|
| 537 |
+
```
|
| 538 |
+
|
| 539 |
+
</td>
|
| 540 |
+
<td align="left"><code>None</code></td>
|
| 541 |
+
<td align="left">None</td>
|
| 542 |
+
</tr>
|
| 543 |
+
|
| 544 |
+
<tr>
|
| 545 |
+
<td align="left"><code>scroll_name_color</code></td>
|
| 546 |
+
<td align="left" style="width: 25%;">
|
| 547 |
+
|
| 548 |
+
```python
|
| 549 |
+
str | None
|
| 550 |
+
```
|
| 551 |
+
|
| 552 |
+
</td>
|
| 553 |
+
<td align="left"><code>None</code></td>
|
| 554 |
+
<td align="left">None</td>
|
| 555 |
+
</tr>
|
| 556 |
+
|
| 557 |
+
<tr>
|
| 558 |
+
<td align="left"><code>label</code></td>
|
| 559 |
+
<td align="left" style="width: 25%;">
|
| 560 |
+
|
| 561 |
+
```python
|
| 562 |
+
str | gradio.i18n.I18nData | None
|
| 563 |
+
```
|
| 564 |
+
|
| 565 |
+
</td>
|
| 566 |
+
<td align="left"><code>None</code></td>
|
| 567 |
+
<td align="left">None</td>
|
| 568 |
+
</tr>
|
| 569 |
+
|
| 570 |
+
<tr>
|
| 571 |
+
<td align="left"><code>every</code></td>
|
| 572 |
+
<td align="left" style="width: 25%;">
|
| 573 |
+
|
| 574 |
+
```python
|
| 575 |
+
float | None
|
| 576 |
+
```
|
| 577 |
+
|
| 578 |
+
</td>
|
| 579 |
+
<td align="left"><code>None</code></td>
|
| 580 |
+
<td align="left">None</td>
|
| 581 |
+
</tr>
|
| 582 |
+
|
| 583 |
+
<tr>
|
| 584 |
+
<td align="left"><code>inputs</code></td>
|
| 585 |
+
<td align="left" style="width: 25%;">
|
| 586 |
+
|
| 587 |
+
```python
|
| 588 |
+
typing.Union[
|
| 589 |
+
gradio.components.base.Component,
|
| 590 |
+
typing.Sequence[gradio.components.base.Component],
|
| 591 |
+
set[gradio.components.base.Component],
|
| 592 |
+
NoneType,
|
| 593 |
+
][
|
| 594 |
+
gradio.components.base.Component,
|
| 595 |
+
typing.Sequence[gradio.components.base.Component][
|
| 596 |
+
gradio.components.base.Component
|
| 597 |
+
],
|
| 598 |
+
set[gradio.components.base.Component],
|
| 599 |
+
None,
|
| 600 |
+
]
|
| 601 |
+
```
|
| 602 |
+
|
| 603 |
+
</td>
|
| 604 |
+
<td align="left"><code>None</code></td>
|
| 605 |
+
<td align="left">None</td>
|
| 606 |
+
</tr>
|
| 607 |
+
|
| 608 |
+
<tr>
|
| 609 |
+
<td align="left"><code>show_label</code></td>
|
| 610 |
+
<td align="left" style="width: 25%;">
|
| 611 |
+
|
| 612 |
+
```python
|
| 613 |
+
bool
|
| 614 |
+
```
|
| 615 |
+
|
| 616 |
+
</td>
|
| 617 |
+
<td align="left"><code>False</code></td>
|
| 618 |
+
<td align="left">None</td>
|
| 619 |
+
</tr>
|
| 620 |
+
|
| 621 |
+
<tr>
|
| 622 |
+
<td align="left"><code>container</code></td>
|
| 623 |
+
<td align="left" style="width: 25%;">
|
| 624 |
+
|
| 625 |
+
```python
|
| 626 |
+
bool
|
| 627 |
+
```
|
| 628 |
+
|
| 629 |
+
</td>
|
| 630 |
+
<td align="left"><code>True</code></td>
|
| 631 |
+
<td align="left">None</td>
|
| 632 |
+
</tr>
|
| 633 |
+
|
| 634 |
+
<tr>
|
| 635 |
+
<td align="left"><code>scale</code></td>
|
| 636 |
+
<td align="left" style="width: 25%;">
|
| 637 |
+
|
| 638 |
+
```python
|
| 639 |
+
int | None
|
| 640 |
+
```
|
| 641 |
+
|
| 642 |
+
</td>
|
| 643 |
+
<td align="left"><code>None</code></td>
|
| 644 |
+
<td align="left">None</td>
|
| 645 |
+
</tr>
|
| 646 |
+
|
| 647 |
+
<tr>
|
| 648 |
+
<td align="left"><code>min_width</code></td>
|
| 649 |
+
<td align="left" style="width: 25%;">
|
| 650 |
+
|
| 651 |
+
```python
|
| 652 |
+
int
|
| 653 |
+
```
|
| 654 |
+
|
| 655 |
+
</td>
|
| 656 |
+
<td align="left"><code>160</code></td>
|
| 657 |
+
<td align="left">None</td>
|
| 658 |
+
</tr>
|
| 659 |
+
|
| 660 |
+
<tr>
|
| 661 |
+
<td align="left"><code>interactive</code></td>
|
| 662 |
+
<td align="left" style="width: 25%;">
|
| 663 |
+
|
| 664 |
+
```python
|
| 665 |
+
bool | None
|
| 666 |
+
```
|
| 667 |
+
|
| 668 |
+
</td>
|
| 669 |
+
<td align="left"><code>None</code></td>
|
| 670 |
+
<td align="left">None</td>
|
| 671 |
+
</tr>
|
| 672 |
+
|
| 673 |
+
<tr>
|
| 674 |
+
<td align="left"><code>visible</code></td>
|
| 675 |
+
<td align="left" style="width: 25%;">
|
| 676 |
+
|
| 677 |
+
```python
|
| 678 |
+
bool
|
| 679 |
+
```
|
| 680 |
+
|
| 681 |
+
</td>
|
| 682 |
+
<td align="left"><code>True</code></td>
|
| 683 |
+
<td align="left">None</td>
|
| 684 |
+
</tr>
|
| 685 |
+
|
| 686 |
+
<tr>
|
| 687 |
+
<td align="left"><code>elem_id</code></td>
|
| 688 |
+
<td align="left" style="width: 25%;">
|
| 689 |
+
|
| 690 |
+
```python
|
| 691 |
+
str | None
|
| 692 |
+
```
|
| 693 |
+
|
| 694 |
+
</td>
|
| 695 |
+
<td align="left"><code>None</code></td>
|
| 696 |
+
<td align="left">None</td>
|
| 697 |
+
</tr>
|
| 698 |
+
|
| 699 |
+
<tr>
|
| 700 |
+
<td align="left"><code>elem_classes</code></td>
|
| 701 |
+
<td align="left" style="width: 25%;">
|
| 702 |
+
|
| 703 |
+
```python
|
| 704 |
+
list[str] | str | None
|
| 705 |
+
```
|
| 706 |
+
|
| 707 |
+
</td>
|
| 708 |
+
<td align="left"><code>None</code></td>
|
| 709 |
+
<td align="left">None</td>
|
| 710 |
+
</tr>
|
| 711 |
+
|
| 712 |
+
<tr>
|
| 713 |
+
<td align="left"><code>render</code></td>
|
| 714 |
+
<td align="left" style="width: 25%;">
|
| 715 |
+
|
| 716 |
+
```python
|
| 717 |
+
bool
|
| 718 |
+
```
|
| 719 |
+
|
| 720 |
+
</td>
|
| 721 |
+
<td align="left"><code>True</code></td>
|
| 722 |
+
<td align="left">None</td>
|
| 723 |
+
</tr>
|
| 724 |
+
|
| 725 |
+
<tr>
|
| 726 |
+
<td align="left"><code>key</code></td>
|
| 727 |
+
<td align="left" style="width: 25%;">
|
| 728 |
+
|
| 729 |
+
```python
|
| 730 |
+
int | str | tuple[int | str, Ellipsis] | None
|
| 731 |
+
```
|
| 732 |
+
|
| 733 |
+
</td>
|
| 734 |
+
<td align="left"><code>None</code></td>
|
| 735 |
+
<td align="left">None</td>
|
| 736 |
+
</tr>
|
| 737 |
+
|
| 738 |
+
<tr>
|
| 739 |
+
<td align="left"><code>preserved_by_key</code></td>
|
| 740 |
+
<td align="left" style="width: 25%;">
|
| 741 |
+
|
| 742 |
+
```python
|
| 743 |
+
list[str] | str | None
|
| 744 |
+
```
|
| 745 |
+
|
| 746 |
+
</td>
|
| 747 |
+
<td align="left"><code>"value"</code></td>
|
| 748 |
+
<td align="left">None</td>
|
| 749 |
+
</tr>
|
| 750 |
+
</tbody></table>
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
### Events
|
| 754 |
+
|
| 755 |
+
| name | description |
|
| 756 |
+
|:-----|:------------|
|
| 757 |
+
| `change` | Triggered when the value of the CreditsPanel changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
|
| 758 |
+
|
| 759 |
+
|
| 760 |
+
|
| 761 |
+
### User function
|
| 762 |
+
|
| 763 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
| 764 |
+
|
| 765 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
| 766 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
| 767 |
+
|
| 768 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
| 769 |
+
|
| 770 |
+
- **As output:** Is passed, dict[str, Any] | None: The input payload, returned unchanged.
|
| 771 |
+
|
| 772 |
+
|
| 773 |
+
```python
|
| 774 |
+
def predict(
|
| 775 |
+
value: typing.Optional[typing.Dict[str, typing.Any]][
|
| 776 |
+
typing.Dict[str, typing.Any][str, Any], None
|
| 777 |
+
]
|
| 778 |
+
) -> Any:
|
| 779 |
+
return value
|
| 780 |
+
```
|
| 781 |
+
|
src/assets/logo.webp
ADDED
|
src/backend/gradio_creditspanel/__init__.py
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from .creditspanel import CreditsPanel
|
| 3 |
+
|
| 4 |
+
__all__ = ['CreditsPanel']
|
src/backend/gradio_creditspanel/creditspanel.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
from typing import Any, Dict, List, Literal, Callable, Sequence
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from gradio_client import handle_file
|
| 5 |
+
from gradio_client.utils import is_http_url_like
|
| 6 |
+
from gradio_client.documentation import document
|
| 7 |
+
from gradio.components import Component
|
| 8 |
+
from gradio.events import Events
|
| 9 |
+
from gradio.i18n import I18nData
|
| 10 |
+
import os
|
| 11 |
+
|
| 12 |
+
@document()
|
| 13 |
+
class CreditsPanel(Component):
|
| 14 |
+
"""
|
| 15 |
+
A Gradio component for displaying credits with customizable visual effects, such as scrolling or Star Wars-style animations.
|
| 16 |
+
Supports displaying a logo, licenses, and configurable text styling.
|
| 17 |
+
|
| 18 |
+
Attributes:
|
| 19 |
+
EVENTS (list): Supported events for the component, currently only `change`.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
EVENTS = [Events.change]
|
| 23 |
+
|
| 24 |
+
def __init__(
|
| 25 |
+
self,
|
| 26 |
+
value: Any = None,
|
| 27 |
+
credits: List[Dict[str, str]] | Callable | None = None,
|
| 28 |
+
*,
|
| 29 |
+
height: int | str | None = None,
|
| 30 |
+
width: int | str | None = None,
|
| 31 |
+
licenses: Dict[str, str | Path] | None = None,
|
| 32 |
+
effect: Literal["scroll", "starwars", "matrix"] = "scroll",
|
| 33 |
+
speed: float = 40.0,
|
| 34 |
+
base_font_size: float = 1.5,
|
| 35 |
+
intro_title: str | None = None,
|
| 36 |
+
intro_subtitle: str | None = None,
|
| 37 |
+
sidebar_position: Literal["right", "bottom"] = "right",
|
| 38 |
+
logo_path: str | Path | None = None,
|
| 39 |
+
show_logo: bool = True,
|
| 40 |
+
show_licenses: bool = True,
|
| 41 |
+
logo_position: Literal["center", "left", "right"] = "center",
|
| 42 |
+
logo_sizing: Literal["stretch", "crop", "resize"] = "resize",
|
| 43 |
+
logo_width: int | str | None = None,
|
| 44 |
+
logo_height: int | str | None = None,
|
| 45 |
+
scroll_background_color: str | None = None,
|
| 46 |
+
scroll_title_color: str | None = None,
|
| 47 |
+
scroll_name_color: str | None = None,
|
| 48 |
+
label: str | I18nData | None = None,
|
| 49 |
+
every: float | None = None,
|
| 50 |
+
inputs: Component | Sequence[Component] | set[Component] | None = None,
|
| 51 |
+
show_label: bool = False,
|
| 52 |
+
container: bool = True,
|
| 53 |
+
scale: int | None = None,
|
| 54 |
+
min_width: int = 160,
|
| 55 |
+
interactive: bool | None = None,
|
| 56 |
+
visible: bool = True,
|
| 57 |
+
elem_id: str | None = None,
|
| 58 |
+
elem_classes: list[str] | str | None = None,
|
| 59 |
+
render: bool = True,
|
| 60 |
+
key: int | str | tuple[int | str, ...] | None = None,
|
| 61 |
+
preserved_by_key: list[str] | str | None = "value",
|
| 62 |
+
):
|
| 63 |
+
"""
|
| 64 |
+
Initialize the CreditsPanel component.
|
| 65 |
+
|
| 66 |
+
Args:
|
| 67 |
+
value (Any, optional): Initial value for the component.
|
| 68 |
+
credits (List[Dict[str, str]] | Callable | None, optional): List of credits as dictionaries with 'title' and 'name' keys, or a callable that returns such a list.
|
| 69 |
+
height (int | str | None, optional): Height of the component (e.g., in pixels or CSS units).
|
| 70 |
+
width (int | str | None, optional): Width of the component (e.g., in pixels or CSS units).
|
| 71 |
+
licenses (Dict[str, str | Path] | None, optional): Dictionary mapping license names to file paths or content strings.
|
| 72 |
+
effect (Literal["scroll", "starwars", "matrix"], optional): Visual effect for credits display. Defaults to "scroll".
|
| 73 |
+
speed (float, optional): Animation speed in seconds. Defaults to 40.0.
|
| 74 |
+
base_font_size (float, optional): Base font size in rem for credits text. Defaults to 1.5.
|
| 75 |
+
intro_title (str | None, optional): Title for the intro section, if any.
|
| 76 |
+
intro_subtitle (str | None, optional): Subtitle for the intro section, if any.
|
| 77 |
+
sidebar_position (Literal["right", "bottom"], optional): Position of the licenses sidebar. Defaults to "right".
|
| 78 |
+
logo_path (str | Path | None, optional): Path or URL to the logo image.
|
| 79 |
+
show_logo (bool, optional): Whether to display the logo. Defaults to True.
|
| 80 |
+
show_licenses (bool, optional): Whether to display licenses. Defaults to True.
|
| 81 |
+
logo_position (Literal["center", "left", "right"], optional): Logo alignment. Defaults to "center".
|
| 82 |
+
logo_sizing (Literal["stretch", "crop", "resize"], optional): Logo sizing mode. Defaults to "resize".
|
| 83 |
+
logo_width (int | str | None, optional): Logo width (e.g., in pixels or CSS units).
|
| 84 |
+
logo_height (int | str | None, optional): Logo height (e.g., in pixels or CSS units).
|
| 85 |
+
scroll_background_color (str | None, optional): Background color for scroll effect.
|
| 86 |
+
scroll_title_color (str | None, optional): Color for credit titles.
|
| 87 |
+
scroll_name_color (str | None, optional): Color for credit names.
|
| 88 |
+
label (str | I18nData | None, optional): Component label.
|
| 89 |
+
every (float | None, optional): Interval for periodic updates.
|
| 90 |
+
inputs (Component | Sequence[Component] | set[Component] | None, optional): Input components for events.
|
| 91 |
+
show_label (bool, optional): Whether to show the label. Defaults to False.
|
| 92 |
+
container (bool, optional): Whether to render in a container. Defaults to True.
|
| 93 |
+
scale (int | None, optional): Scaling factor for the component.
|
| 94 |
+
min_width (int, optional): Minimum width in pixels. Defaults to 160.
|
| 95 |
+
interactive (bool | None, optional): Whether the component is interactive.
|
| 96 |
+
visible (bool, optional): Whether the component is visible. Defaults to True.
|
| 97 |
+
elem_id (str | None, optional): Custom HTML element ID.
|
| 98 |
+
elem_classes (list[str] | str | None, optional): CSS classes for the component.
|
| 99 |
+
render (bool, optional): Whether to render the component. Defaults to True.
|
| 100 |
+
key (int | str | tuple[int | str, ...] | None, optional): Component key for state preservation.
|
| 101 |
+
preserved_by_key (list[str] | str | None, optional): Properties preserved by key. Defaults to "value".
|
| 102 |
+
"""
|
| 103 |
+
self.height = height
|
| 104 |
+
self.width = width
|
| 105 |
+
self.credits_data = credits if credits is not None else []
|
| 106 |
+
self.licenses_paths = licenses or {}
|
| 107 |
+
self.effect = effect
|
| 108 |
+
self.speed = speed
|
| 109 |
+
self.base_font_size = base_font_size
|
| 110 |
+
self.intro_title = intro_title
|
| 111 |
+
self.intro_subtitle = intro_subtitle
|
| 112 |
+
self.sidebar_position = sidebar_position
|
| 113 |
+
self.logo_path = logo_path
|
| 114 |
+
self.show_logo = show_logo
|
| 115 |
+
self.show_licenses = show_licenses
|
| 116 |
+
self.logo_position = logo_position
|
| 117 |
+
self.logo_sizing = logo_sizing
|
| 118 |
+
self.logo_width = logo_width
|
| 119 |
+
self.logo_height = logo_height
|
| 120 |
+
self.scroll_background_color = scroll_background_color
|
| 121 |
+
self.scroll_title_color = scroll_title_color
|
| 122 |
+
self.scroll_name_color = scroll_name_color
|
| 123 |
+
super().__init__(
|
| 124 |
+
label=label,
|
| 125 |
+
every=every,
|
| 126 |
+
inputs=inputs,
|
| 127 |
+
show_label=show_label,
|
| 128 |
+
container=container,
|
| 129 |
+
scale=scale,
|
| 130 |
+
min_width=min_width,
|
| 131 |
+
interactive=interactive,
|
| 132 |
+
elem_id=elem_id,
|
| 133 |
+
elem_classes=elem_classes,
|
| 134 |
+
render=render,
|
| 135 |
+
key=key,
|
| 136 |
+
visible=visible,
|
| 137 |
+
preserved_by_key=preserved_by_key,
|
| 138 |
+
value=value,
|
| 139 |
+
)
|
| 140 |
+
|
| 141 |
+
def _process_license_files(self) -> Dict[str, str]:
|
| 142 |
+
"""
|
| 143 |
+
Process license files into a dictionary of name-content pairs.
|
| 144 |
+
|
| 145 |
+
Returns:
|
| 146 |
+
Dict[str, str]: Dictionary mapping license names to their content or error messages if loading fails.
|
| 147 |
+
"""
|
| 148 |
+
processed = {}
|
| 149 |
+
for name, path in self.licenses_paths.items():
|
| 150 |
+
try:
|
| 151 |
+
with open(path, "r", encoding="utf-8") as f:
|
| 152 |
+
processed[name] = f.read()
|
| 153 |
+
except Exception as e:
|
| 154 |
+
processed[name] = f"Error loading license file '{path}':\n{e}"
|
| 155 |
+
return processed
|
| 156 |
+
|
| 157 |
+
def _process_logo_path(self) -> Dict[str, Any] | None:
|
| 158 |
+
"""
|
| 159 |
+
Process the logo path, handling both local files and URLs.
|
| 160 |
+
|
| 161 |
+
Returns:
|
| 162 |
+
Dict[str, Any] | None: Dictionary with logo details (path, url, orig_name, mime_type) or None if no logo_path is provided or the file is not found.
|
| 163 |
+
"""
|
| 164 |
+
if not self.logo_path:
|
| 165 |
+
return None
|
| 166 |
+
path = str(self.logo_path)
|
| 167 |
+
if is_http_url_like(path):
|
| 168 |
+
return {"path": None, "url": path, "orig_name": Path(path).name, "mime_type": None}
|
| 169 |
+
if os.path.exists(path):
|
| 170 |
+
return handle_file(path)
|
| 171 |
+
return None
|
| 172 |
+
|
| 173 |
+
def preprocess(self, payload: Dict[str, Any] | None) -> Dict[str, Any] | None:
|
| 174 |
+
"""
|
| 175 |
+
Preprocess the input payload.
|
| 176 |
+
|
| 177 |
+
Args:
|
| 178 |
+
payload (Dict[str, Any] | None): Input data to preprocess.
|
| 179 |
+
|
| 180 |
+
Returns:
|
| 181 |
+
Dict[str, Any] | None: The input payload, returned unchanged.
|
| 182 |
+
"""
|
| 183 |
+
return payload
|
| 184 |
+
|
| 185 |
+
def postprocess(self, value: Any) -> Dict[str, Any] | None:
|
| 186 |
+
"""
|
| 187 |
+
Postprocess the component's value to prepare data for rendering.
|
| 188 |
+
|
| 189 |
+
Args:
|
| 190 |
+
value (Any): Input value, typically a list of credits.
|
| 191 |
+
|
| 192 |
+
Returns:
|
| 193 |
+
Dict[str, Any] | None: Dictionary containing processed credits, licenses, and configuration, or None if no credits or licenses are provided.
|
| 194 |
+
"""
|
| 195 |
+
credits_source = value if isinstance(value, list) else self.credits_data
|
| 196 |
+
if not credits_source and not self.licenses_paths:
|
| 197 |
+
return None
|
| 198 |
+
return {
|
| 199 |
+
"credits": credits_source,
|
| 200 |
+
"licenses": self._process_license_files() if self.show_licenses else {},
|
| 201 |
+
"effect": self.effect,
|
| 202 |
+
"speed": self.speed,
|
| 203 |
+
"base_font_size": self.base_font_size,
|
| 204 |
+
"intro_title": self.intro_title,
|
| 205 |
+
"intro_subtitle": self.intro_subtitle,
|
| 206 |
+
"sidebar_position": self.sidebar_position,
|
| 207 |
+
"logo_path": self._process_logo_path(),
|
| 208 |
+
"show_logo": self.show_logo,
|
| 209 |
+
"show_licenses": self.show_licenses,
|
| 210 |
+
"logo_position": self.logo_position,
|
| 211 |
+
"logo_sizing": self.logo_sizing,
|
| 212 |
+
"logo_width": self.logo_width,
|
| 213 |
+
"logo_height": self.logo_height,
|
| 214 |
+
"scroll_background_color": self.scroll_background_color,
|
| 215 |
+
"scroll_title_color": self.scroll_title_color,
|
| 216 |
+
"scroll_name_color": self.scroll_name_color
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
def api_info(self) -> Dict[str, Any]:
|
| 220 |
+
"""
|
| 221 |
+
Provide API information for the component.
|
| 222 |
+
|
| 223 |
+
Returns:
|
| 224 |
+
Dict[str, Any]: Dictionary indicating the component's data type ("object").
|
| 225 |
+
"""
|
| 226 |
+
return {"type": "object"}
|
| 227 |
+
|
| 228 |
+
def example_payload(self) -> Any:
|
| 229 |
+
"""
|
| 230 |
+
Provide an example payload for the component.
|
| 231 |
+
|
| 232 |
+
Returns:
|
| 233 |
+
Dict[str, Any]: Example data structure for the component's payload.
|
| 234 |
+
"""
|
| 235 |
+
return {
|
| 236 |
+
"credits": [{"title": "Example", "name": "Credit"}],
|
| 237 |
+
"licenses": {},
|
| 238 |
+
"effect": "scroll",
|
| 239 |
+
"speed": 20,
|
| 240 |
+
"sidebar_position": "right",
|
| 241 |
+
"logo_path": None,
|
| 242 |
+
"show_logo": True,
|
| 243 |
+
"show_licenses": True,
|
| 244 |
+
"logo_position": "center",
|
| 245 |
+
"logo_sizing": "resize",
|
| 246 |
+
"logo_width": None,
|
| 247 |
+
"logo_height": None,
|
| 248 |
+
"scroll_background_color": None,
|
| 249 |
+
"scroll_title_color": None,
|
| 250 |
+
"scroll_name_color": None
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
def example_value(self) -> Any:
|
| 254 |
+
"""
|
| 255 |
+
Provide an example value for the component.
|
| 256 |
+
|
| 257 |
+
Returns:
|
| 258 |
+
List[Dict[str, str]]: Example list of credits.
|
| 259 |
+
"""
|
| 260 |
+
return [{"title": "Example", "name": "Credit"}]
|
src/backend/gradio_creditspanel/templates/component/index.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/backend/gradio_creditspanel/templates/component/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.block.svelte-239wnu{position:relative;margin:0;box-shadow:var(--block-shadow);border-width:var(--block-border-width);border-color:var(--block-border-color);border-radius:var(--block-radius);background:var(--block-background-fill);width:100%;line-height:var(--line-sm)}.block.fullscreen.svelte-239wnu{border-radius:0}.auto-margin.svelte-239wnu{margin-left:auto;margin-right:auto}.block.border_focus.svelte-239wnu{border-color:var(--color-accent)}.block.border_contrast.svelte-239wnu{border-color:var(--body-text-color)}.padded.svelte-239wnu{padding:var(--block-padding)}.hidden.svelte-239wnu{display:none}.flex.svelte-239wnu{display:flex;flex-direction:column}.hide-container.svelte-239wnu:not(.fullscreen){margin:0;box-shadow:none;--block-border-width:0;background:transparent;padding:0;overflow:visible}.resize-handle.svelte-239wnu{position:absolute;bottom:0;right:0;width:10px;height:10px;fill:var(--block-border-color);cursor:nwse-resize}.fullscreen.svelte-239wnu{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:1000;overflow:auto}.animating.svelte-239wnu{animation:svelte-239wnu-pop-out .1s ease-out forwards}@keyframes svelte-239wnu-pop-out{0%{position:fixed;top:var(--start-top);left:var(--start-left);width:var(--start-width);height:var(--start-height);z-index:100}to{position:fixed;top:0vh;left:0vw;width:100vw;height:100vh;z-index:1000}}.placeholder.svelte-239wnu{border-radius:var(--block-radius);border-width:var(--block-border-width);border-color:var(--block-border-color);border-style:dashed}Tables */ table,tr,td,th{margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);padding:var(--spacing-xl)}.md code,.md pre{background:none;font-family:var(--font-mono);font-size:var(--text-sm);text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:2;tab-size:2;-webkit-hyphens:none;hyphens:none}.md pre[class*=language-]::selection,.md pre[class*=language-] ::selection,.md code[class*=language-]::selection,.md code[class*=language-] ::selection{text-shadow:none;background:#b3d4fc}.md pre{padding:1em;margin:.5em 0;overflow:auto;position:relative;margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);box-shadow:none;border:none;border-radius:var(--radius-md);background:var(--code-background-fill);padding:var(--spacing-xxl);font-family:var(--font-mono);text-shadow:none;border-radius:var(--radius-sm);white-space:nowrap;display:block;white-space:pre}.md :not(pre)>code{padding:.1em;border-radius:var(--radius-xs);white-space:normal;background:var(--code-background-fill);border:1px solid var(--panel-border-color);padding:var(--spacing-xxs) var(--spacing-xs)}.md .token.comment,.md .token.prolog,.md .token.doctype,.md .token.cdata{color:#708090}.md .token.punctuation{color:#999}.md .token.namespace{opacity:.7}.md .token.property,.md .token.tag,.md .token.boolean,.md .token.number,.md .token.constant,.md .token.symbol,.md .token.deleted{color:#905}.md .token.selector,.md .token.attr-name,.md .token.string,.md .token.char,.md .token.builtin,.md .token.inserted{color:#690}.md .token.atrule,.md .token.attr-value,.md .token.keyword{color:#07a}.md .token.function,.md .token.class-name{color:#dd4a68}.md .token.regex,.md .token.important,.md .token.variable{color:#e90}.md .token.important,.md .token.bold{font-weight:700}.md .token.italic{font-style:italic}.md .token.entity{cursor:help}.dark .md .token.comment,.dark .md .token.prolog,.dark .md .token.cdata{color:#5c6370}.dark .md .token.doctype,.dark .md .token.punctuation,.dark .md .token.entity{color:#abb2bf}.dark .md .token.attr-name,.dark .md .token.class-name,.dark .md .token.boolean,.dark .md .token.constant,.dark .md .token.number,.dark .md .token.atrule{color:#d19a66}.dark .md .token.keyword{color:#c678dd}.dark .md .token.property,.dark .md .token.tag,.dark .md .token.symbol,.dark .md .token.deleted,.dark .md .token.important{color:#e06c75}.dark .md .token.selector,.dark .md .token.string,.dark .md .token.char,.dark .md .token.builtin,.dark .md .token.inserted,.dark .md .token.regex,.dark .md .token.attr-value,.dark .md .token.attr-value>.token.punctuation{color:#98c379}.dark .md .token.variable,.dark .md .token.operator,.dark .md .token.function{color:#61afef}.dark .md .token.url{color:#56b6c2}span.svelte-1m32c2s div[class*=code_wrap]{position:relative}span.svelte-1m32c2s span.katex{font-size:var(--text-lg);direction:ltr}span.svelte-1m32c2s div[class*=code_wrap]>button{z-index:1;cursor:pointer;border-bottom-left-radius:var(--radius-sm);padding:var(--spacing-md);width:25px;height:25px;position:absolute;right:0}span.svelte-1m32c2s .check{opacity:0;z-index:var(--layer-top);transition:opacity .2s;background:var(--code-background-fill);color:var(--body-text-color);position:absolute;top:var(--size-1-5);left:var(--size-1-5)}span.svelte-1m32c2s p:not(:first-child){margin-top:var(--spacing-xxl)}span.svelte-1m32c2s .md-header-anchor{margin-left:-25px;padding-right:8px;line-height:1;color:var(--body-text-color-subdued);opacity:0}span.svelte-1m32c2s h1:hover .md-header-anchor,span.svelte-1m32c2s h2:hover .md-header-anchor,span.svelte-1m32c2s h3:hover .md-header-anchor,span.svelte-1m32c2s h4:hover .md-header-anchor,span.svelte-1m32c2s h5:hover .md-header-anchor,span.svelte-1m32c2s h6:hover .md-header-anchor{opacity:1}span.md.svelte-1m32c2s .md-header-anchor>svg{color:var(--body-text-color-subdued)}span.svelte-1m32c2s table{word-break:break-word}div.svelte-17qq50w>.md.prose{font-weight:var(--block-info-text-weight);font-size:var(--block-info-text-size);line-height:var(--line-sm)}div.svelte-17qq50w>.md.prose *{color:var(--block-info-text-color)}div.svelte-17qq50w{margin-bottom:var(--spacing-md)}span.has-info.svelte-zgrq3{margin-bottom:var(--spacing-xs)}span.svelte-zgrq3:not(.has-info){margin-bottom:var(--spacing-lg)}span.svelte-zgrq3{display:inline-block;position:relative;z-index:var(--layer-4);border:solid var(--block-title-border-width) var(--block-title-border-color);border-radius:var(--block-title-radius);background:var(--block-title-background-fill);padding:var(--block-title-padding);color:var(--block-title-text-color);font-weight:var(--block-title-text-weight);font-size:var(--block-title-text-size);line-height:var(--line-sm)}span[dir=rtl].svelte-zgrq3{display:block}.hide.svelte-zgrq3{margin:0;height:0}label.svelte-13ao5pu.svelte-13ao5pu{display:inline-flex;align-items:center;z-index:var(--layer-2);box-shadow:var(--block-label-shadow);border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-left:none;border-radius:var(--block-label-radius);background:var(--block-label-background-fill);padding:var(--block-label-padding);pointer-events:none;color:var(--block-label-text-color);font-weight:var(--block-label-text-weight);font-size:var(--block-label-text-size);line-height:var(--line-sm)}.gr-group label.svelte-13ao5pu.svelte-13ao5pu{border-top-left-radius:0}label.float.svelte-13ao5pu.svelte-13ao5pu{position:absolute;top:var(--block-label-margin);left:var(--block-label-margin)}label.svelte-13ao5pu.svelte-13ao5pu:not(.float){position:static;margin-top:var(--block-label-margin);margin-left:var(--block-label-margin)}.hide.svelte-13ao5pu.svelte-13ao5pu{height:0}span.svelte-13ao5pu.svelte-13ao5pu{opacity:.8;margin-right:var(--size-2);width:calc(var(--block-label-text-size) - 1px);height:calc(var(--block-label-text-size) - 1px)}.hide-label.svelte-13ao5pu.svelte-13ao5pu{box-shadow:none;border-width:0;background:transparent;overflow:visible}label[dir=rtl].svelte-13ao5pu.svelte-13ao5pu{border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-right:none;border-bottom-left-radius:var(--block-radius);border-bottom-right-radius:var(--block-label-radius);border-top-left-radius:var(--block-label-radius)}label[dir=rtl].svelte-13ao5pu span.svelte-13ao5pu{margin-left:var(--size-2);margin-right:0}button.svelte-qgco6m{display:flex;justify-content:center;align-items:center;gap:1px;z-index:var(--layer-2);border-radius:var(--radius-xs);color:var(--block-label-text-color);border:1px solid transparent;padding:var(--spacing-xxs)}button.svelte-qgco6m:hover{background-color:var(--background-fill-secondary)}button[disabled].svelte-qgco6m{opacity:.5;box-shadow:none}button[disabled].svelte-qgco6m:hover{cursor:not-allowed}.padded.svelte-qgco6m{background:var(--bg-color)}button.svelte-qgco6m:hover,button.highlight.svelte-qgco6m{cursor:pointer;color:var(--color-accent)}.padded.svelte-qgco6m:hover{color:var(--block-label-text-color)}span.svelte-qgco6m{padding:0 1px;font-size:10px}div.svelte-qgco6m{display:flex;align-items:center;justify-content:center;transition:filter .2s ease-in-out}.x-small.svelte-qgco6m{width:10px;height:10px}.small.svelte-qgco6m{width:14px;height:14px}.medium.svelte-qgco6m{width:20px;height:20px}.large.svelte-qgco6m{width:22px;height:22px}.pending.svelte-qgco6m{animation:svelte-qgco6m-flash .5s infinite}@keyframes svelte-qgco6m-flash{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.transparent.svelte-qgco6m{background:transparent;border:none;box-shadow:none}.empty.svelte-3w3rth{display:flex;justify-content:center;align-items:center;margin-top:calc(0px - var(--size-6));height:var(--size-full)}.icon.svelte-3w3rth{opacity:.5;height:var(--size-5);color:var(--body-text-color)}.small.svelte-3w3rth{min-height:calc(var(--size-32) - 20px)}.large.svelte-3w3rth{min-height:calc(var(--size-64) - 20px)}.unpadded_box.svelte-3w3rth{margin-top:0}.small_parent.svelte-3w3rth{min-height:100%!important}.dropdown-arrow.svelte-145leq6,.dropdown-arrow.svelte-ihhdbf{fill:currentColor}.circle.svelte-ihhdbf{fill:currentColor;opacity:.1}svg.svelte-pb9pol{animation:svelte-pb9pol-spin 1.5s linear infinite}@keyframes svelte-pb9pol-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}h2.svelte-1xg7h5n{font-size:var(--text-xl)!important}p.svelte-1xg7h5n,h2.svelte-1xg7h5n{white-space:pre-line}.wrap.svelte-1xg7h5n{display:flex;flex-direction:column;justify-content:center;align-items:center;min-height:var(--size-60);color:var(--block-label-text-color);line-height:var(--line-md);height:100%;padding-top:var(--size-3);text-align:center;margin:auto var(--spacing-lg)}.or.svelte-1xg7h5n{color:var(--body-text-color-subdued);display:flex}.icon-wrap.svelte-1xg7h5n{width:30px;margin-bottom:var(--spacing-lg)}@media (--screen-md){.wrap.svelte-1xg7h5n{font-size:var(--text-lg)}}.hovered.svelte-1xg7h5n{color:var(--color-accent)}div.svelte-q32hvf{border-top:1px solid transparent;display:flex;max-height:100%;justify-content:center;align-items:center;gap:var(--spacing-sm);height:auto;align-items:flex-end;color:var(--block-label-text-color);flex-shrink:0}.show_border.svelte-q32hvf{border-top:1px solid var(--block-border-color);margin-top:var(--spacing-xxl);box-shadow:var(--shadow-drop)}.source-selection.svelte-15ls1gu{display:flex;align-items:center;justify-content:center;border-top:1px solid var(--border-color-primary);width:100%;margin-left:auto;margin-right:auto;height:var(--size-10)}.icon.svelte-15ls1gu{width:22px;height:22px;margin:var(--spacing-lg) var(--spacing-xs);padding:var(--spacing-xs);color:var(--neutral-400);border-radius:var(--radius-md)}.selected.svelte-15ls1gu{color:var(--color-accent)}.icon.svelte-15ls1gu:hover,.icon.svelte-15ls1gu:focus{color:var(--color-accent)}.icon-button-wrapper.svelte-1h0hs6p{display:flex;flex-direction:row;align-items:center;justify-content:center;z-index:var(--layer-2);gap:var(--spacing-sm);box-shadow:var(--shadow-drop);border:1px solid var(--border-color-primary);background:var(--block-background-fill);padding:var(--spacing-xxs)}.icon-button-wrapper.hide-top-corner.svelte-1h0hs6p{border-top:none;border-right:none;border-radius:var(--block-label-right-radius)}.icon-button-wrapper.display-top-corner.svelte-1h0hs6p{border-radius:var(--radius-sm) 0 0 var(--radius-sm);top:var(--spacing-sm);right:-1px}.icon-button-wrapper.svelte-1h0hs6p:not(.top-panel){border:1px solid var(--border-color-primary);border-radius:var(--radius-sm)}.top-panel.svelte-1h0hs6p{position:absolute;top:var(--block-label-margin);right:var(--block-label-margin);margin:0}.icon-button-wrapper.svelte-1h0hs6p button{margin:var(--spacing-xxs);border-radius:var(--radius-xs);position:relative}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child),.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child){margin-right:var(--spacing-xxs)}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child):not(.no-border *):after,.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child):not(.no-border *):after{content:"";position:absolute;right:-4.5px;top:15%;height:70%;width:1px;background-color:var(--border-color-primary)}.icon-button-wrapper.svelte-1h0hs6p>*{height:100%}svg.svelte-43sxxs.svelte-43sxxs{width:var(--size-20);height:var(--size-20)}svg.svelte-43sxxs path.svelte-43sxxs{fill:var(--loader-color)}div.svelte-43sxxs.svelte-43sxxs{z-index:var(--layer-2)}.margin.svelte-43sxxs.svelte-43sxxs{margin:var(--size-4)}.wrap.svelte-17v219f.svelte-17v219f{display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:var(--layer-2);transition:opacity .1s ease-in-out;border-radius:var(--block-radius);background:var(--block-background-fill);padding:0 var(--size-6);max-height:var(--size-screen-h);overflow:hidden}.wrap.center.svelte-17v219f.svelte-17v219f{top:0;right:0;left:0}.wrap.default.svelte-17v219f.svelte-17v219f{top:0;right:0;bottom:0;left:0}.hide.svelte-17v219f.svelte-17v219f{opacity:0;pointer-events:none}.generating.svelte-17v219f.svelte-17v219f{animation:svelte-17v219f-pulseStart 1s cubic-bezier(.4,0,.6,1),svelte-17v219f-pulse 2s cubic-bezier(.4,0,.6,1) 1s infinite;border:2px solid var(--color-accent);background:transparent;z-index:var(--layer-1);pointer-events:none}.translucent.svelte-17v219f.svelte-17v219f{background:none}@keyframes svelte-17v219f-pulseStart{0%{opacity:0}to{opacity:1}}@keyframes svelte-17v219f-pulse{0%,to{opacity:1}50%{opacity:.5}}.loading.svelte-17v219f.svelte-17v219f{z-index:var(--layer-2);color:var(--body-text-color)}.eta-bar.svelte-17v219f.svelte-17v219f{position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:left;opacity:.8;z-index:var(--layer-1);transition:10ms;background:var(--background-fill-secondary)}.progress-bar-wrap.svelte-17v219f.svelte-17v219f{border:1px solid var(--border-color-primary);background:var(--background-fill-primary);width:55.5%;height:var(--size-4)}.progress-bar.svelte-17v219f.svelte-17v219f{transform-origin:left;background-color:var(--loader-color);width:var(--size-full);height:var(--size-full)}.progress-level.svelte-17v219f.svelte-17v219f{display:flex;flex-direction:column;align-items:center;gap:1;z-index:var(--layer-2);width:var(--size-full)}.progress-level-inner.svelte-17v219f.svelte-17v219f{margin:var(--size-2) auto;color:var(--body-text-color);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text.svelte-17v219f.svelte-17v219f{position:absolute;bottom:0;right:0;z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text-center.svelte-17v219f.svelte-17v219f{display:flex;position:absolute;top:0;right:0;justify-content:center;align-items:center;transform:translateY(var(--size-6));z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono);text-align:center}.error.svelte-17v219f.svelte-17v219f{box-shadow:var(--shadow-drop);border:solid 1px var(--error-border-color);border-radius:var(--radius-full);background:var(--error-background-fill);padding-right:var(--size-4);padding-left:var(--size-4);color:var(--error-text-color);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--line-lg);font-family:var(--font)}.minimal.svelte-17v219f.svelte-17v219f{pointer-events:none}.minimal.svelte-17v219f .progress-text.svelte-17v219f{background:var(--block-background-fill)}.border.svelte-17v219f.svelte-17v219f{border:1px solid var(--border-color-primary)}.clear-status.svelte-17v219f.svelte-17v219f{position:absolute;display:flex;top:var(--size-2);right:var(--size-2);justify-content:flex-end;gap:var(--spacing-sm);z-index:var(--layer-1)}.toast-body.svelte-syezpc{display:flex;position:relative;right:0;left:0;align-items:center;margin:var(--size-6) var(--size-4);margin:auto;border-radius:var(--container-radius);overflow:hidden;pointer-events:auto}.toast-body.error.svelte-syezpc{border:1px solid var(--color-red-700);background:var(--color-red-50)}.dark .toast-body.error.svelte-syezpc{border:1px solid var(--color-red-500);background-color:var(--color-grey-950)}.toast-body.warning.svelte-syezpc{border:1px solid var(--color-yellow-700);background:var(--color-yellow-50)}.dark .toast-body.warning.svelte-syezpc{border:1px solid var(--color-yellow-500);background-color:var(--color-grey-950)}.toast-body.info.svelte-syezpc{border:1px solid var(--color-grey-700);background:var(--color-grey-50)}.dark .toast-body.info.svelte-syezpc{border:1px solid var(--color-grey-500);background-color:var(--color-grey-950)}.toast-body.success.svelte-syezpc{border:1px solid var(--color-green-700);background:var(--color-green-50)}.dark .toast-body.success.svelte-syezpc{border:1px solid var(--color-green-500);background-color:var(--color-grey-950)}.toast-title.svelte-syezpc{display:flex;align-items:center;font-weight:var(--weight-bold);font-size:var(--text-lg);line-height:var(--line-sm)}.toast-title.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-title.error.svelte-syezpc{color:var(--color-red-50)}.toast-title.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-title.warning.svelte-syezpc{color:var(--color-yellow-50)}.toast-title.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-title.info.svelte-syezpc{color:var(--color-grey-50)}.toast-title.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-title.success.svelte-syezpc{color:var(--color-green-50)}.toast-close.svelte-syezpc{margin:0 var(--size-3);border-radius:var(--size-3);padding:0px var(--size-1-5);font-size:var(--size-5);line-height:var(--size-5)}.toast-close.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-close.error.svelte-syezpc{color:var(--color-red-500)}.toast-close.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-close.warning.svelte-syezpc{color:var(--color-yellow-500)}.toast-close.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-close.info.svelte-syezpc{color:var(--color-grey-500)}.toast-close.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-close.success.svelte-syezpc{color:var(--color-green-500)}.toast-text.svelte-syezpc{font-size:var(--text-lg);word-wrap:break-word;overflow-wrap:break-word;word-break:break-word}.toast-text.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-text.error.svelte-syezpc{color:var(--color-red-50)}.toast-text.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-text.warning.svelte-syezpc{color:var(--color-yellow-50)}.toast-text.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-text.info.svelte-syezpc{color:var(--color-grey-50)}.toast-text.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-text.success.svelte-syezpc{color:var(--color-green-50)}.toast-details.svelte-syezpc{margin:var(--size-3) var(--size-3) var(--size-3) 0;width:100%}.toast-icon.svelte-syezpc{display:flex;position:absolute;position:relative;flex-shrink:0;justify-content:center;align-items:center;margin:var(--size-2);border-radius:var(--radius-full);padding:var(--size-1);padding-left:calc(var(--size-1) - 1px);width:35px;height:35px}.toast-icon.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-icon.error.svelte-syezpc{color:var(--color-red-500)}.toast-icon.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-icon.warning.svelte-syezpc{color:var(--color-yellow-500)}.toast-icon.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-icon.info.svelte-syezpc{color:var(--color-grey-500)}.toast-icon.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-icon.success.svelte-syezpc{color:var(--color-green-500)}@keyframes svelte-syezpc-countdown{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.timer.svelte-syezpc{position:absolute;bottom:0;left:0;transform-origin:0 0;animation:svelte-syezpc-countdown 10s linear forwards;width:100%;height:var(--size-1)}.timer.error.svelte-syezpc{background:var(--color-red-700)}.dark .timer.error.svelte-syezpc{background:var(--color-red-500)}.timer.warning.svelte-syezpc{background:var(--color-yellow-700)}.dark .timer.warning.svelte-syezpc{background:var(--color-yellow-500)}.timer.info.svelte-syezpc{background:var(--color-grey-700)}.dark .timer.info.svelte-syezpc{background:var(--color-grey-500)}.timer.success.svelte-syezpc{background:var(--color-green-700)}.dark .timer.success.svelte-syezpc{background:var(--color-green-500)}.hidden.svelte-syezpc{display:none}.toast-text.svelte-syezpc a{text-decoration:underline}.toast-wrap.svelte-gatr8h{display:flex;position:fixed;top:var(--size-4);right:var(--size-4);flex-direction:column;align-items:end;gap:var(--size-2);z-index:var(--layer-top);width:calc(100% - var(--size-8))}@media (--screen-sm){.toast-wrap.svelte-gatr8h{width:calc(var(--size-96) + var(--size-10))}}.streaming-bar.svelte-ga0jj6{position:absolute;bottom:0;left:0;right:0;height:4px;background-color:var(--primary-600);animation:svelte-ga0jj6-countdown linear forwards;z-index:1}@keyframes svelte-ga0jj6-countdown{0%{transform:translate(0)}to{transform:translate(-100%)}}.wrapper.svelte-141h5y1.svelte-141h5y1{width:100%;height:100%;overflow:hidden;position:relative;font-family:sans-serif}.credit.intro-block.svelte-141h5y1.svelte-141h5y1{margin-bottom:5rem;text-align:center}.credits-container.svelte-141h5y1.svelte-141h5y1{position:absolute;bottom:0;transform:translateY(100%);width:100%;text-align:center;animation:svelte-141h5y1-scroll var(--animation-duration) linear infinite}.credit.svelte-141h5y1.svelte-141h5y1{margin-bottom:2rem}.credit.svelte-141h5y1 h2.svelte-141h5y1,.credit.svelte-141h5y1 p.svelte-141h5y1{margin:.5rem 0;font-family:sans-serif}@keyframes svelte-141h5y1-scroll{0%{transform:translateY(100%)}to{transform:translateY(-100%)}}.viewport.svelte-1gy01d0{width:100%;height:100%;position:relative;overflow:hidden;perspective:400px;-webkit-mask-image:linear-gradient(to bottom,black 60%,transparent 100%);mask-image:linear-gradient(to bottom,black 60%,transparent 100%);font-family:Droid Sans,sans-serif;font-weight:700}.stars.svelte-1gy01d0{position:absolute;top:0;left:0;width:1px;height:1px;background:transparent;z-index:0;animation:svelte-1gy01d0-twinkle 10s linear infinite}.stars.small.svelte-1gy01d0{animation-duration:10s}.stars.medium.svelte-1gy01d0{animation-duration:15s}.stars.large.svelte-1gy01d0{animation-duration:20s}@keyframes svelte-1gy01d0-twinkle{0%{opacity:.6}50%{opacity:1}to{opacity:.6}}.crawl.svelte-1gy01d0{position:absolute;width:100%;bottom:0;transform-origin:50% 100%;animation:svelte-1gy01d0-crawl-animation var(--animation-duration) linear infinite;z-index:1;text-align:center}@keyframes svelte-1gy01d0-crawl-animation{0%{transform:rotateX(60deg) translateY(100%) translateZ(100px);opacity:1}to{transform:rotateX(60deg) translateY(-150%) translateZ(-1200px);opacity:1}}.credit.intro-block.svelte-1gy01d0{margin-bottom:5rem}.credit.svelte-1gy01d0{margin-bottom:2rem}h2.svelte-1gy01d0,p.svelte-1gy01d0{margin:.5rem 0;padding:0;white-space:nowrap}.matrix-container.svelte-8jsw80{width:100%;height:100%;position:relative;overflow:hidden}canvas.svelte-8jsw80{display:block;position:absolute;top:0;left:0;width:100%;height:100%;z-index:1}.credits-scroll-overlay.svelte-8jsw80{position:absolute;top:0;left:0;width:100%;height:100%;z-index:2;color:#fff;font-family:monospace;text-align:center;-webkit-mask-image:linear-gradient(transparent,black 20%,black 80%,transparent);mask-image:linear-gradient(transparent,black 20%,black 80%,transparent)}.credits-content.svelte-8jsw80{position:absolute;width:100%;bottom:0;transform:translateY(100%);animation:svelte-8jsw80-scroll-from-bottom var(--animation-duration) linear infinite}@keyframes svelte-8jsw80-scroll-from-bottom{0%{transform:translateY(100%)}to{transform:translateY(-100%)}}.credit-block.intro-block.svelte-8jsw80{margin-bottom:5rem}.credit-block.svelte-8jsw80{margin-bottom:2.5em}.title.svelte-8jsw80{color:#0f0;text-transform:uppercase;opacity:.8}.name.svelte-8jsw80{font-weight:700;color:#5f5;text-shadow:0 0 5px #0F0}.unstyled-link.svelte-151nsdd{all:unset;cursor:pointer}img.svelte-kxeri3{object-fit:cover}.image-container.svelte-x2tujq.svelte-x2tujq{height:100%;position:relative;min-width:var(--size-20)}.image-container.svelte-x2tujq button.svelte-x2tujq{width:var(--size-full);height:var(--size-full);border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center}.image-frame.svelte-x2tujq img{width:var(--size-full);height:var(--size-full);object-fit:scale-down}.selectable.svelte-x2tujq.svelte-x2tujq{cursor:crosshair}.fullscreen-controls svg{position:relative;top:0}.image-container:fullscreen{background-color:#000;display:flex;justify-content:center;align-items:center}.image-container:fullscreen img{max-width:90vw;max-height:90vh;object-fit:scale-down}.image-frame.svelte-x2tujq.svelte-x2tujq{width:auto;height:100%;display:flex;align-items:center;justify-content:center}.block{border:none!important;box-shadow:none!important;border-style:none!important}.outer-logo-wrapper.svelte-1ewbjj5.svelte-1ewbjj5,.outer-credits-wrapper.svelte-1ewbjj5.svelte-1ewbjj5{display:flex;flex-direction:column;width:100%;border:none}.logo-panel.svelte-1ewbjj5.svelte-1ewbjj5{background:var(--background-fill-primary);border:none;border-bottom:1px solid var(--border-color-primary);display:flex!important;align-items:center;justify-content:var(--logo-justify, center);width:100%}.credits-panel-wrapper.svelte-1ewbjj5.svelte-1ewbjj5{display:flex;flex-direction:var(--panel-direction, row);min-height:var(--size-full, 500px);width:100%;background:var(--background-fill-primary);border:1px solid var(--border-color-primary);border-radius:var(--radius-lg);overflow:hidden}.main-credits-panel.svelte-1ewbjj5.svelte-1ewbjj5{flex-grow:1;flex-shrink:1;min-width:200px;background:#000;overflow:hidden;position:relative}.licenses-sidebar.svelte-1ewbjj5.svelte-1ewbjj5{width:var(--sidebar-width, 400px);max-width:100%;max-height:var(--sidebar-max-height, none);flex-shrink:1;flex-grow:0;background:var(--background-fill-secondary);overflow-y:auto;border-left:var(--border-left, 1px solid var(--border-color-primary));border-top:var(--border-top, none)}.licenses-sidebar.svelte-1ewbjj5 h3.svelte-1ewbjj5{margin:var(--spacing-lg);font-size:var(--text-lg)}.licenses-sidebar.svelte-1ewbjj5 li.svelte-1ewbjj5{padding:0;margin:0;cursor:default;border-bottom:1px solid var(--border-color-primary)}.licenses-sidebar.svelte-1ewbjj5 li button.svelte-1ewbjj5{background:none;border:none;font:inherit;color:inherit;text-align:left;width:100%;cursor:pointer;padding:var(--spacing-md) var(--spacing-lg);transition:background-color .2s}.licenses-sidebar.svelte-1ewbjj5 li button.svelte-1ewbjj5:hover{background-color:var(--background-fill-primary)}.licenses-sidebar.svelte-1ewbjj5 li button.svelte-1ewbjj5:focus-visible{outline:2px solid var(--color-accent);outline-offset:-2px}.licenses-sidebar.svelte-1ewbjj5 li button.selected.svelte-1ewbjj5{background-color:var(--color-accent);color:#fff;font-weight:700}.license-display.svelte-1ewbjj5.svelte-1ewbjj5{padding:var(--spacing-lg);overflow-y:auto;flex-grow:1;border-top:1px solid var(--border-color-primary);background:var(--background-fill-primary)}.license-display.svelte-1ewbjj5 h4.svelte-1ewbjj5{margin-top:0}.license-display.svelte-1ewbjj5 pre.svelte-1ewbjj5{white-space:pre-wrap;word-break:break-word;font-size:var(--text-sm);color:var(--body-text-color-subdued)}
|
src/backend/gradio_creditspanel/templates/example/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const {
|
| 2 |
+
HtmlTagHydration: r,
|
| 3 |
+
SvelteComponent: d,
|
| 4 |
+
attr: u,
|
| 5 |
+
children: o,
|
| 6 |
+
claim_element: h,
|
| 7 |
+
claim_html_tag: m,
|
| 8 |
+
detach: c,
|
| 9 |
+
element: g,
|
| 10 |
+
init: v,
|
| 11 |
+
insert_hydration: y,
|
| 12 |
+
noop: _,
|
| 13 |
+
safe_not_equal: b,
|
| 14 |
+
toggle_class: i
|
| 15 |
+
} = window.__gradio__svelte__internal;
|
| 16 |
+
function q(n) {
|
| 17 |
+
let e, a;
|
| 18 |
+
return {
|
| 19 |
+
c() {
|
| 20 |
+
e = g("div"), a = new r(!1), this.h();
|
| 21 |
+
},
|
| 22 |
+
l(l) {
|
| 23 |
+
e = h(l, "DIV", { class: !0 });
|
| 24 |
+
var t = o(e);
|
| 25 |
+
a = m(t, !1), t.forEach(c), this.h();
|
| 26 |
+
},
|
| 27 |
+
h() {
|
| 28 |
+
a.a = null, u(e, "class", "prose svelte-180qqaf"), i(
|
| 29 |
+
e,
|
| 30 |
+
"table",
|
| 31 |
+
/*type*/
|
| 32 |
+
n[1] === "table"
|
| 33 |
+
), i(
|
| 34 |
+
e,
|
| 35 |
+
"gallery",
|
| 36 |
+
/*type*/
|
| 37 |
+
n[1] === "gallery"
|
| 38 |
+
), i(
|
| 39 |
+
e,
|
| 40 |
+
"selected",
|
| 41 |
+
/*selected*/
|
| 42 |
+
n[2]
|
| 43 |
+
);
|
| 44 |
+
},
|
| 45 |
+
m(l, t) {
|
| 46 |
+
y(l, e, t), a.m(
|
| 47 |
+
/*value*/
|
| 48 |
+
n[0],
|
| 49 |
+
e
|
| 50 |
+
);
|
| 51 |
+
},
|
| 52 |
+
p(l, [t]) {
|
| 53 |
+
t & /*value*/
|
| 54 |
+
1 && a.p(
|
| 55 |
+
/*value*/
|
| 56 |
+
l[0]
|
| 57 |
+
), t & /*type*/
|
| 58 |
+
2 && i(
|
| 59 |
+
e,
|
| 60 |
+
"table",
|
| 61 |
+
/*type*/
|
| 62 |
+
l[1] === "table"
|
| 63 |
+
), t & /*type*/
|
| 64 |
+
2 && i(
|
| 65 |
+
e,
|
| 66 |
+
"gallery",
|
| 67 |
+
/*type*/
|
| 68 |
+
l[1] === "gallery"
|
| 69 |
+
), t & /*selected*/
|
| 70 |
+
4 && i(
|
| 71 |
+
e,
|
| 72 |
+
"selected",
|
| 73 |
+
/*selected*/
|
| 74 |
+
l[2]
|
| 75 |
+
);
|
| 76 |
+
},
|
| 77 |
+
i: _,
|
| 78 |
+
o: _,
|
| 79 |
+
d(l) {
|
| 80 |
+
l && c(e);
|
| 81 |
+
}
|
| 82 |
+
};
|
| 83 |
+
}
|
| 84 |
+
function w(n, e, a) {
|
| 85 |
+
let { value: l } = e, { type: t } = e, { selected: f = !1 } = e;
|
| 86 |
+
return n.$$set = (s) => {
|
| 87 |
+
"value" in s && a(0, l = s.value), "type" in s && a(1, t = s.type), "selected" in s && a(2, f = s.selected);
|
| 88 |
+
}, [l, t, f];
|
| 89 |
+
}
|
| 90 |
+
class E extends d {
|
| 91 |
+
constructor(e) {
|
| 92 |
+
super(), v(this, e, w, q, b, { value: 0, type: 1, selected: 2 });
|
| 93 |
+
}
|
| 94 |
+
}
|
| 95 |
+
export {
|
| 96 |
+
E as default
|
| 97 |
+
};
|
src/backend/gradio_creditspanel/templates/example/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.gallery.svelte-180qqaf{padding:var(--size-2)}
|
src/demo/__init__.py
ADDED
|
File without changes
|
src/demo/app copy.py
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from gradio_creditspanel import CreditsPanel
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
# Create dummy license files
|
| 6 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 7 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 8 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 9 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 10 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 11 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 12 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 13 |
+
|
| 14 |
+
# Create assets directory for logo
|
| 15 |
+
os.makedirs("assets", exist_ok=True)
|
| 16 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 17 |
+
print("Warning: ./assets/logo.webp not found. Creating placeholder. Replace with a valid WebP image.")
|
| 18 |
+
with open("./assets/logo.webp", "w") as f:
|
| 19 |
+
f.write("Placeholder WebP logo")
|
| 20 |
+
else:
|
| 21 |
+
print("Logo found at ./assets/logo.webp")
|
| 22 |
+
|
| 23 |
+
credits_list = [
|
| 24 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 25 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 26 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 27 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 28 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 29 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 30 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 31 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 32 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 33 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 34 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 35 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 36 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 37 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 38 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 39 |
+
{"title": "Cloud Infrastructure Engineer", "name": "Lucas Nguyen"},
|
| 40 |
+
{"title": "Mobile Developer", "name": "Mia Hernandez"},
|
| 41 |
+
{"title": "Performance Engineer", "name": "James Taylor"},
|
| 42 |
+
{"title": "Component Concept", "name": "Your Name"},
|
| 43 |
+
{"title": "Support Engineer", "name": "Charlotte Moore"}
|
| 44 |
+
]
|
| 45 |
+
|
| 46 |
+
license_paths = {
|
| 47 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 48 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
DEFAULT_SPEEDS = {
|
| 52 |
+
"scroll": 40.0,
|
| 53 |
+
"starwars": 80.0,
|
| 54 |
+
"matrix": 40.0
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
def update_panel(
|
| 58 |
+
effect: str,
|
| 59 |
+
speed: float,
|
| 60 |
+
sidebar_position: str,
|
| 61 |
+
show_logo: bool,
|
| 62 |
+
show_licenses: bool,
|
| 63 |
+
logo_position: str,
|
| 64 |
+
logo_sizing: str,
|
| 65 |
+
logo_width: int | str | None,
|
| 66 |
+
logo_height: int | str | None,
|
| 67 |
+
scroll_background_color: str | None,
|
| 68 |
+
scroll_title_color: str | None,
|
| 69 |
+
scroll_name_color: str | None
|
| 70 |
+
):
|
| 71 |
+
print(f"Updating panel: effect={effect}, speed={speed}, sidebar_position={sidebar_position}, show_logo={show_logo}, show_licenses={show_licenses}, logo_position={logo_position}, logo_sizing={logo_sizing}, logo_width={logo_width}, logo_height={logo_height}")
|
| 72 |
+
return gr.update(
|
| 73 |
+
visible=True,
|
| 74 |
+
effect=effect,
|
| 75 |
+
speed=speed,
|
| 76 |
+
sidebar_position=sidebar_position,
|
| 77 |
+
show_logo=show_logo,
|
| 78 |
+
show_licenses=show_licenses,
|
| 79 |
+
logo_position=logo_position,
|
| 80 |
+
logo_sizing=logo_sizing,
|
| 81 |
+
logo_width=logo_width,
|
| 82 |
+
logo_height=logo_height,
|
| 83 |
+
scroll_background_color=scroll_background_color,
|
| 84 |
+
scroll_title_color=scroll_title_color,
|
| 85 |
+
scroll_name_color=scroll_name_color,
|
| 86 |
+
value=credits_list
|
| 87 |
+
# value={
|
| 88 |
+
# "credits": credits_list,
|
| 89 |
+
# "licenses": license_paths,
|
| 90 |
+
# "effect": effect,
|
| 91 |
+
# "speed": speed,
|
| 92 |
+
# "sidebar_position": sidebar_position,
|
| 93 |
+
# "logo_path": "./assets/logo.webp", # Handled by Gradio's file serving
|
| 94 |
+
# "show_logo": show_logo,
|
| 95 |
+
# "show_licenses": show_licenses,
|
| 96 |
+
# "logo_position": logo_position,
|
| 97 |
+
# "logo_sizing": logo_sizing,
|
| 98 |
+
# "logo_width": logo_width,
|
| 99 |
+
# "logo_height": logo_height,
|
| 100 |
+
# "scroll_background_color": scroll_background_color,
|
| 101 |
+
# "scroll_title_color": scroll_title_color,
|
| 102 |
+
# "scroll_name_color": scroll_name_color
|
| 103 |
+
# }
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
def update_speed_on_effect_change(effect: str):
|
| 107 |
+
"""Update speed_slider to default speed when effect changes."""
|
| 108 |
+
return DEFAULT_SPEEDS.get(effect, 40.0)
|
| 109 |
+
|
| 110 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo", css="") as demo:
|
| 111 |
+
gr.Markdown(
|
| 112 |
+
"""
|
| 113 |
+
# Interactive CreditsPanel Demo
|
| 114 |
+
Use the sidebar controls to customize the credits panel.
|
| 115 |
+
"""
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
with gr.Sidebar(position="right"):
|
| 119 |
+
effect_radio = gr.Radio(
|
| 120 |
+
["scroll", "starwars", "matrix"],
|
| 121 |
+
label="Animation Effect",
|
| 122 |
+
value="scroll",
|
| 123 |
+
info="Select the visual style for the credits."
|
| 124 |
+
)
|
| 125 |
+
speed_slider = gr.Slider(
|
| 126 |
+
minimum=5.0,
|
| 127 |
+
maximum=100.0,
|
| 128 |
+
step=1.0,
|
| 129 |
+
value=DEFAULT_SPEEDS["scroll"],
|
| 130 |
+
label="Animation Speed (seconds)",
|
| 131 |
+
info="Duration of the animation cycle."
|
| 132 |
+
)
|
| 133 |
+
sidebar_position_radio = gr.Radio(
|
| 134 |
+
["right", "bottom"],
|
| 135 |
+
label="Sidebar Position",
|
| 136 |
+
value="right",
|
| 137 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 138 |
+
)
|
| 139 |
+
show_logo_checkbox = gr.Checkbox(
|
| 140 |
+
label="Show Logo",
|
| 141 |
+
value=True,
|
| 142 |
+
info="Toggle the logo panel."
|
| 143 |
+
)
|
| 144 |
+
show_licenses_checkbox = gr.Checkbox(
|
| 145 |
+
label="Show Licenses",
|
| 146 |
+
value=True,
|
| 147 |
+
info="Toggle the licenses sidebar."
|
| 148 |
+
)
|
| 149 |
+
logo_position_radio = gr.Radio(
|
| 150 |
+
["center", "left", "right"],
|
| 151 |
+
label="Logo Position",
|
| 152 |
+
value="center",
|
| 153 |
+
info="Position of the logo in the panel."
|
| 154 |
+
)
|
| 155 |
+
logo_sizing_radio = gr.Radio(
|
| 156 |
+
["stretch", "crop", "resize"],
|
| 157 |
+
label="Logo Sizing",
|
| 158 |
+
value="resize",
|
| 159 |
+
info="How the logo fits in the panel."
|
| 160 |
+
)
|
| 161 |
+
logo_width_input = gr.Textbox(
|
| 162 |
+
label="Logo Width (px or CSS)",
|
| 163 |
+
value="200px",
|
| 164 |
+
info="Width of the logo (e.g., '200px' or '50%')."
|
| 165 |
+
)
|
| 166 |
+
logo_height_input = gr.Textbox(
|
| 167 |
+
label="Logo Height (px or CSS)",
|
| 168 |
+
value="100px",
|
| 169 |
+
info="Height of the logo (e.g., '100px' or '10%')."
|
| 170 |
+
)
|
| 171 |
+
scroll_background_color = gr.ColorPicker(
|
| 172 |
+
label="Scroll Background Color",
|
| 173 |
+
value="#000000",
|
| 174 |
+
info="Background color for ScrollEffect."
|
| 175 |
+
)
|
| 176 |
+
scroll_title_color = gr.ColorPicker(
|
| 177 |
+
label="Scroll Title Color",
|
| 178 |
+
value="#FFFFFF",
|
| 179 |
+
info="Color for title text in ScrollEffect."
|
| 180 |
+
)
|
| 181 |
+
scroll_name_color = gr.ColorPicker(
|
| 182 |
+
label="Scroll Name Color",
|
| 183 |
+
value="#FFFFFF",
|
| 184 |
+
info="Color for name text in ScrollEffect."
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
panel = CreditsPanel(
|
| 188 |
+
credits=credits_list,
|
| 189 |
+
licenses=license_paths,
|
| 190 |
+
effect="scroll",
|
| 191 |
+
height=500,
|
| 192 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 193 |
+
sidebar_position="right",
|
| 194 |
+
logo_path="./assets/logo.webp", # Handled by Gradio's file serving
|
| 195 |
+
show_logo=True,
|
| 196 |
+
show_licenses=True,
|
| 197 |
+
logo_position="center",
|
| 198 |
+
logo_sizing="resize",
|
| 199 |
+
logo_width="200px",
|
| 200 |
+
logo_height="100px",
|
| 201 |
+
scroll_background_color="#000000",
|
| 202 |
+
scroll_title_color="#FFFFFF",
|
| 203 |
+
scroll_name_color="#FFFFFF",
|
| 204 |
+
visible=True
|
| 205 |
+
)
|
| 206 |
+
|
| 207 |
+
inputs = [
|
| 208 |
+
effect_radio,
|
| 209 |
+
speed_slider,
|
| 210 |
+
sidebar_position_radio,
|
| 211 |
+
show_logo_checkbox,
|
| 212 |
+
show_licenses_checkbox,
|
| 213 |
+
logo_position_radio,
|
| 214 |
+
logo_sizing_radio,
|
| 215 |
+
logo_width_input,
|
| 216 |
+
logo_height_input,
|
| 217 |
+
scroll_background_color,
|
| 218 |
+
scroll_title_color,
|
| 219 |
+
scroll_name_color
|
| 220 |
+
]
|
| 221 |
+
|
| 222 |
+
# Update speed when effect changes
|
| 223 |
+
effect_radio.change(
|
| 224 |
+
fn=update_speed_on_effect_change,
|
| 225 |
+
inputs=effect_radio,
|
| 226 |
+
outputs=speed_slider
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
# Update panel for all inputs
|
| 230 |
+
for input_component in inputs:
|
| 231 |
+
input_component.change(
|
| 232 |
+
fn=update_panel,
|
| 233 |
+
inputs=inputs,
|
| 234 |
+
outputs=panel
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
if __name__ == "__main__":
|
| 238 |
+
demo.launch(debug=True, share=False)
|
src/demo/app.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
app.py
|
| 3 |
+
|
| 4 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 5 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 6 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 7 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import gradio as gr
|
| 11 |
+
from gradio_creditspanel import CreditsPanel
|
| 12 |
+
import os
|
| 13 |
+
|
| 14 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 15 |
+
# This section prepares all necessary assets and data for the demo.
|
| 16 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 17 |
+
|
| 18 |
+
def setup_demo_files():
|
| 19 |
+
"""
|
| 20 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 21 |
+
This makes the application self-contained and easy to run.
|
| 22 |
+
"""
|
| 23 |
+
# Create dummy license files
|
| 24 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 25 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 26 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 27 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 28 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 29 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 30 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 31 |
+
|
| 32 |
+
# Create a placeholder logo if it doesn't exist
|
| 33 |
+
os.makedirs("assets", exist_ok=True)
|
| 34 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 35 |
+
with open("./assets/logo.webp", "w") as f:
|
| 36 |
+
f.write("Placeholder WebP logo")
|
| 37 |
+
|
| 38 |
+
# Initial data for the credits roll
|
| 39 |
+
credits_list = [
|
| 40 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 41 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 42 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 43 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 44 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 45 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 46 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 47 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 48 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 49 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 50 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 51 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 52 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 53 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 54 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 55 |
+
]
|
| 56 |
+
|
| 57 |
+
# Paths to license files
|
| 58 |
+
license_paths = {
|
| 59 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 60 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 64 |
+
DEFAULT_SPEEDS = {
|
| 65 |
+
"scroll": 40.0,
|
| 66 |
+
"starwars": 80.0,
|
| 67 |
+
"matrix": 40.0
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 71 |
+
# These functions define the application's interactive logic.
|
| 72 |
+
|
| 73 |
+
def update_panel(
|
| 74 |
+
effect: str, speed: float, base_font_size: float,
|
| 75 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 76 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 77 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 78 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 79 |
+
scroll_name_color: str | None
|
| 80 |
+
) -> dict:
|
| 81 |
+
"""
|
| 82 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 83 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 84 |
+
"""
|
| 85 |
+
return gr.update(
|
| 86 |
+
visible=True,
|
| 87 |
+
effect=effect,
|
| 88 |
+
speed=speed,
|
| 89 |
+
base_font_size=base_font_size,
|
| 90 |
+
intro_title=intro_title,
|
| 91 |
+
intro_subtitle=intro_subtitle,
|
| 92 |
+
sidebar_position=sidebar_position,
|
| 93 |
+
show_logo=show_logo,
|
| 94 |
+
show_licenses=show_licenses,
|
| 95 |
+
logo_position=logo_position,
|
| 96 |
+
logo_sizing=logo_sizing,
|
| 97 |
+
logo_width=logo_width,
|
| 98 |
+
logo_height=logo_height,
|
| 99 |
+
scroll_background_color=scroll_background_color,
|
| 100 |
+
scroll_title_color=scroll_title_color,
|
| 101 |
+
scroll_name_color=scroll_name_color,
|
| 102 |
+
value=credits_list # The list of credits to display
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 106 |
+
"""
|
| 107 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 108 |
+
animation effect is changed.
|
| 109 |
+
"""
|
| 110 |
+
font_size = 1.5
|
| 111 |
+
if effect == "starwars":
|
| 112 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 113 |
+
|
| 114 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 115 |
+
return speed, font_size
|
| 116 |
+
|
| 117 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 118 |
+
# This section constructs the user interface using gr.Blocks.
|
| 119 |
+
|
| 120 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 121 |
+
gr.Markdown(
|
| 122 |
+
"""
|
| 123 |
+
# Interactive CreditsPanel Demo
|
| 124 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 125 |
+
"""
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
with gr.Sidebar(position="right"):
|
| 129 |
+
gr.Markdown("### Effects Settings")
|
| 130 |
+
effect_radio = gr.Radio(
|
| 131 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 132 |
+
info="Select the visual style for the credits."
|
| 133 |
+
)
|
| 134 |
+
speed_slider = gr.Slider(
|
| 135 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 136 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 137 |
+
)
|
| 138 |
+
font_size_slider = gr.Slider(
|
| 139 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 140 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
gr.Markdown("### Intro Text")
|
| 144 |
+
intro_title_input = gr.Textbox(
|
| 145 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 146 |
+
)
|
| 147 |
+
intro_subtitle_input = gr.Textbox(
|
| 148 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
gr.Markdown("### Layout & Visibility")
|
| 152 |
+
sidebar_position_radio = gr.Radio(
|
| 153 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 154 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 155 |
+
)
|
| 156 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 157 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 158 |
+
|
| 159 |
+
gr.Markdown("### Logo Customization")
|
| 160 |
+
logo_position_radio = gr.Radio(
|
| 161 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 162 |
+
)
|
| 163 |
+
logo_sizing_radio = gr.Radio(
|
| 164 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 165 |
+
)
|
| 166 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 167 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 168 |
+
|
| 169 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 170 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 171 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 172 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 173 |
+
|
| 174 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 175 |
+
panel = CreditsPanel(
|
| 176 |
+
credits=credits_list,
|
| 177 |
+
licenses=license_paths,
|
| 178 |
+
effect="scroll",
|
| 179 |
+
height=500,
|
| 180 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 181 |
+
base_font_size=1.5,
|
| 182 |
+
intro_title="Gradio",
|
| 183 |
+
intro_subtitle="The best UI framework",
|
| 184 |
+
sidebar_position="right",
|
| 185 |
+
logo_path="./assets/logo.webp",
|
| 186 |
+
show_logo=True,
|
| 187 |
+
show_licenses=True,
|
| 188 |
+
logo_position="center",
|
| 189 |
+
logo_sizing="resize",
|
| 190 |
+
logo_width="200px",
|
| 191 |
+
logo_height="100px",
|
| 192 |
+
scroll_background_color="#000000",
|
| 193 |
+
scroll_title_color="#FFFFFF",
|
| 194 |
+
scroll_name_color="#FFFFFF",
|
| 195 |
+
)
|
| 196 |
+
|
| 197 |
+
# List of all input components that should trigger a panel update
|
| 198 |
+
inputs = [
|
| 199 |
+
effect_radio, speed_slider, font_size_slider,
|
| 200 |
+
intro_title_input, intro_subtitle_input,
|
| 201 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 202 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 203 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 204 |
+
]
|
| 205 |
+
|
| 206 |
+
# --- 4. EVENT BINDING ---
|
| 207 |
+
# Connect the UI controls to the handler functions.
|
| 208 |
+
|
| 209 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 210 |
+
effect_radio.change(
|
| 211 |
+
fn=update_ui_on_effect_change,
|
| 212 |
+
inputs=effect_radio,
|
| 213 |
+
outputs=[speed_slider, font_size_slider]
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
# General event: any change in an input control updates the main panel
|
| 217 |
+
for input_component in inputs:
|
| 218 |
+
input_component.change(
|
| 219 |
+
fn=update_panel,
|
| 220 |
+
inputs=inputs,
|
| 221 |
+
outputs=panel
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
# --- 5. APP LAUNCH ---
|
| 225 |
+
if __name__ == "__main__":
|
| 226 |
+
setup_demo_files()
|
| 227 |
+
demo.launch()
|
src/demo/css.css
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
html {
|
| 2 |
+
font-family: Inter;
|
| 3 |
+
font-size: 16px;
|
| 4 |
+
font-weight: 400;
|
| 5 |
+
line-height: 1.5;
|
| 6 |
+
-webkit-text-size-adjust: 100%;
|
| 7 |
+
background: #fff;
|
| 8 |
+
color: #323232;
|
| 9 |
+
-webkit-font-smoothing: antialiased;
|
| 10 |
+
-moz-osx-font-smoothing: grayscale;
|
| 11 |
+
text-rendering: optimizeLegibility;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
:root {
|
| 15 |
+
--space: 1;
|
| 16 |
+
--vspace: calc(var(--space) * 1rem);
|
| 17 |
+
--vspace-0: calc(3 * var(--space) * 1rem);
|
| 18 |
+
--vspace-1: calc(2 * var(--space) * 1rem);
|
| 19 |
+
--vspace-2: calc(1.5 * var(--space) * 1rem);
|
| 20 |
+
--vspace-3: calc(0.5 * var(--space) * 1rem);
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
.app {
|
| 24 |
+
max-width: 748px !important;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
.prose p {
|
| 28 |
+
margin: var(--vspace) 0;
|
| 29 |
+
line-height: var(--vspace * 2);
|
| 30 |
+
font-size: 1rem;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
code {
|
| 34 |
+
font-family: "Inconsolata", sans-serif;
|
| 35 |
+
font-size: 16px;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
h1,
|
| 39 |
+
h1 code {
|
| 40 |
+
font-weight: 400;
|
| 41 |
+
line-height: calc(2.5 / var(--space) * var(--vspace));
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
h1 code {
|
| 45 |
+
background: none;
|
| 46 |
+
border: none;
|
| 47 |
+
letter-spacing: 0.05em;
|
| 48 |
+
padding-bottom: 5px;
|
| 49 |
+
position: relative;
|
| 50 |
+
padding: 0;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
h2 {
|
| 54 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
| 55 |
+
line-height: 1em;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
h3,
|
| 59 |
+
h3 code {
|
| 60 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
| 61 |
+
line-height: 1em;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
h4,
|
| 65 |
+
h5,
|
| 66 |
+
h6 {
|
| 67 |
+
margin: var(--vspace-3) 0 var(--vspace-3) 0;
|
| 68 |
+
line-height: var(--vspace);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
.bigtitle,
|
| 72 |
+
h1,
|
| 73 |
+
h1 code {
|
| 74 |
+
font-size: calc(8px * 4.5);
|
| 75 |
+
word-break: break-word;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
.title,
|
| 79 |
+
h2,
|
| 80 |
+
h2 code {
|
| 81 |
+
font-size: calc(8px * 3.375);
|
| 82 |
+
font-weight: lighter;
|
| 83 |
+
word-break: break-word;
|
| 84 |
+
border: none;
|
| 85 |
+
background: none;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
.subheading1,
|
| 89 |
+
h3,
|
| 90 |
+
h3 code {
|
| 91 |
+
font-size: calc(8px * 1.8);
|
| 92 |
+
font-weight: 600;
|
| 93 |
+
border: none;
|
| 94 |
+
background: none;
|
| 95 |
+
letter-spacing: 0.1em;
|
| 96 |
+
text-transform: uppercase;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
h2 code {
|
| 100 |
+
padding: 0;
|
| 101 |
+
position: relative;
|
| 102 |
+
letter-spacing: 0.05em;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
blockquote {
|
| 106 |
+
font-size: calc(8px * 1.1667);
|
| 107 |
+
font-style: italic;
|
| 108 |
+
line-height: calc(1.1667 * var(--vspace));
|
| 109 |
+
margin: var(--vspace-2) var(--vspace-2);
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
.subheading2,
|
| 113 |
+
h4 {
|
| 114 |
+
font-size: calc(8px * 1.4292);
|
| 115 |
+
text-transform: uppercase;
|
| 116 |
+
font-weight: 600;
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
.subheading3,
|
| 120 |
+
h5 {
|
| 121 |
+
font-size: calc(8px * 1.2917);
|
| 122 |
+
line-height: calc(1.2917 * var(--vspace));
|
| 123 |
+
|
| 124 |
+
font-weight: lighter;
|
| 125 |
+
text-transform: uppercase;
|
| 126 |
+
letter-spacing: 0.15em;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
h6 {
|
| 130 |
+
font-size: calc(8px * 1.1667);
|
| 131 |
+
font-size: 1.1667em;
|
| 132 |
+
font-weight: normal;
|
| 133 |
+
font-style: italic;
|
| 134 |
+
font-family: "le-monde-livre-classic-byol", serif !important;
|
| 135 |
+
letter-spacing: 0px !important;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
#start .md > *:first-child {
|
| 139 |
+
margin-top: 0;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
h2 + h3 {
|
| 143 |
+
margin-top: 0;
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
.md hr {
|
| 147 |
+
border: none;
|
| 148 |
+
border-top: 1px solid var(--block-border-color);
|
| 149 |
+
margin: var(--vspace-2) 0 var(--vspace-2) 0;
|
| 150 |
+
}
|
| 151 |
+
.prose ul {
|
| 152 |
+
margin: var(--vspace-2) 0 var(--vspace-1) 0;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
.gap {
|
| 156 |
+
gap: 0;
|
| 157 |
+
}
|
src/demo/requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
gradio_creditspanel
|
src/demo/space.py
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from app import demo as app
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
_docs = {'CreditsPanel': {'description': 'A Gradio component for displaying credits with customizable visual effects, such as scrolling or Star Wars-style animations.\nSupports displaying a logo, licenses, and configurable text styling.\n\n EVENTS (list): Supported events for the component, currently only `change`.', 'members': {'__init__': {'value': {'type': 'Any', 'default': 'None', 'description': None}, 'credits': {'type': 'typing.Union[\n typing.List[typing.Dict[str, str]],\n typing.Callable,\n NoneType,\n][\n typing.List[typing.Dict[str, str]][\n typing.Dict[str, str][str, str]\n ],\n Callable,\n None,\n]', 'default': 'None', 'description': None}, 'height': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'width': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'licenses': {'type': 'typing.Optional[typing.Dict[str, str | pathlib.Path]][\n typing.Dict[str, str | pathlib.Path][\n str, str | pathlib.Path\n ],\n None,\n]', 'default': 'None', 'description': None}, 'effect': {'type': '"scroll" | "starwars" | "matrix"', 'default': '"scroll"', 'description': None}, 'speed': {'type': 'float', 'default': '40.0', 'description': None}, 'base_font_size': {'type': 'float', 'default': '1.5', 'description': None}, 'intro_title': {'type': 'str | None', 'default': 'None', 'description': None}, 'intro_subtitle': {'type': 'str | None', 'default': 'None', 'description': None}, 'sidebar_position': {'type': '"right" | "bottom"', 'default': '"right"', 'description': None}, 'logo_path': {'type': 'str | pathlib.Path | None', 'default': 'None', 'description': None}, 'show_logo': {'type': 'bool', 'default': 'True', 'description': None}, 'show_licenses': {'type': 'bool', 'default': 'True', 'description': None}, 'logo_position': {'type': '"center" | "left" | "right"', 'default': '"center"', 'description': None}, 'logo_sizing': {'type': '"stretch" | "crop" | "resize"', 'default': '"resize"', 'description': None}, 'logo_width': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'logo_height': {'type': 'int | str | None', 'default': 'None', 'description': None}, 'scroll_background_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'scroll_title_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'scroll_name_color': {'type': 'str | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | gradio.i18n.I18nData | None', 'default': 'None', 'description': None}, 'every': {'type': 'float | None', 'default': 'None', 'description': None}, 'inputs': {'type': 'typing.Union[\n gradio.components.base.Component,\n typing.Sequence[gradio.components.base.Component],\n set[gradio.components.base.Component],\n NoneType,\n][\n gradio.components.base.Component,\n typing.Sequence[gradio.components.base.Component][\n gradio.components.base.Component\n ],\n set[gradio.components.base.Component],\n None,\n]', 'default': 'None', 'description': None}, 'show_label': {'type': 'bool', 'default': 'False', 'description': None}, 'container': {'type': 'bool', 'default': 'True', 'description': None}, 'scale': {'type': 'int | None', 'default': 'None', 'description': None}, 'min_width': {'type': 'int', 'default': '160', 'description': None}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': None}, 'visible': {'type': 'bool', 'default': 'True', 'description': None}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': None}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': None}, 'render': {'type': 'bool', 'default': 'True', 'description': None}, 'key': {'type': 'int | str | tuple[int | str, Ellipsis] | None', 'default': 'None', 'description': None}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': None}}, 'postprocess': {'value': {'type': 'Any', 'description': None}}, 'preprocess': {'return': {'type': 'typing.Optional[typing.Dict[str, typing.Any]][\n typing.Dict[str, typing.Any][str, Any], None\n]', 'description': 'Dict[str, Any] | None: The input payload, returned unchanged.'}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the CreditsPanel changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'CreditsPanel': []}}}
|
| 7 |
+
|
| 8 |
+
abs_path = os.path.join(os.path.dirname(__file__), "css.css")
|
| 9 |
+
|
| 10 |
+
with gr.Blocks(
|
| 11 |
+
css=abs_path,
|
| 12 |
+
theme=gr.themes.Ocean(
|
| 13 |
+
font_mono=[
|
| 14 |
+
gr.themes.GoogleFont("Inconsolata"),
|
| 15 |
+
"monospace",
|
| 16 |
+
],
|
| 17 |
+
),
|
| 18 |
+
) as demo:
|
| 19 |
+
gr.Markdown(
|
| 20 |
+
"""
|
| 21 |
+
# `gradio_creditspanel`
|
| 22 |
+
|
| 23 |
+
<div style="display: flex; gap: 7px;">
|
| 24 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
| 25 |
+
</div>
|
| 26 |
+
|
| 27 |
+
Credits Panel for Gradio UI
|
| 28 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 29 |
+
app.render()
|
| 30 |
+
gr.Markdown(
|
| 31 |
+
"""
|
| 32 |
+
## Installation
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
pip install gradio_creditspanel
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
## Usage
|
| 39 |
+
|
| 40 |
+
```python
|
| 41 |
+
\"\"\"
|
| 42 |
+
app.py
|
| 43 |
+
|
| 44 |
+
This script serves as an interactive demonstration for the custom Gradio component `CreditsPanel`.
|
| 45 |
+
It showcases all available features of the component, allowing users to dynamically adjust
|
| 46 |
+
properties like animation effects, speed, layout, and styling. The app also demonstrates
|
| 47 |
+
how to handle file dependencies (logo, licenses) in a portable way.
|
| 48 |
+
\"\"\"
|
| 49 |
+
|
| 50 |
+
import gradio as gr
|
| 51 |
+
from gradio_creditspanel import CreditsPanel
|
| 52 |
+
import os
|
| 53 |
+
|
| 54 |
+
# --- 1. SETUP & DATA PREPARATION ---
|
| 55 |
+
# This section prepares all necessary assets and data for the demo.
|
| 56 |
+
# It ensures the demo runs out-of-the-box without manual setup.
|
| 57 |
+
|
| 58 |
+
def setup_demo_files():
|
| 59 |
+
\"\"\"
|
| 60 |
+
Creates necessary directories and dummy files (logo, licenses) for the demo.
|
| 61 |
+
This makes the application self-contained and easy to run.
|
| 62 |
+
\"\"\"
|
| 63 |
+
# Create dummy license files
|
| 64 |
+
os.makedirs("LICENSES", exist_ok=True)
|
| 65 |
+
if not os.path.exists("LICENSES/Apache.txt"):
|
| 66 |
+
with open("LICENSES/Apache.txt", "w") as f:
|
| 67 |
+
f.write("Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/...")
|
| 68 |
+
if not os.path.exists("LICENSES/MIT.txt"):
|
| 69 |
+
with open("LICENSES/MIT.txt", "w") as f:
|
| 70 |
+
f.write("MIT License\nCopyright (c) 2025 Author\nPermission is hereby granted...")
|
| 71 |
+
|
| 72 |
+
# Create a placeholder logo if it doesn't exist
|
| 73 |
+
os.makedirs("assets", exist_ok=True)
|
| 74 |
+
if not os.path.exists("./assets/logo.webp"):
|
| 75 |
+
with open("./assets/logo.webp", "w") as f:
|
| 76 |
+
f.write("Placeholder WebP logo")
|
| 77 |
+
|
| 78 |
+
# Initial data for the credits roll
|
| 79 |
+
credits_list = [
|
| 80 |
+
{"title": "Project Manager", "name": "Emma Thompson"},
|
| 81 |
+
{"title": "Lead Developer", "name": "John Doe"},
|
| 82 |
+
{"title": "Senior Backend Engineer", "name": "Michael Chen"},
|
| 83 |
+
{"title": "Frontend Developer", "name": "Sarah Johnson"},
|
| 84 |
+
{"title": "UI/UX Designer", "name": "Jane Smith"},
|
| 85 |
+
{"title": "Database Architect", "name": "Alex Ray"},
|
| 86 |
+
{"title": "DevOps Engineer", "name": "Liam Patel"},
|
| 87 |
+
{"title": "Quality Assurance Lead", "name": "Sam Wilson"},
|
| 88 |
+
{"title": "Test Automation Engineer", "name": "Olivia Brown"},
|
| 89 |
+
{"title": "Security Analyst", "name": "David Kim"},
|
| 90 |
+
{"title": "Data Scientist", "name": "Sophie Martinez"},
|
| 91 |
+
{"title": "Machine Learning Engineer", "name": "Ethan Lee"},
|
| 92 |
+
{"title": "API Developer", "name": "Isabella Garcia"},
|
| 93 |
+
{"title": "Technical Writer", "name": "Noah Davis"},
|
| 94 |
+
{"title": "Scrum Master", "name": "Ava Rodriguez"},
|
| 95 |
+
]
|
| 96 |
+
|
| 97 |
+
# Paths to license files
|
| 98 |
+
license_paths = {
|
| 99 |
+
"Gradio Framework": "./LICENSES/Apache.txt",
|
| 100 |
+
"This Component": "./LICENSES/MIT.txt"
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
# Default animation speeds for each effect to provide a good user experience
|
| 104 |
+
DEFAULT_SPEEDS = {
|
| 105 |
+
"scroll": 40.0,
|
| 106 |
+
"starwars": 80.0,
|
| 107 |
+
"matrix": 40.0
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
# --- 2. GRADIO EVENT HANDLER FUNCTIONS ---
|
| 111 |
+
# These functions define the application's interactive logic.
|
| 112 |
+
|
| 113 |
+
def update_panel(
|
| 114 |
+
effect: str, speed: float, base_font_size: float,
|
| 115 |
+
intro_title: str, intro_subtitle: str, sidebar_position: str,
|
| 116 |
+
show_logo: bool, show_licenses: bool, logo_position: str,
|
| 117 |
+
logo_sizing: str, logo_width: str | None, logo_height: str | None,
|
| 118 |
+
scroll_background_color: str | None, scroll_title_color: str | None,
|
| 119 |
+
scroll_name_color: str | None
|
| 120 |
+
) -> dict:
|
| 121 |
+
\"\"\"
|
| 122 |
+
Callback function that updates all properties of the CreditsPanel component.
|
| 123 |
+
It takes the current state of all UI controls and returns a gr.update() dictionary.
|
| 124 |
+
\"\"\"
|
| 125 |
+
return gr.update(
|
| 126 |
+
visible=True,
|
| 127 |
+
effect=effect,
|
| 128 |
+
speed=speed,
|
| 129 |
+
base_font_size=base_font_size,
|
| 130 |
+
intro_title=intro_title,
|
| 131 |
+
intro_subtitle=intro_subtitle,
|
| 132 |
+
sidebar_position=sidebar_position,
|
| 133 |
+
show_logo=show_logo,
|
| 134 |
+
show_licenses=show_licenses,
|
| 135 |
+
logo_position=logo_position,
|
| 136 |
+
logo_sizing=logo_sizing,
|
| 137 |
+
logo_width=logo_width,
|
| 138 |
+
logo_height=logo_height,
|
| 139 |
+
scroll_background_color=scroll_background_color,
|
| 140 |
+
scroll_title_color=scroll_title_color,
|
| 141 |
+
scroll_name_color=scroll_name_color,
|
| 142 |
+
value=credits_list # The list of credits to display
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
def update_ui_on_effect_change(effect: str) -> tuple[float, float]:
|
| 146 |
+
\"\"\"
|
| 147 |
+
Updates the speed and font size sliders to sensible defaults when the
|
| 148 |
+
animation effect is changed.
|
| 149 |
+
\"\"\"
|
| 150 |
+
font_size = 1.5
|
| 151 |
+
if effect == "starwars":
|
| 152 |
+
font_size = 6.0 # Star Wars effect looks better with a larger font
|
| 153 |
+
|
| 154 |
+
speed = DEFAULT_SPEEDS.get(effect, 40.0)
|
| 155 |
+
return speed, font_size
|
| 156 |
+
|
| 157 |
+
# --- 3. GRADIO UI DEFINITION ---
|
| 158 |
+
# This section constructs the user interface using gr.Blocks.
|
| 159 |
+
|
| 160 |
+
with gr.Blocks(theme=gr.themes.Ocean(), title="CreditsPanel Demo") as demo:
|
| 161 |
+
gr.Markdown(
|
| 162 |
+
\"\"\"
|
| 163 |
+
# Interactive CreditsPanel Demo
|
| 164 |
+
Use the sidebar controls to customize the `CreditsPanel` component in real-time.
|
| 165 |
+
\"\"\"
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
with gr.Sidebar(position="right"):
|
| 169 |
+
gr.Markdown("### Effects Settings")
|
| 170 |
+
effect_radio = gr.Radio(
|
| 171 |
+
["scroll", "starwars", "matrix"], label="Animation Effect", value="scroll",
|
| 172 |
+
info="Select the visual style for the credits."
|
| 173 |
+
)
|
| 174 |
+
speed_slider = gr.Slider(
|
| 175 |
+
minimum=5.0, maximum=100.0, step=1.0, value=DEFAULT_SPEEDS["scroll"],
|
| 176 |
+
label="Animation Speed (seconds)", info="Duration of one animation cycle."
|
| 177 |
+
)
|
| 178 |
+
font_size_slider = gr.Slider(
|
| 179 |
+
minimum=1.0, maximum=10.0, step=0.1, value=1.5,
|
| 180 |
+
label="Base Font Size (rem)", info="Controls the base font size."
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
gr.Markdown("### Intro Text")
|
| 184 |
+
intro_title_input = gr.Textbox(
|
| 185 |
+
label="Intro Title", value="Gradio", info="Main title for the intro sequence."
|
| 186 |
+
)
|
| 187 |
+
intro_subtitle_input = gr.Textbox(
|
| 188 |
+
label="Intro Subtitle", value="The best UI framework", info="Subtitle for the intro sequence."
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
gr.Markdown("### Layout & Visibility")
|
| 192 |
+
sidebar_position_radio = gr.Radio(
|
| 193 |
+
["right", "bottom"], label="Sidebar Position", value="right",
|
| 194 |
+
info="Place the licenses sidebar on the right or bottom."
|
| 195 |
+
)
|
| 196 |
+
show_logo_checkbox = gr.Checkbox(label="Show Logo", value=True)
|
| 197 |
+
show_licenses_checkbox = gr.Checkbox(label="Show Licenses", value=True)
|
| 198 |
+
|
| 199 |
+
gr.Markdown("### Logo Customization")
|
| 200 |
+
logo_position_radio = gr.Radio(
|
| 201 |
+
["left", "center", "right"], label="Logo Position", value="center"
|
| 202 |
+
)
|
| 203 |
+
logo_sizing_radio = gr.Radio(
|
| 204 |
+
["stretch", "crop", "resize"], label="Logo Sizing", value="resize"
|
| 205 |
+
)
|
| 206 |
+
logo_width_input = gr.Textbox(label="Logo Width", value="200px")
|
| 207 |
+
logo_height_input = gr.Textbox(label="Logo Height", value="100px")
|
| 208 |
+
|
| 209 |
+
gr.Markdown("### Color Settings (Scroll Effect)")
|
| 210 |
+
scroll_background_color = gr.ColorPicker(label="Background Color", value="#000000")
|
| 211 |
+
scroll_title_color = gr.ColorPicker(label="Title Color", value="#FFFFFF")
|
| 212 |
+
scroll_name_color = gr.ColorPicker(label="Name Color", value="#FFFFFF")
|
| 213 |
+
|
| 214 |
+
# Instantiate the custom CreditsPanel component with default values
|
| 215 |
+
panel = CreditsPanel(
|
| 216 |
+
credits=credits_list,
|
| 217 |
+
licenses=license_paths,
|
| 218 |
+
effect="scroll",
|
| 219 |
+
height=500,
|
| 220 |
+
speed=DEFAULT_SPEEDS["scroll"],
|
| 221 |
+
base_font_size=1.5,
|
| 222 |
+
intro_title="Gradio",
|
| 223 |
+
intro_subtitle="The best UI framework",
|
| 224 |
+
sidebar_position="right",
|
| 225 |
+
logo_path="./assets/logo.webp",
|
| 226 |
+
show_logo=True,
|
| 227 |
+
show_licenses=True,
|
| 228 |
+
logo_position="center",
|
| 229 |
+
logo_sizing="resize",
|
| 230 |
+
logo_width="200px",
|
| 231 |
+
logo_height="100px",
|
| 232 |
+
scroll_background_color="#000000",
|
| 233 |
+
scroll_title_color="#FFFFFF",
|
| 234 |
+
scroll_name_color="#FFFFFF",
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
# List of all input components that should trigger a panel update
|
| 238 |
+
inputs = [
|
| 239 |
+
effect_radio, speed_slider, font_size_slider,
|
| 240 |
+
intro_title_input, intro_subtitle_input,
|
| 241 |
+
sidebar_position_radio, show_logo_checkbox, show_licenses_checkbox,
|
| 242 |
+
logo_position_radio, logo_sizing_radio, logo_width_input, logo_height_input,
|
| 243 |
+
scroll_background_color, scroll_title_color, scroll_name_color
|
| 244 |
+
]
|
| 245 |
+
|
| 246 |
+
# --- 4. EVENT BINDING ---
|
| 247 |
+
# Connect the UI controls to the handler functions.
|
| 248 |
+
|
| 249 |
+
# Special event: changing the effect also updates speed and font size sliders
|
| 250 |
+
effect_radio.change(
|
| 251 |
+
fn=update_ui_on_effect_change,
|
| 252 |
+
inputs=effect_radio,
|
| 253 |
+
outputs=[speed_slider, font_size_slider]
|
| 254 |
+
)
|
| 255 |
+
|
| 256 |
+
# General event: any change in an input control updates the main panel
|
| 257 |
+
for input_component in inputs:
|
| 258 |
+
input_component.change(
|
| 259 |
+
fn=update_panel,
|
| 260 |
+
inputs=inputs,
|
| 261 |
+
outputs=panel
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
# --- 5. APP LAUNCH ---
|
| 265 |
+
if __name__ == "__main__":
|
| 266 |
+
setup_demo_files()
|
| 267 |
+
demo.launch()
|
| 268 |
+
```
|
| 269 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
gr.Markdown("""
|
| 273 |
+
## `CreditsPanel`
|
| 274 |
+
|
| 275 |
+
### Initialization
|
| 276 |
+
""", elem_classes=["md-custom"], header_links=True)
|
| 277 |
+
|
| 278 |
+
gr.ParamViewer(value=_docs["CreditsPanel"]["members"]["__init__"], linkify=[])
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
gr.Markdown("### Events")
|
| 282 |
+
gr.ParamViewer(value=_docs["CreditsPanel"]["events"], linkify=['Event'])
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
gr.Markdown("""
|
| 288 |
+
|
| 289 |
+
### User function
|
| 290 |
+
|
| 291 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
| 292 |
+
|
| 293 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
| 294 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
| 295 |
+
|
| 296 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
| 297 |
+
|
| 298 |
+
- **As input:** Is passed, dict[str, Any] | None: The input payload, returned unchanged.
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
```python
|
| 302 |
+
def predict(
|
| 303 |
+
value: typing.Optional[typing.Dict[str, typing.Any]][
|
| 304 |
+
typing.Dict[str, typing.Any][str, Any], None
|
| 305 |
+
]
|
| 306 |
+
) -> Any:
|
| 307 |
+
return value
|
| 308 |
+
```
|
| 309 |
+
""", elem_classes=["md-custom", "CreditsPanel-user-fn"], header_links=True)
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
demo.load(None, js=r"""function() {
|
| 315 |
+
const refs = {};
|
| 316 |
+
const user_fn_refs = {
|
| 317 |
+
CreditsPanel: [], };
|
| 318 |
+
requestAnimationFrame(() => {
|
| 319 |
+
|
| 320 |
+
Object.entries(user_fn_refs).forEach(([key, refs]) => {
|
| 321 |
+
if (refs.length > 0) {
|
| 322 |
+
const el = document.querySelector(`.${key}-user-fn`);
|
| 323 |
+
if (!el) return;
|
| 324 |
+
refs.forEach(ref => {
|
| 325 |
+
el.innerHTML = el.innerHTML.replace(
|
| 326 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
| 327 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
| 328 |
+
);
|
| 329 |
+
})
|
| 330 |
+
}
|
| 331 |
+
})
|
| 332 |
+
|
| 333 |
+
Object.entries(refs).forEach(([key, refs]) => {
|
| 334 |
+
if (refs.length > 0) {
|
| 335 |
+
const el = document.querySelector(`.${key}`);
|
| 336 |
+
if (!el) return;
|
| 337 |
+
refs.forEach(ref => {
|
| 338 |
+
el.innerHTML = el.innerHTML.replace(
|
| 339 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
| 340 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
| 341 |
+
);
|
| 342 |
+
})
|
| 343 |
+
}
|
| 344 |
+
})
|
| 345 |
+
})
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
""")
|
| 349 |
+
|
| 350 |
+
demo.launch()
|
src/frontend/Example.svelte
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
export let value: string;
|
| 3 |
+
export let type: "gallery" | "table";
|
| 4 |
+
export let selected = false;
|
| 5 |
+
</script>
|
| 6 |
+
|
| 7 |
+
<div
|
| 8 |
+
class:table={type === "table"}
|
| 9 |
+
class:gallery={type === "gallery"}
|
| 10 |
+
class:selected
|
| 11 |
+
class="prose"
|
| 12 |
+
>
|
| 13 |
+
{@html value}
|
| 14 |
+
</div>
|
| 15 |
+
|
| 16 |
+
<style>
|
| 17 |
+
.gallery {
|
| 18 |
+
padding: var(--size-2);
|
| 19 |
+
}
|
| 20 |
+
</style>
|
src/frontend/Index.svelte
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import type { Gradio } from "@gradio/utils";
|
| 3 |
+
import { Block } from "@gradio/atoms";
|
| 4 |
+
import { StatusTracker } from "@gradio/statustracker";
|
| 5 |
+
import type { LoadingStatus } from "@gradio/statustracker";
|
| 6 |
+
import ScrollEffect from "./shared/ScrollEffect.svelte";
|
| 7 |
+
import StarWarsEffect from "./shared/StarWarsEffect.svelte";
|
| 8 |
+
import MatrixEffect from "./shared/MatrixEffect.svelte";
|
| 9 |
+
import { Image } from "@gradio/image/shared";
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* Props for the Index component.
|
| 13 |
+
* @typedef {Object} Value
|
| 14 |
+
* @property {Array<{title: string, name: string}>} credits - List of credits with title and name.
|
| 15 |
+
* @property {Record<string, string>} licenses - License names and content.
|
| 16 |
+
* @property {"scroll" | "starwars" | "matrix"} effect - Credits display effect.
|
| 17 |
+
* @property {number} speed - Animation speed in seconds.
|
| 18 |
+
* @property {number} base_font_size - Base font size in rem.
|
| 19 |
+
* @property {string | null} intro_title - Intro title.
|
| 20 |
+
* @property {string | null} intro_subtitle - Intro subtitle.
|
| 21 |
+
* @property {"right" | "bottom"} sidebar_position - Licenses sidebar position.
|
| 22 |
+
* @property {{path: string | null, url: string | null, orig_name: string | null, mime_type: string | null} | null} logo_path - Logo file details.
|
| 23 |
+
* @property {boolean} show_logo - Show logo.
|
| 24 |
+
* @property {boolean} show_licenses - Show licenses.
|
| 25 |
+
* @property {"center" | "left" | "right"} logo_position - Logo alignment.
|
| 26 |
+
* @property {"stretch" | "crop" | "resize"} logo_sizing - Logo sizing mode.
|
| 27 |
+
* @property {number | string | null} logo_width - Logo width.
|
| 28 |
+
* @property {number | string | null} logo_height - Logo height.
|
| 29 |
+
* @property {string | null} scroll_background_color - Scroll effect background color.
|
| 30 |
+
* @property {string | null} scroll_title_color - Credit title color.
|
| 31 |
+
* @property {string | null} scroll_name_color - Credit name color.
|
| 32 |
+
* @property {number} title_font_size - Title font size (unused in StarWarsEffect).
|
| 33 |
+
* @property {number} name_font_size - Name font size (unused in StarWarsEffect).
|
| 34 |
+
*/
|
| 35 |
+
export let value: Value | null = null;
|
| 36 |
+
export let elem_id = "";
|
| 37 |
+
export let elem_classes: string[] = [];
|
| 38 |
+
export let visible = true;
|
| 39 |
+
export let container = true;
|
| 40 |
+
export let scale: number | null = null;
|
| 41 |
+
export let min_width: number | undefined = undefined;
|
| 42 |
+
export let height: number | string | undefined = undefined;
|
| 43 |
+
export let width: number | string | undefined = undefined;
|
| 44 |
+
export let loading_status: LoadingStatus;
|
| 45 |
+
export let gradio: Gradio<{ change: never }>;
|
| 46 |
+
|
| 47 |
+
// Default value if `value` is null
|
| 48 |
+
$: effectiveValue = value || {
|
| 49 |
+
credits: [
|
| 50 |
+
{ title: "Lead Developer", name: "John Doe" },
|
| 51 |
+
{ title: "UI/UX Design", name: "Jane Smith" },
|
| 52 |
+
{ title: "Backend Engineering", name: "Alex Ray" },
|
| 53 |
+
{ title: "Component Concept", name: "Your Name" },
|
| 54 |
+
{ title: "Quality Assurance", name: "Sam Wilson" },
|
| 55 |
+
],
|
| 56 |
+
licenses: {
|
| 57 |
+
"Gradio Framework": "Apache License placeholder",
|
| 58 |
+
"This Component": "MIT License placeholder",
|
| 59 |
+
},
|
| 60 |
+
effect: "scroll",
|
| 61 |
+
speed: 40,
|
| 62 |
+
base_font_size: 1.5,
|
| 63 |
+
intro_title: "",
|
| 64 |
+
intro_subtitle: "",
|
| 65 |
+
sidebar_position: "right",
|
| 66 |
+
logo_path: null,
|
| 67 |
+
show_logo: true,
|
| 68 |
+
show_licenses: true,
|
| 69 |
+
logo_position: "center",
|
| 70 |
+
logo_sizing: "resize",
|
| 71 |
+
logo_width: null,
|
| 72 |
+
logo_height: null,
|
| 73 |
+
scroll_background_color: null,
|
| 74 |
+
scroll_title_color: null,
|
| 75 |
+
scroll_name_color: null
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
// Tracks selected license for display
|
| 79 |
+
let selected_license_name: string | null = null;
|
| 80 |
+
|
| 81 |
+
// Toggles license content display
|
| 82 |
+
function show_license(name: string) {
|
| 83 |
+
selected_license_name = selected_license_name === name ? null : name;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// Reactive styles for dimensions and logo
|
| 87 |
+
$: height_style =
|
| 88 |
+
typeof height === "number" ? `${height}px` : height || "500px";
|
| 89 |
+
$: width_style = typeof width === "number" ? `${width}px` : width || "100%";
|
| 90 |
+
$: logo_width_style = effectiveValue.logo_width
|
| 91 |
+
? typeof effectiveValue.logo_width === "number"
|
| 92 |
+
? `${effectiveValue.logo_width}px`
|
| 93 |
+
: effectiveValue.logo_width
|
| 94 |
+
: "auto";
|
| 95 |
+
$: logo_height_style = effectiveValue.logo_height
|
| 96 |
+
? typeof effectiveValue.logo_height === "number"
|
| 97 |
+
? `${effectiveValue.logo_height}px`
|
| 98 |
+
: effectiveValue.logo_height
|
| 99 |
+
: "100px";
|
| 100 |
+
$: logo_panel_height = effectiveValue.logo_height
|
| 101 |
+
? typeof effectiveValue.logo_height === "number"
|
| 102 |
+
? `${effectiveValue.logo_height}px`
|
| 103 |
+
: effectiveValue.logo_height
|
| 104 |
+
: "100px";
|
| 105 |
+
$: object_fit =
|
| 106 |
+
effectiveValue.logo_sizing === "stretch"
|
| 107 |
+
? "fill"
|
| 108 |
+
: effectiveValue.logo_sizing === "crop"
|
| 109 |
+
? "cover"
|
| 110 |
+
: "contain";
|
| 111 |
+
$: logo_justify =
|
| 112 |
+
effectiveValue.logo_position === "center"
|
| 113 |
+
? "center"
|
| 114 |
+
: effectiveValue.logo_position === "left"
|
| 115 |
+
? "flex-start"
|
| 116 |
+
: "flex-end";
|
| 117 |
+
</script>
|
| 118 |
+
|
| 119 |
+
<Block
|
| 120 |
+
{visible}
|
| 121 |
+
{elem_id}
|
| 122 |
+
{elem_classes}
|
| 123 |
+
{container}
|
| 124 |
+
{scale}
|
| 125 |
+
{min_width}
|
| 126 |
+
padding={false}
|
| 127 |
+
>
|
| 128 |
+
<!-- Loading status tracker -->
|
| 129 |
+
<StatusTracker
|
| 130 |
+
autoscroll={gradio.autoscroll}
|
| 131 |
+
i18n={gradio.i18n}
|
| 132 |
+
queue_position={loading_status?.queue_position ?? -1}
|
| 133 |
+
queue_size={loading_status?.queue_size ?? 0}
|
| 134 |
+
status={loading_status?.status ?? "complete"}
|
| 135 |
+
/>
|
| 136 |
+
<slot />
|
| 137 |
+
|
| 138 |
+
<!-- Logo panel -->
|
| 139 |
+
{#key effectiveValue.logo_position}
|
| 140 |
+
<div class="outer-logo-wrapper" style:width={width_style}>
|
| 141 |
+
{#if effectiveValue.show_logo && effectiveValue.logo_path?.url}
|
| 142 |
+
<div
|
| 143 |
+
class="logo-panel"
|
| 144 |
+
style:height={logo_panel_height}
|
| 145 |
+
style:display="flex"
|
| 146 |
+
style:justify-content={logo_justify}
|
| 147 |
+
>
|
| 148 |
+
{#if gradio}
|
| 149 |
+
<Image
|
| 150 |
+
src={effectiveValue.logo_path.url}
|
| 151 |
+
alt="Logo"
|
| 152 |
+
loading="lazy"
|
| 153 |
+
{gradio}
|
| 154 |
+
style="width: {logo_width_style}; height: {logo_height_style}; object-fit: {object_fit};"
|
| 155 |
+
/>
|
| 156 |
+
{:else}
|
| 157 |
+
<img
|
| 158 |
+
src={effectiveValue.logo_path.url}
|
| 159 |
+
alt="Logo"
|
| 160 |
+
style="width: {logo_width_style}; height: {logo_height_style}; object-fit: {object_fit};"
|
| 161 |
+
/>
|
| 162 |
+
{/if}
|
| 163 |
+
</div>
|
| 164 |
+
{/if}
|
| 165 |
+
</div>
|
| 166 |
+
{/key}
|
| 167 |
+
|
| 168 |
+
<!-- Credits and licenses panel -->
|
| 169 |
+
{#key effectiveValue.sidebar_position}
|
| 170 |
+
<div class="outer-credits-wrapper" style:width={width_style}>
|
| 171 |
+
<div
|
| 172 |
+
class="credits-panel-wrapper"
|
| 173 |
+
style:width={width_style}
|
| 174 |
+
style:height={effectiveValue.sidebar_position === "right"
|
| 175 |
+
? height_style
|
| 176 |
+
: undefined}
|
| 177 |
+
>
|
| 178 |
+
{#key { effect: effectiveValue.effect, speed: effectiveValue.speed }}
|
| 179 |
+
<div
|
| 180 |
+
class="main-credits-panel"
|
| 181 |
+
style:height={height_style}
|
| 182 |
+
style:width={effectiveValue.sidebar_position === "right" &&
|
| 183 |
+
effectiveValue.show_licenses
|
| 184 |
+
? "calc(100% - var(--sidebar-width, 400px))"
|
| 185 |
+
: width_style}
|
| 186 |
+
>
|
| 187 |
+
{#if effectiveValue.effect === "scroll"}
|
| 188 |
+
<ScrollEffect
|
| 189 |
+
credits={effectiveValue.credits}
|
| 190 |
+
speed={effectiveValue.speed}
|
| 191 |
+
base_font_size={effectiveValue.base_font_size}
|
| 192 |
+
intro_title={effectiveValue.intro_title}
|
| 193 |
+
intro_subtitle={effectiveValue.intro_subtitle}
|
| 194 |
+
background_color={effectiveValue.scroll_background_color}
|
| 195 |
+
title_color={effectiveValue.scroll_title_color}
|
| 196 |
+
name_color={effectiveValue.scroll_name_color}
|
| 197 |
+
/>
|
| 198 |
+
{:else if effectiveValue.effect === "starwars"}
|
| 199 |
+
<StarWarsEffect
|
| 200 |
+
credits={effectiveValue.credits}
|
| 201 |
+
speed={effectiveValue.speed}
|
| 202 |
+
base_font_size={effectiveValue.base_font_size}
|
| 203 |
+
intro_title={effectiveValue.intro_title}
|
| 204 |
+
intro_subtitle={effectiveValue.intro_subtitle}
|
| 205 |
+
/>
|
| 206 |
+
{:else if effectiveValue.effect === "matrix"}
|
| 207 |
+
<MatrixEffect
|
| 208 |
+
credits={effectiveValue.credits}
|
| 209 |
+
speed={effectiveValue.speed}
|
| 210 |
+
base_font_size={effectiveValue.base_font_size}
|
| 211 |
+
intro_title={effectiveValue.intro_title}
|
| 212 |
+
intro_subtitle={effectiveValue.intro_subtitle}
|
| 213 |
+
/>
|
| 214 |
+
{/if}
|
| 215 |
+
</div>
|
| 216 |
+
{/key}
|
| 217 |
+
{#if effectiveValue.show_licenses && Object.keys(effectiveValue.licenses).length > 0}
|
| 218 |
+
<div class="licenses-sidebar">
|
| 219 |
+
<h3>Licenses</h3>
|
| 220 |
+
<ul>
|
| 221 |
+
{#each Object.entries(effectiveValue.licenses) as [name, content] (name)}
|
| 222 |
+
<li>
|
| 223 |
+
<button
|
| 224 |
+
class:selected={selected_license_name === name}
|
| 225 |
+
on:click={() => show_license(name)}
|
| 226 |
+
type="button"
|
| 227 |
+
>
|
| 228 |
+
{name}
|
| 229 |
+
</button>
|
| 230 |
+
</li>
|
| 231 |
+
{/each}
|
| 232 |
+
</ul>
|
| 233 |
+
{#if selected_license_name}
|
| 234 |
+
<div class="license-display">
|
| 235 |
+
<h4>{selected_license_name}</h4>
|
| 236 |
+
<pre>{effectiveValue.licenses[selected_license_name]}</pre>
|
| 237 |
+
</div>
|
| 238 |
+
{/if}
|
| 239 |
+
</div>
|
| 240 |
+
{/if}
|
| 241 |
+
</div>
|
| 242 |
+
</div>
|
| 243 |
+
{/key}
|
| 244 |
+
</Block>
|
| 245 |
+
|
| 246 |
+
<svelte:head>
|
| 247 |
+
{#if effectiveValue.sidebar_position === "bottom"}
|
| 248 |
+
<!-- Bottom sidebar styles -->
|
| 249 |
+
<style>
|
| 250 |
+
.credits-panel-wrapper {
|
| 251 |
+
flex-direction: column !important;
|
| 252 |
+
--panel-direction: column;
|
| 253 |
+
--sidebar-width: 100%;
|
| 254 |
+
--border-left: none;
|
| 255 |
+
--border-top: 1px solid var(--border-color-primary);
|
| 256 |
+
--sidebar-max-height: 400px;
|
| 257 |
+
}
|
| 258 |
+
.licenses-sidebar {
|
| 259 |
+
width: 100% !important;
|
| 260 |
+
border-left: none !important;
|
| 261 |
+
border-top: 1px solid var(--border-color-primary) !important;
|
| 262 |
+
}
|
| 263 |
+
.main-credits-panel {
|
| 264 |
+
width: 100% !important;
|
| 265 |
+
}
|
| 266 |
+
</style>
|
| 267 |
+
{:else}
|
| 268 |
+
<!-- Right sidebar styles -->
|
| 269 |
+
<style>
|
| 270 |
+
.credits-panel-wrapper { flex-direction: row !important; --panel-direction: row; --sidebar-width: 400px; --border-left: 1px solid var(--border-color-primary); --border-top: none; --sidebar-max-height: {height_style}; }
|
| 271 |
+
.licenses-sidebar { width: var(--sidebar-width, 400px) !important; border-left: 1px solid var(--border-color-primary) !important; border-top: none !important; }
|
| 272 |
+
.main-credits-panel { width: calc(100% - var(--sidebar-width, 400px)) !important; }
|
| 273 |
+
</style>
|
| 274 |
+
{/if}
|
| 275 |
+
</svelte:head>
|
| 276 |
+
|
| 277 |
+
<style>
|
| 278 |
+
/* Remove default block styling */
|
| 279 |
+
:global(.block) {
|
| 280 |
+
border: none !important;
|
| 281 |
+
box-shadow: none !important;
|
| 282 |
+
border-style: none !important;
|
| 283 |
+
}
|
| 284 |
+
/* Logo wrapper */
|
| 285 |
+
.outer-logo-wrapper {
|
| 286 |
+
display: flex;
|
| 287 |
+
flex-direction: column;
|
| 288 |
+
width: 100%;
|
| 289 |
+
border: none;
|
| 290 |
+
}
|
| 291 |
+
/* Credits wrapper */
|
| 292 |
+
.outer-credits-wrapper {
|
| 293 |
+
display: flex;
|
| 294 |
+
flex-direction: column;
|
| 295 |
+
width: 100%;
|
| 296 |
+
border: none;
|
| 297 |
+
}
|
| 298 |
+
/* Logo panel */
|
| 299 |
+
.logo-panel {
|
| 300 |
+
background: var(--background-fill-primary);
|
| 301 |
+
border: none;
|
| 302 |
+
border-bottom: 1px solid var(--border-color-primary);
|
| 303 |
+
display: flex !important;
|
| 304 |
+
align-items: center;
|
| 305 |
+
justify-content: var(--logo-justify, center);
|
| 306 |
+
width: 100%;
|
| 307 |
+
}
|
| 308 |
+
/* Credits and licenses container */
|
| 309 |
+
.credits-panel-wrapper {
|
| 310 |
+
display: flex;
|
| 311 |
+
flex-direction: var(--panel-direction, row);
|
| 312 |
+
min-height: var(--size-full, 500px);
|
| 313 |
+
width: 100%;
|
| 314 |
+
background: var(--background-fill-primary);
|
| 315 |
+
border: 1px solid var(--border-color-primary);
|
| 316 |
+
border-radius: var(--radius-lg);
|
| 317 |
+
overflow: hidden;
|
| 318 |
+
}
|
| 319 |
+
/* Credits display panel */
|
| 320 |
+
.main-credits-panel {
|
| 321 |
+
flex-grow: 1;
|
| 322 |
+
flex-shrink: 1;
|
| 323 |
+
min-width: 200px;
|
| 324 |
+
background: black;
|
| 325 |
+
overflow: hidden;
|
| 326 |
+
position: relative;
|
| 327 |
+
}
|
| 328 |
+
/* Licenses sidebar */
|
| 329 |
+
.licenses-sidebar {
|
| 330 |
+
width: var(--sidebar-width, 400px);
|
| 331 |
+
max-width: 100%;
|
| 332 |
+
max-height: var(--sidebar-max-height, none);
|
| 333 |
+
flex-shrink: 1;
|
| 334 |
+
flex-grow: 0;
|
| 335 |
+
background: var(--background-fill-secondary);
|
| 336 |
+
overflow-y: auto;
|
| 337 |
+
border-left: var(--border-left, 1px solid var(--border-color-primary));
|
| 338 |
+
border-top: var(--border-top, none);
|
| 339 |
+
}
|
| 340 |
+
.licenses-sidebar h3 {
|
| 341 |
+
margin: var(--spacing-lg);
|
| 342 |
+
font-size: var(--text-lg);
|
| 343 |
+
}
|
| 344 |
+
.licenses-sidebar li {
|
| 345 |
+
padding: 0;
|
| 346 |
+
margin: 0;
|
| 347 |
+
cursor: default;
|
| 348 |
+
border-bottom: 1px solid var(--border-color-primary);
|
| 349 |
+
}
|
| 350 |
+
.licenses-sidebar li button {
|
| 351 |
+
background: none;
|
| 352 |
+
border: none;
|
| 353 |
+
font: inherit;
|
| 354 |
+
color: inherit;
|
| 355 |
+
text-align: left;
|
| 356 |
+
width: 100%;
|
| 357 |
+
cursor: pointer;
|
| 358 |
+
padding: var(--spacing-md) var(--spacing-lg);
|
| 359 |
+
transition: background-color 0.2s;
|
| 360 |
+
}
|
| 361 |
+
.licenses-sidebar li button:hover {
|
| 362 |
+
background-color: var(--background-fill-primary);
|
| 363 |
+
}
|
| 364 |
+
.licenses-sidebar li button:focus-visible {
|
| 365 |
+
outline: 2px solid var(--color-accent);
|
| 366 |
+
outline-offset: -2px;
|
| 367 |
+
}
|
| 368 |
+
.licenses-sidebar li button.selected {
|
| 369 |
+
background-color: var(--color-accent);
|
| 370 |
+
color: white;
|
| 371 |
+
font-weight: bold;
|
| 372 |
+
}
|
| 373 |
+
.license-display {
|
| 374 |
+
padding: var(--spacing-lg);
|
| 375 |
+
overflow-y: auto;
|
| 376 |
+
flex-grow: 1;
|
| 377 |
+
border-top: 1px solid var(--border-color-primary);
|
| 378 |
+
background: var(--background-fill-primary);
|
| 379 |
+
}
|
| 380 |
+
.license-display h4 {
|
| 381 |
+
margin-top: 0;
|
| 382 |
+
}
|
| 383 |
+
.license-display pre {
|
| 384 |
+
white-space: pre-wrap;
|
| 385 |
+
word-break: break-word;
|
| 386 |
+
font-size: var(--text-sm);
|
| 387 |
+
color: var(--body-text-color-subdued);
|
| 388 |
+
}
|
| 389 |
+
</style>
|
src/frontend/gradio.config.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
export default {
|
| 2 |
+
plugins: [],
|
| 3 |
+
svelte: {
|
| 4 |
+
preprocess: [],
|
| 5 |
+
},
|
| 6 |
+
build: {
|
| 7 |
+
target: "modules",
|
| 8 |
+
},
|
| 9 |
+
};
|
src/frontend/package-lock.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/frontend/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "gradio_creditspanel",
|
| 3 |
+
"version": "0.7.0",
|
| 4 |
+
"description": "Gradio UI packages",
|
| 5 |
+
"type": "module",
|
| 6 |
+
"author": "",
|
| 7 |
+
"license": "ISC",
|
| 8 |
+
"private": false,
|
| 9 |
+
"main_changeset": true,
|
| 10 |
+
"dependencies": {
|
| 11 |
+
"@gradio/atoms": "0.16.5",
|
| 12 |
+
"@gradio/image": "^0.22.17",
|
| 13 |
+
"@gradio/statustracker": "0.10.18",
|
| 14 |
+
"@gradio/utils": "0.10.2",
|
| 15 |
+
"@gradio/icons": "0.13.1"
|
| 16 |
+
},
|
| 17 |
+
"devDependencies": {
|
| 18 |
+
"@gradio/preview": "0.14.0"
|
| 19 |
+
},
|
| 20 |
+
"exports": {
|
| 21 |
+
"./package.json": "./package.json",
|
| 22 |
+
".": {
|
| 23 |
+
"gradio": "./Index.svelte",
|
| 24 |
+
"svelte": "./dist/Index.svelte",
|
| 25 |
+
"types": "./dist/Index.svelte.d.ts"
|
| 26 |
+
},
|
| 27 |
+
"./example": {
|
| 28 |
+
"gradio": "./Example.svelte",
|
| 29 |
+
"svelte": "./dist/Example.svelte",
|
| 30 |
+
"types": "./dist/Example.svelte.d.ts"
|
| 31 |
+
},
|
| 32 |
+
"./base": {
|
| 33 |
+
"gradio": "./Index.svelte",
|
| 34 |
+
"svelte": "./dist/Index.svelte",
|
| 35 |
+
"types": "./dist/Index.svelte.d.ts"
|
| 36 |
+
}
|
| 37 |
+
},
|
| 38 |
+
"peerDependencies": {
|
| 39 |
+
"svelte": "^4.0.0"
|
| 40 |
+
},
|
| 41 |
+
"repository": {
|
| 42 |
+
"type": "git",
|
| 43 |
+
"url": "git+https://github.com/gradio-app/gradio.git",
|
| 44 |
+
"directory": "js/html"
|
| 45 |
+
}
|
| 46 |
+
}
|
src/frontend/shared/MatrixEffect.svelte
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { onMount, onDestroy } from 'svelte';
|
| 3 |
+
|
| 4 |
+
/**
|
| 5 |
+
* Props for the MatrixEffect component.
|
| 6 |
+
* @typedef {Object} Props
|
| 7 |
+
* @property {Array<{title: string, name: string}>} credits - List of credits with title and name.
|
| 8 |
+
* @property {number} speed - Animation speed in seconds (default: 20).
|
| 9 |
+
* @property {number} base_font_size - Base font size in em (default: 1.0).
|
| 10 |
+
* @property {string | null} intro_title - Optional intro title.
|
| 11 |
+
* @property {string | null} intro_subtitle - Optional intro subtitle.
|
| 12 |
+
*/
|
| 13 |
+
export let credits: Props['credits'];
|
| 14 |
+
export let speed: number = 20;
|
| 15 |
+
export let base_font_size: number = 1.0;
|
| 16 |
+
export let intro_title: string | null = null;
|
| 17 |
+
export let intro_subtitle: string | null = null;
|
| 18 |
+
|
| 19 |
+
// Combines intro and credits for display
|
| 20 |
+
$: display_items = (() => {
|
| 21 |
+
const items = [];
|
| 22 |
+
if (intro_title || intro_subtitle) {
|
| 23 |
+
items.push({
|
| 24 |
+
title: intro_title || '',
|
| 25 |
+
name: intro_subtitle || '',
|
| 26 |
+
is_intro: true
|
| 27 |
+
});
|
| 28 |
+
}
|
| 29 |
+
return [...items, ...credits.map(c => ({ ...c, is_intro: false }))];
|
| 30 |
+
})();
|
| 31 |
+
|
| 32 |
+
// Reactive font size styles
|
| 33 |
+
$: title_style = (is_intro: boolean) => `font-size: ${is_intro ? base_font_size * 1.2 : base_font_size * 0.8}em;`;
|
| 34 |
+
$: name_style = (is_intro: boolean) => `font-size: ${is_intro ? base_font_size * 1.5 : base_font_size}em;`;
|
| 35 |
+
|
| 36 |
+
// Canvas setup for Matrix effect
|
| 37 |
+
let canvas: HTMLCanvasElement;
|
| 38 |
+
let ctx: CanvasRenderingContext2D;
|
| 39 |
+
let contentElement: HTMLElement | null;
|
| 40 |
+
const fontSize = 16;
|
| 41 |
+
const characters = 'アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブヅプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン01';
|
| 42 |
+
let columns: number;
|
| 43 |
+
let drops: number[] = [];
|
| 44 |
+
let animationFrameId: number;
|
| 45 |
+
|
| 46 |
+
// Initialize canvas and drops
|
| 47 |
+
function setup() {
|
| 48 |
+
if (!canvas) return;
|
| 49 |
+
const parent = canvas.parentElement;
|
| 50 |
+
if (parent) {
|
| 51 |
+
canvas.width = parent.clientWidth;
|
| 52 |
+
canvas.height = parent.clientHeight;
|
| 53 |
+
}
|
| 54 |
+
ctx = canvas.getContext('2d')!;
|
| 55 |
+
columns = Math.floor(canvas.width / fontSize);
|
| 56 |
+
drops = Array(columns).fill(1);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
// Draw Matrix falling characters
|
| 60 |
+
function drawMatrix() {
|
| 61 |
+
if (!ctx) return;
|
| 62 |
+
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
| 63 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
| 64 |
+
ctx.fillStyle = '#0F0';
|
| 65 |
+
ctx.font = `${fontSize}px monospace`;
|
| 66 |
+
for (let i = 0; i < drops.length; i++) {
|
| 67 |
+
const text = characters.charAt(Math.floor(Math.random() * characters.length));
|
| 68 |
+
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
|
| 69 |
+
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
| 70 |
+
drops[i] = 0;
|
| 71 |
+
}
|
| 72 |
+
drops[i]++;
|
| 73 |
+
}
|
| 74 |
+
animationFrameId = requestAnimationFrame(drawMatrix);
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
// Reset credits animation
|
| 78 |
+
function resetCreditsAnimation() {
|
| 79 |
+
if (contentElement) {
|
| 80 |
+
contentElement.style.animation = 'none';
|
| 81 |
+
void contentElement.offsetHeight; // Trigger reflow
|
| 82 |
+
contentElement.style.animation = '';
|
| 83 |
+
}
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// Setup canvas and animation on mount
|
| 87 |
+
onMount(() => {
|
| 88 |
+
setup();
|
| 89 |
+
drawMatrix();
|
| 90 |
+
resetCreditsAnimation();
|
| 91 |
+
const resizeObserver = new ResizeObserver(() => {
|
| 92 |
+
cancelAnimationFrame(animationFrameId);
|
| 93 |
+
setup();
|
| 94 |
+
drawMatrix();
|
| 95 |
+
});
|
| 96 |
+
if (canvas.parentElement) {
|
| 97 |
+
resizeObserver.observe(canvas.parentElement);
|
| 98 |
+
}
|
| 99 |
+
return () => {
|
| 100 |
+
cancelAnimationFrame(animationFrameId);
|
| 101 |
+
if (canvas.parentElement) {
|
| 102 |
+
resizeObserver.unobserve(canvas.parentElement);
|
| 103 |
+
}
|
| 104 |
+
};
|
| 105 |
+
});
|
| 106 |
+
|
| 107 |
+
// Reset animation on prop changes
|
| 108 |
+
$: credits, speed, intro_title, intro_subtitle, resetCreditsAnimation();
|
| 109 |
+
|
| 110 |
+
// Cleanup on destroy
|
| 111 |
+
onDestroy(() => {
|
| 112 |
+
contentElement = null;
|
| 113 |
+
});
|
| 114 |
+
</script>
|
| 115 |
+
|
| 116 |
+
<div class="matrix-container">
|
| 117 |
+
<canvas bind:this={canvas}></canvas>
|
| 118 |
+
<div class="credits-scroll-overlay">
|
| 119 |
+
<div class="credits-content" bind:this={contentElement} style="--animation-duration: {speed}s;">
|
| 120 |
+
{#each display_items as item}
|
| 121 |
+
<div class="credit-block" class:intro-block={item.is_intro}>
|
| 122 |
+
<div style={title_style(item.is_intro)} class="title">{item.title}</div>
|
| 123 |
+
{#if item.name}
|
| 124 |
+
<div style={name_style(item.is_intro)} class="name">{item.name}</div>
|
| 125 |
+
{/if}
|
| 126 |
+
</div>
|
| 127 |
+
{/each}
|
| 128 |
+
</div>
|
| 129 |
+
</div>
|
| 130 |
+
</div>
|
| 131 |
+
|
| 132 |
+
<style>
|
| 133 |
+
/* Container for Matrix effect */
|
| 134 |
+
.matrix-container {
|
| 135 |
+
width: 100%;
|
| 136 |
+
height: 100%;
|
| 137 |
+
position: relative;
|
| 138 |
+
overflow: hidden;
|
| 139 |
+
}
|
| 140 |
+
/* Canvas for falling characters */
|
| 141 |
+
canvas {
|
| 142 |
+
display: block;
|
| 143 |
+
position: absolute;
|
| 144 |
+
top: 0;
|
| 145 |
+
left: 0;
|
| 146 |
+
width: 100%;
|
| 147 |
+
height: 100%;
|
| 148 |
+
z-index: 1;
|
| 149 |
+
}
|
| 150 |
+
/* Overlay for scrolling credits */
|
| 151 |
+
.credits-scroll-overlay {
|
| 152 |
+
position: absolute;
|
| 153 |
+
top: 0;
|
| 154 |
+
left: 0;
|
| 155 |
+
width: 100%;
|
| 156 |
+
height: 100%;
|
| 157 |
+
z-index: 2;
|
| 158 |
+
color: #fff;
|
| 159 |
+
font-family: monospace;
|
| 160 |
+
text-align: center;
|
| 161 |
+
-webkit-mask-image: linear-gradient(transparent, black 20%, black 80%, transparent);
|
| 162 |
+
mask-image: linear-gradient(transparent, black 20%, black 80%, transparent);
|
| 163 |
+
}
|
| 164 |
+
/* Scrolling credits container */
|
| 165 |
+
.credits-content {
|
| 166 |
+
position: absolute;
|
| 167 |
+
width: 100%;
|
| 168 |
+
bottom: 0;
|
| 169 |
+
transform: translateY(100%);
|
| 170 |
+
animation: scroll-from-bottom var(--animation-duration) linear infinite;
|
| 171 |
+
}
|
| 172 |
+
@keyframes scroll-from-bottom {
|
| 173 |
+
from { transform: translateY(100%); }
|
| 174 |
+
to { transform: translateY(-100%); }
|
| 175 |
+
}
|
| 176 |
+
/* Intro block spacing */
|
| 177 |
+
.credit-block.intro-block { margin-bottom: 5rem; }
|
| 178 |
+
/* Credit block spacing */
|
| 179 |
+
.credit-block { margin-bottom: 2.5em; }
|
| 180 |
+
/* Title styling */
|
| 181 |
+
.title {
|
| 182 |
+
color: #0F0;
|
| 183 |
+
text-transform: uppercase;
|
| 184 |
+
opacity: 0.8;
|
| 185 |
+
}
|
| 186 |
+
/* Name styling */
|
| 187 |
+
.name {
|
| 188 |
+
font-weight: bold;
|
| 189 |
+
color: #5F5;
|
| 190 |
+
text-shadow: 0 0 5px #0F0;
|
| 191 |
+
}
|
| 192 |
+
</style>
|
src/frontend/shared/ScrollEffect.svelte
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
/**
|
| 3 |
+
* Props for the ScrollEffect component.
|
| 4 |
+
* @typedef {Object} Props
|
| 5 |
+
* @property {Array<{title: string, name: string}>} credits - List of credits with title and name.
|
| 6 |
+
* @property {number} speed - Animation speed in seconds.
|
| 7 |
+
* @property {number} base_font_size - Base font size in rem (default: 1.5).
|
| 8 |
+
* @property {string | null} background_color - Background color (default: black).
|
| 9 |
+
* @property {string | null} title_color - Title text color (default: white).
|
| 10 |
+
* @property {string | null} name_color - Name text color (default: white).
|
| 11 |
+
* @property {string | null} intro_title - Optional intro title.
|
| 12 |
+
* @property {string | null} intro_subtitle - Optional intro subtitle.
|
| 13 |
+
*/
|
| 14 |
+
export let credits: Props['credits'];
|
| 15 |
+
export let speed: number;
|
| 16 |
+
export let base_font_size: number = 1.5;
|
| 17 |
+
export let background_color: string | null = null;
|
| 18 |
+
export let title_color: string | null = null;
|
| 19 |
+
export let name_color: string | null = null;
|
| 20 |
+
export let intro_title: string | null = null;
|
| 21 |
+
export let intro_subtitle: string | null = null;
|
| 22 |
+
|
| 23 |
+
// Flag to trigger animation reset
|
| 24 |
+
let reset = false;
|
| 25 |
+
|
| 26 |
+
// Combine intro and credits for display
|
| 27 |
+
$: display_items = (() => {
|
| 28 |
+
const items = [];
|
| 29 |
+
if (intro_title || intro_subtitle) {
|
| 30 |
+
items.push({
|
| 31 |
+
title: intro_title || '',
|
| 32 |
+
name: intro_subtitle || '',
|
| 33 |
+
is_intro: true
|
| 34 |
+
});
|
| 35 |
+
}
|
| 36 |
+
return [...items, ...credits.map(c => ({ ...c, is_intro: false }))];
|
| 37 |
+
})();
|
| 38 |
+
|
| 39 |
+
// Reactive styles for title and name
|
| 40 |
+
$: title_style = (is_intro: boolean) => `color: ${title_color || 'white'}; font-size: ${is_intro ? base_font_size * 1.5 : base_font_size}rem;`;
|
| 41 |
+
$: name_style = (is_intro: boolean) => `color: ${name_color || 'white'}; font-size: ${is_intro ? base_font_size * 0.9 : base_font_size * 0.8}rem;`;
|
| 42 |
+
|
| 43 |
+
// Reset animation on prop changes
|
| 44 |
+
function resetAnimation() {
|
| 45 |
+
reset = true;
|
| 46 |
+
setTimeout(() => (reset = false), 0);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
// Trigger reset on prop changes
|
| 52 |
+
$: credits, speed, resetAnimation();
|
| 53 |
+
</script>
|
| 54 |
+
|
| 55 |
+
<div class="wrapper" style:--animation-duration="{speed}s" style:background={background_color || 'black'}>
|
| 56 |
+
{#if !reset}
|
| 57 |
+
<div class="credits-container">
|
| 58 |
+
{#each display_items as item}
|
| 59 |
+
<div class="credit" class:intro-block={item.is_intro}>
|
| 60 |
+
<h2 style={title_style(item.is_intro)}>{item.title}</h2>
|
| 61 |
+
{#if item.name}<p style={name_style(item.is_intro)}>{item.name}</p>{/if}
|
| 62 |
+
</div>
|
| 63 |
+
{/each}
|
| 64 |
+
</div>
|
| 65 |
+
{/if}
|
| 66 |
+
</div>
|
| 67 |
+
|
| 68 |
+
<style>
|
| 69 |
+
/* Container for scrolling credits */
|
| 70 |
+
.wrapper {
|
| 71 |
+
width: 100%;
|
| 72 |
+
height: 100%;
|
| 73 |
+
overflow: hidden;
|
| 74 |
+
position: relative;
|
| 75 |
+
font-family: sans-serif;
|
| 76 |
+
}
|
| 77 |
+
/* Intro block styling */
|
| 78 |
+
.credit.intro-block {
|
| 79 |
+
margin-bottom: 5rem;
|
| 80 |
+
text-align: center;
|
| 81 |
+
}
|
| 82 |
+
/* Credits container with scroll animation */
|
| 83 |
+
.credits-container {
|
| 84 |
+
position: absolute;
|
| 85 |
+
bottom: 0;
|
| 86 |
+
transform: translateY(100%);
|
| 87 |
+
width: 100%;
|
| 88 |
+
text-align: center;
|
| 89 |
+
animation: scroll var(--animation-duration) linear infinite;
|
| 90 |
+
}
|
| 91 |
+
/* Individual credit block */
|
| 92 |
+
.credit {
|
| 93 |
+
margin-bottom: 2rem;
|
| 94 |
+
}
|
| 95 |
+
.credit h2 {
|
| 96 |
+
margin: 0.5rem 0;
|
| 97 |
+
font-family: sans-serif;
|
| 98 |
+
}
|
| 99 |
+
.credit p {
|
| 100 |
+
margin: 0.5rem 0;
|
| 101 |
+
font-family: sans-serif;
|
| 102 |
+
}
|
| 103 |
+
/* Scroll animation keyframes */
|
| 104 |
+
@keyframes scroll {
|
| 105 |
+
0% { transform: translateY(100%); }
|
| 106 |
+
100% { transform: translateY(-100%); }
|
| 107 |
+
}
|
| 108 |
+
</style>
|
src/frontend/shared/StarWarsEffect.svelte
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<script lang="ts">
|
| 2 |
+
import { onMount, onDestroy } from 'svelte';
|
| 3 |
+
|
| 4 |
+
/**
|
| 5 |
+
* Props for the StarWarsEffect component.
|
| 6 |
+
* @typedef {Object} Props
|
| 7 |
+
* @property {Array<{title: string, name: string}>} credits - List of credits with title and name.
|
| 8 |
+
* @property {number} speed - Animation speed in seconds (default: 40).
|
| 9 |
+
* @property {number} base_font_size - Base font size in rem (default: 1.5).
|
| 10 |
+
* @property {string | null} background_color - Background color (default: black).
|
| 11 |
+
* @property {string | null} title_color - Title text color (default: #feda4a).
|
| 12 |
+
* @property {string | null} name_color - Name text color (default: #feda4a).
|
| 13 |
+
* @property {string | null} intro_title - Optional intro title.
|
| 14 |
+
* @property {string | null} intro_subtitle - Optional intro subtitle.
|
| 15 |
+
*/
|
| 16 |
+
export let credits: Props['credits'];
|
| 17 |
+
export let speed: number = 40;
|
| 18 |
+
export let base_font_size: number = 1.5;
|
| 19 |
+
export let background_color: string | null = null;
|
| 20 |
+
export let title_color: string | null = null;
|
| 21 |
+
export let name_color: string | null = null;
|
| 22 |
+
export let intro_title: string | null = null;
|
| 23 |
+
export let intro_subtitle: string | null = null;
|
| 24 |
+
|
| 25 |
+
// Reactive styles for title and name
|
| 26 |
+
$: title_style = (is_intro: boolean) => `color: ${title_color || '#feda4a'}; font-size: ${is_intro ? base_font_size * 1.5 : base_font_size}rem !important;`;
|
| 27 |
+
$: name_style = (is_intro: boolean) => `color: ${name_color || '#feda4a'}; font-size: ${is_intro ? base_font_size * 0.9 : base_font_size * 0.7}rem !important;`;
|
| 28 |
+
|
| 29 |
+
// Combine intro and credits for display
|
| 30 |
+
$: display_items = (() => {
|
| 31 |
+
const items = [];
|
| 32 |
+
if (intro_title || intro_subtitle) {
|
| 33 |
+
items.push({
|
| 34 |
+
title: intro_title || '',
|
| 35 |
+
name: intro_subtitle || '',
|
| 36 |
+
is_intro: true
|
| 37 |
+
});
|
| 38 |
+
}
|
| 39 |
+
return [...items, ...credits.map(c => ({ ...c, is_intro: false }))];
|
| 40 |
+
})();
|
| 41 |
+
|
| 42 |
+
// Element for animation reset
|
| 43 |
+
let crawlElement: HTMLElement | null;
|
| 44 |
+
|
| 45 |
+
// Reset animation on prop changes
|
| 46 |
+
function resetAnimation() {
|
| 47 |
+
if (crawlElement) {
|
| 48 |
+
crawlElement.style.animation = 'none';
|
| 49 |
+
void crawlElement.offsetHeight; // Trigger reflow
|
| 50 |
+
crawlElement.style.animation = '';
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
// Initialize animation on mount
|
| 55 |
+
onMount(() => {
|
| 56 |
+
resetAnimation();
|
| 57 |
+
return () => {};
|
| 58 |
+
});
|
| 59 |
+
|
| 60 |
+
// Trigger reset on prop changes
|
| 61 |
+
$: credits, speed, base_font_size, background_color, title_color, name_color, intro_title, intro_subtitle, resetAnimation();
|
| 62 |
+
|
| 63 |
+
// Cleanup on destroy
|
| 64 |
+
onDestroy(() => {
|
| 65 |
+
crawlElement = null;
|
| 66 |
+
});
|
| 67 |
+
|
| 68 |
+
// Generate star shadows for background
|
| 69 |
+
const generate_star_shadows = (count: number, size: string) => {
|
| 70 |
+
let shadows = '';
|
| 71 |
+
for (let i = 0; i < count; i++) {
|
| 72 |
+
shadows += `${Math.random() * 2000}px ${Math.random() * 2000}px ${size} white, `;
|
| 73 |
+
}
|
| 74 |
+
return shadows.slice(0, -2);
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
const small_stars = generate_star_shadows(200, '1px');
|
| 78 |
+
const medium_stars = generate_star_shadows(100, '2px');
|
| 79 |
+
const large_stars = generate_star_shadows(50, '3px');
|
| 80 |
+
</script>
|
| 81 |
+
|
| 82 |
+
<div class="viewport" style:background={background_color || 'black'}>
|
| 83 |
+
<!-- Star layers for background -->
|
| 84 |
+
<div class="stars small" style="box-shadow: {small_stars};"></div>
|
| 85 |
+
<div class="stars medium" style="box-shadow: {medium_stars};"></div>
|
| 86 |
+
<div class="stars large" style="box-shadow: {large_stars};"></div>
|
| 87 |
+
|
| 88 |
+
<!-- Crawling credits -->
|
| 89 |
+
<div class="crawl" bind:this={crawlElement} style="--animation-duration: {speed}s;">
|
| 90 |
+
{#each display_items as item}
|
| 91 |
+
<div class="credit" class:intro-block={item.is_intro}>
|
| 92 |
+
<h2 style={title_style(item.is_intro)}>{item.title}</h2>
|
| 93 |
+
{#if item.name}<p style={name_style(item.is_intro)}>{item.name}</p>{/if}
|
| 94 |
+
</div>
|
| 95 |
+
{/each}
|
| 96 |
+
</div>
|
| 97 |
+
</div>
|
| 98 |
+
|
| 99 |
+
<style>
|
| 100 |
+
/* Container with perspective for 3D effect */
|
| 101 |
+
.viewport {
|
| 102 |
+
width: 100%;
|
| 103 |
+
height: 100%;
|
| 104 |
+
position: relative;
|
| 105 |
+
overflow: hidden;
|
| 106 |
+
perspective: 400px;
|
| 107 |
+
-webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
|
| 108 |
+
mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
|
| 109 |
+
font-family: "Droid Sans", sans-serif;
|
| 110 |
+
font-weight: bold;
|
| 111 |
+
}
|
| 112 |
+
/* Star layers with twinkling animation */
|
| 113 |
+
.stars {
|
| 114 |
+
position: absolute;
|
| 115 |
+
top: 0;
|
| 116 |
+
left: 0;
|
| 117 |
+
width: 1px;
|
| 118 |
+
height: 1px;
|
| 119 |
+
background: transparent;
|
| 120 |
+
z-index: 0;
|
| 121 |
+
animation: twinkle 10s linear infinite;
|
| 122 |
+
}
|
| 123 |
+
.stars.small { animation-duration: 10s; }
|
| 124 |
+
.stars.medium { animation-duration: 15s; }
|
| 125 |
+
.stars.large { animation-duration: 20s; }
|
| 126 |
+
@keyframes twinkle {
|
| 127 |
+
0% { opacity: 0.6; }
|
| 128 |
+
50% { opacity: 1; }
|
| 129 |
+
100% { opacity: 0.6; }
|
| 130 |
+
}
|
| 131 |
+
/* Crawling text container */
|
| 132 |
+
.crawl {
|
| 133 |
+
position: absolute;
|
| 134 |
+
width: 100%;
|
| 135 |
+
bottom: 0;
|
| 136 |
+
transform-origin: 50% 100%;
|
| 137 |
+
animation: crawl-animation var(--animation-duration) linear infinite;
|
| 138 |
+
z-index: 1;
|
| 139 |
+
text-align: center;
|
| 140 |
+
}
|
| 141 |
+
/* Crawl animation with 3D transform */
|
| 142 |
+
@keyframes crawl-animation {
|
| 143 |
+
0% { transform: rotateX(60deg) translateY(100%) translateZ(100px); opacity: 1; }
|
| 144 |
+
100% { transform: rotateX(60deg) translateY(-150%) translateZ(-1200px); opacity: 1; }
|
| 145 |
+
}
|
| 146 |
+
/* Intro block spacing */
|
| 147 |
+
.credit.intro-block { margin-bottom: 5rem; }
|
| 148 |
+
/* Credit block spacing */
|
| 149 |
+
.credit { margin-bottom: 2rem; }
|
| 150 |
+
/* Text styling */
|
| 151 |
+
h2, p {
|
| 152 |
+
margin: 0.5rem 0;
|
| 153 |
+
padding: 0;
|
| 154 |
+
white-space: nowrap;
|
| 155 |
+
}
|
| 156 |
+
</style>
|
src/frontend/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"compilerOptions": {
|
| 3 |
+
"allowJs": true,
|
| 4 |
+
"checkJs": true,
|
| 5 |
+
"esModuleInterop": true,
|
| 6 |
+
"forceConsistentCasingInFileNames": true,
|
| 7 |
+
"resolveJsonModule": true,
|
| 8 |
+
"skipLibCheck": true,
|
| 9 |
+
"sourceMap": true,
|
| 10 |
+
"strict": true,
|
| 11 |
+
"verbatimModuleSyntax": true
|
| 12 |
+
},
|
| 13 |
+
"exclude": ["node_modules", "dist", "./gradio.config.js"]
|
| 14 |
+
}
|
src/package-lock.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "creditspanel",
|
| 3 |
+
"lockfileVersion": 3,
|
| 4 |
+
"requires": true,
|
| 5 |
+
"packages": {}
|
| 6 |
+
}
|
src/pyproject.toml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = [
|
| 3 |
+
"hatchling",
|
| 4 |
+
"hatch-requirements-txt",
|
| 5 |
+
"hatch-fancy-pypi-readme>=22.5.0",
|
| 6 |
+
]
|
| 7 |
+
build-backend = "hatchling.build"
|
| 8 |
+
|
| 9 |
+
[project]
|
| 10 |
+
name = "gradio_creditspanel"
|
| 11 |
+
version = "0.0.1"
|
| 12 |
+
description = "Credits Panel for Gradio UI"
|
| 13 |
+
readme = "README.md"
|
| 14 |
+
license = "apache-2.0"
|
| 15 |
+
requires-python = ">=3.10"
|
| 16 |
+
authors = [{ name = "Eliseu Silva", email = "elismasilva@gmail.com" }]
|
| 17 |
+
keywords = ["gradio-custom-component", "gradio-template-HTML"]
|
| 18 |
+
# Add dependencies here
|
| 19 |
+
dependencies = ["gradio>=4.0,<6.0"]
|
| 20 |
+
classifiers = [
|
| 21 |
+
'Development Status :: 3 - Alpha',
|
| 22 |
+
'Operating System :: OS Independent',
|
| 23 |
+
'Programming Language :: Python :: 3',
|
| 24 |
+
'Programming Language :: Python :: 3 :: Only',
|
| 25 |
+
'Programming Language :: Python :: 3.8',
|
| 26 |
+
'Programming Language :: Python :: 3.9',
|
| 27 |
+
'Programming Language :: Python :: 3.10',
|
| 28 |
+
'Programming Language :: Python :: 3.11',
|
| 29 |
+
'Topic :: Scientific/Engineering',
|
| 30 |
+
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
| 31 |
+
'Topic :: Scientific/Engineering :: Visualization',
|
| 32 |
+
]
|
| 33 |
+
|
| 34 |
+
# The repository and space URLs are optional, but recommended.
|
| 35 |
+
# Adding a repository URL will create a badge in the auto-generated README that links to the repository.
|
| 36 |
+
# Adding a space URL will create a badge in the auto-generated README that links to the space.
|
| 37 |
+
# This will make it easy for people to find your deployed demo or source code when they
|
| 38 |
+
# encounter your project in the wild.
|
| 39 |
+
|
| 40 |
+
# [project.urls]
|
| 41 |
+
# repository = "your github repository"
|
| 42 |
+
# space = "your space url"
|
| 43 |
+
|
| 44 |
+
[project.optional-dependencies]
|
| 45 |
+
dev = ["build", "twine"]
|
| 46 |
+
|
| 47 |
+
[tool.hatch.build]
|
| 48 |
+
artifacts = ["/backend/gradio_creditspanel/templates", "*.pyi", "/\\backend\\gradio_creditspanel\\templates"]
|
| 49 |
+
|
| 50 |
+
[tool.hatch.build.targets.wheel]
|
| 51 |
+
packages = ["/backend/gradio_creditspanel"]
|