Make login page UI consistent (#2684)

* changes

* changes

* changes

* capitalize login
This commit is contained in:
aliabid94 2022-11-21 12:01:57 -06:00 committed by GitHub
parent 70227354e6
commit 084b2b832e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 70 deletions

View File

@ -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:

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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) => {