mirror of
https://github.com/gradio-app/gradio.git
synced 2025-03-07 11:46:51 +08:00
Make login page UI consistent (#2684)
* changes * changes * changes * capitalize login
This commit is contained in:
parent
70227354e6
commit
084b2b832e
@ -6,6 +6,10 @@
|
||||
|
||||
New API Docs page with in-browser playground and updated aesthetics. [@gary149](https://github.com/gary149) in [PR 2652](https://github.com/gradio-app/gradio/pull/2652)
|
||||
|
||||
### Revamped Login page
|
||||
|
||||
Previously our login page had its own CSS, had no dark mode, and had an ugly json message on the wrong credentials. Made the page more aesthetically consistent, added dark mode support, and a nicer error message. [@aliabid94](https://github.com/aliabid94) in [PR 2684](https://github.com/gradio-app/gradio/pull/2684)
|
||||
|
||||
### Accessing the Requests Object Directly
|
||||
|
||||
You can now access the Request object directly in your Python function by [@abidlabs](https://github.com/abidlabs) in [PR 2641](https://github.com/gradio-app/gradio/pull/2641). This means that you can access request headers, the client IP address, and so on. In order to use it, add a parameter to your function and set its type hint to be `gr.Request`. Here's a simple example:
|
||||
|
@ -39,8 +39,8 @@
|
||||
export let autoscroll: boolean = false;
|
||||
export let show_api: boolean = true;
|
||||
export let control_page_title = false;
|
||||
export let app_mode: boolean;
|
||||
|
||||
let app_mode = window.__gradio_mode__ === "app";
|
||||
let loading_status = create_loading_status_store();
|
||||
|
||||
$: app_state.update((s) => ({ ...s, autoscroll }));
|
||||
@ -389,54 +389,6 @@
|
||||
set_prop(instance_map[id], "pending", pending_status === "pending");
|
||||
}
|
||||
}
|
||||
|
||||
function handle_darkmode() {
|
||||
let url = new URL(window.location.toString());
|
||||
|
||||
const color_mode: "light" | "dark" | "system" | null = url.searchParams.get(
|
||||
"__theme"
|
||||
) as "light" | "dark" | "system" | null;
|
||||
|
||||
if (color_mode !== null) {
|
||||
if (color_mode === "dark") {
|
||||
darkmode();
|
||||
} else if (color_mode === "system") {
|
||||
use_system_theme();
|
||||
}
|
||||
// light is default, so we don't need to do anything else
|
||||
} else if (url.searchParams.get("__dark-theme") === "true") {
|
||||
darkmode();
|
||||
} else {
|
||||
use_system_theme();
|
||||
}
|
||||
}
|
||||
|
||||
function use_system_theme() {
|
||||
update_scheme();
|
||||
window
|
||||
?.matchMedia("(prefers-color-scheme: dark)")
|
||||
?.addEventListener("change", update_scheme);
|
||||
|
||||
function update_scheme() {
|
||||
const is_dark =
|
||||
window?.matchMedia?.("(prefers-color-scheme: dark)").matches ?? null;
|
||||
|
||||
if (is_dark) {
|
||||
darkmode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function darkmode() {
|
||||
target.classList.add("dark");
|
||||
if (app_mode) {
|
||||
document.body.style.backgroundColor = "rgb(11, 15, 25)"; // bg-gray-950 for scrolling outside the body
|
||||
}
|
||||
}
|
||||
|
||||
if (window.__gradio_mode__ !== "website") {
|
||||
handle_darkmode();
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -1,29 +1,72 @@
|
||||
<script lang="ts">
|
||||
import { Component as Form } from "./components/Form";
|
||||
import { Component as Textbox } from "./components/Textbox";
|
||||
export let root: string;
|
||||
export let id: number;
|
||||
export let auth_message: string | null;
|
||||
export let app_mode: boolean;
|
||||
|
||||
window.__gradio_loader__[id].$set({ status: "complete" });
|
||||
let username = "";
|
||||
let password = "";
|
||||
let incorrect_credentials = false;
|
||||
|
||||
const submit = async () => {
|
||||
const formData = new FormData();
|
||||
formData.append("username", username);
|
||||
formData.append("password", password);
|
||||
|
||||
let response = await fetch(root + "login", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
if (response.status === 400) {
|
||||
incorrect_credentials = true;
|
||||
username = "";
|
||||
password = "";
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="login container mt-8">
|
||||
<form
|
||||
class="mx-auto p-4 bg-gray-50 shadow-md w-1/2"
|
||||
id="login"
|
||||
method="POST"
|
||||
action={root + "login"}
|
||||
>
|
||||
<h2 class="text-2xl font-semibold my-2">login</h2>
|
||||
<div
|
||||
class="dark:bg-gray-950 w-full flex flex-col items-center justify-center"
|
||||
class:min-h-screen={app_mode}
|
||||
>
|
||||
<div class="gr-panel !p-8">
|
||||
<h2 class="text-2xl font-semibold mb-6">Login</h2>
|
||||
{#if auth_message}
|
||||
<p class="my-4">{auth_message}</p>
|
||||
{/if}
|
||||
<label class="block uppercase mt-4" for="username">username</label>
|
||||
<input class="p-2 block" type="text" name="username" />
|
||||
<label class="block uppercase mt-4" for="password">password</label>
|
||||
<input class="p-2 block" type="password" name="password" />
|
||||
<input
|
||||
type="submit"
|
||||
class="block bg-amber-500 hover:bg-amber-400 dark:hover:bg-amber-600 transition px-4 py-2 rounded text-white font-semibold cursor-pointer mt-4"
|
||||
/>
|
||||
</form>
|
||||
{#if incorrect_credentials}
|
||||
<p class="my-4 text-red-600 font-semibold">Incorrect Credentials</p>
|
||||
{/if}
|
||||
<Form>
|
||||
<Textbox
|
||||
label="username"
|
||||
lines={1}
|
||||
show_label={true}
|
||||
max_lines={1}
|
||||
mode="dynamic"
|
||||
on:submit={submit}
|
||||
bind:value={username}
|
||||
/>
|
||||
<Textbox
|
||||
label="password"
|
||||
lines={1}
|
||||
show_label={true}
|
||||
max_lines={1}
|
||||
mode="dynamic"
|
||||
type="password"
|
||||
on:submit={submit}
|
||||
bind:value={password}
|
||||
/>
|
||||
</Form>
|
||||
|
||||
<button
|
||||
class="gr-button gr-button-lg gr-button-primary w-full mt-4"
|
||||
on:click={submit}>Login</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
export let style: Styles = {};
|
||||
|
||||
export let loading_status: LoadingStatus;
|
||||
export let loading_status: LoadingStatus | undefined = undefined;
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
</script>
|
||||
@ -29,7 +29,9 @@
|
||||
{elem_id}
|
||||
disable={typeof style.container === "boolean" && !style.container}
|
||||
>
|
||||
<StatusTracker {...loading_status} />
|
||||
{#if loading_status}
|
||||
<StatusTracker {...loading_status} />
|
||||
{/if}
|
||||
|
||||
<TextBox
|
||||
bind:value
|
||||
|
@ -38,6 +38,7 @@ interface Config {
|
||||
}
|
||||
|
||||
let app_id: string | null = null;
|
||||
let app_mode = window.__gradio_mode__ === "app";
|
||||
|
||||
async function reload_check(root: string) {
|
||||
const result = await (await fetch(root + "app_id")).text();
|
||||
@ -152,7 +153,8 @@ function mount_app(
|
||||
props: {
|
||||
auth_message: config.auth_message,
|
||||
root: config.root,
|
||||
id
|
||||
id,
|
||||
app_mode
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -167,7 +169,13 @@ function mount_app(
|
||||
new Blocks({
|
||||
target: wrapper,
|
||||
//@ts-ignore
|
||||
props: { ...config, target: wrapper, id, autoscroll: autoscroll }
|
||||
props: {
|
||||
...config,
|
||||
target: wrapper,
|
||||
id,
|
||||
autoscroll: autoscroll,
|
||||
app_mode
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -214,6 +222,9 @@ function create_custom_element() {
|
||||
});
|
||||
|
||||
this.root.append(this.wrapper);
|
||||
if (window.__gradio_mode__ !== "website") {
|
||||
handle_darkmode(this.wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
@ -272,6 +283,9 @@ function create_custom_element() {
|
||||
async function unscoped_mount() {
|
||||
const target = document.querySelector("#root")! as HTMLDivElement;
|
||||
target.classList.add("gradio-container");
|
||||
if (window.__gradio_mode__ !== "website") {
|
||||
handle_darkmode(target);
|
||||
}
|
||||
|
||||
window.__gradio_loader__[0] = new Loader({
|
||||
target: target,
|
||||
@ -287,6 +301,50 @@ async function unscoped_mount() {
|
||||
mount_app({ ...config, control_page_title: true }, false, target, 0);
|
||||
}
|
||||
|
||||
function handle_darkmode(target: HTMLDivElement) {
|
||||
let url = new URL(window.location.toString());
|
||||
|
||||
const color_mode: "light" | "dark" | "system" | null = url.searchParams.get(
|
||||
"__theme"
|
||||
) as "light" | "dark" | "system" | null;
|
||||
|
||||
if (color_mode !== null) {
|
||||
if (color_mode === "dark") {
|
||||
darkmode(target);
|
||||
} else if (color_mode === "system") {
|
||||
use_system_theme(target);
|
||||
}
|
||||
// light is default, so we don't need to do anything else
|
||||
} else if (url.searchParams.get("__dark-theme") === "true") {
|
||||
darkmode(target);
|
||||
} else {
|
||||
use_system_theme(target);
|
||||
}
|
||||
}
|
||||
|
||||
function use_system_theme(target: HTMLDivElement) {
|
||||
update_scheme();
|
||||
window
|
||||
?.matchMedia("(prefers-color-scheme: dark)")
|
||||
?.addEventListener("change", update_scheme);
|
||||
|
||||
function update_scheme() {
|
||||
const is_dark =
|
||||
window?.matchMedia?.("(prefers-color-scheme: dark)").matches ?? null;
|
||||
|
||||
if (is_dark) {
|
||||
darkmode(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function darkmode(target: HTMLDivElement) {
|
||||
target.classList.add("dark");
|
||||
if (app_mode) {
|
||||
document.body.style.backgroundColor = "rgb(11, 15, 25)"; // bg-gray-950 for scrolling outside the body
|
||||
}
|
||||
}
|
||||
|
||||
// dev mode or if inside an iframe
|
||||
if (BUILD_MODE === "dev" || window.location !== window.parent.location) {
|
||||
window.scoped_css_attach = (link) => {
|
||||
|
Loading…
Reference in New Issue
Block a user