mirror of
https://github.com/gradio-app/gradio.git
synced 2025-02-17 11:29:58 +08:00
Render each app in the PR's spaces preview in a separate page (#6657)
* Use template response * minor fix * Return type hint * add changeset * Remove return types * response_class=None * Use relative path * SPA * remove pydantic pin * Revert * delete changeset * Overflow hidden on body * text gray * Collapsible sidebar * max-height * Use search params * document.location.search --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
parent
30c9fbb5c7
commit
1086542f17
@ -4,12 +4,30 @@ import os
|
||||
import sys
|
||||
import copy
|
||||
import pathlib
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.templating import Jinja2Templates
|
||||
import uvicorn
|
||||
from gradio.utils import get_space
|
||||
|
||||
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
|
||||
|
||||
demo_dir = pathlib.Path(__file__).parent / "demos"
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
names = sorted(os.listdir("./demos"))
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def index(request: Request):
|
||||
names = [[p[0], p[2]] for p in all_demos]
|
||||
return templates.TemplateResponse("index.html", {"request": request, "names": names,
|
||||
"initial_demo": names[0][0], "is_space": get_space()})
|
||||
|
||||
|
||||
all_demos = []
|
||||
demo_module = None
|
||||
for p in sorted(os.listdir("./demos")):
|
||||
@ -20,16 +38,15 @@ for p in sorted(os.listdir("./demos")):
|
||||
demo_module = importlib.import_module(f"run")
|
||||
else:
|
||||
demo_module = importlib.reload(demo_module)
|
||||
all_demos.append((p, demo_module.demo))
|
||||
all_demos.append((p, demo_module.demo.queue(), False))
|
||||
except Exception as e:
|
||||
p = p + " ❌"
|
||||
with gr.Blocks() as demo:
|
||||
gr.Markdown(f"Error loading demo: {e}")
|
||||
all_demos.append((p, demo))
|
||||
all_demos.append((p, demo, True))
|
||||
|
||||
with gr.Blocks() as mega_demo:
|
||||
for demo_name, demo in all_demos:
|
||||
with gr.Tab(demo_name):
|
||||
demo.render()
|
||||
for demo_name, demo, _ in all_demos:
|
||||
app = gr.mount_gradio_app(app, demo, f"/demo/{demo_name}")
|
||||
|
||||
mega_demo.queue().launch()
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(app, port=7860, host="0.0.0.0")
|
||||
|
118
demo/all_demos/templates/index.html
Normal file
118
demo/all_demos/templates/index.html
Normal file
@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{%if is_space %}
|
||||
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
|
||||
{% endif %}
|
||||
<style>
|
||||
/* Reset some default styles */
|
||||
body, h1, h2, h3, p, ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
max-height: calc(100vh - 50px);
|
||||
width: 300px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
font-size: 0.875rem; /* 14px */
|
||||
line-height: 1.25rem; /* 20px */
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
display: block;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
color: rgb(107 114 128);
|
||||
}
|
||||
|
||||
.sidebar a:hover {
|
||||
color: black;
|
||||
transform: translateX(1px);
|
||||
}
|
||||
|
||||
/* Apply a different style to the selected item in the sidebar */
|
||||
.sidebar a.active {
|
||||
background-color: rgb(251 146 60);
|
||||
color: white;
|
||||
border-radius: 0.75rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Styling for the close button */
|
||||
.close-btn {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
background-color: white;
|
||||
font-size: xx-large;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Styling for the content */
|
||||
.content {
|
||||
margin-left: 300px;
|
||||
padding: 20px;
|
||||
display: block;
|
||||
height: 100vh;
|
||||
transition: margin-left 0.3s ease;
|
||||
}
|
||||
|
||||
.content.collapsed {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* Make the iframe responsive */
|
||||
.content iframe {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
/* Adjust styles for smaller screens */
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script src="//unpkg.com/alpinejs" defer></script>
|
||||
</head>
|
||||
<body x-data="{ current_demo: '{{ initial_demo }}', is_collapsed: false }">
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<div>
|
||||
<button @click="is_collapsed = !is_collapsed" class="close-btn">
|
||||
<a x-text="is_collapsed ? '➡️' : '⬅️'"></a>
|
||||
</button>
|
||||
</div>
|
||||
<div :class="{ 'sidebar': true, 'collapsed': is_collapsed }" style="margin-top: 50px;">
|
||||
{% for name in names %}
|
||||
<a @click="current_demo = '{{ name[0] }}'" :class="current_demo == '{{ name[0] }}' ? 'active' : ''">{{ name[0] }} {% if name[1] %}❌{% endif %}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="{ 'content': true, 'collapsed': is_collapsed }">
|
||||
<iframe :src="`/demo/${current_demo}${document.location.search}`"></iframe>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -72,7 +72,5 @@ if __name__ == "__main__":
|
||||
torch==1.12.1
|
||||
altair
|
||||
vega_datasets
|
||||
pydantic==2.1.1
|
||||
pydantic_core==2.4.0
|
||||
"""
|
||||
open(reqs_file_path, "w").write(textwrap.dedent(requirements))
|
||||
|
Loading…
Reference in New Issue
Block a user