Skip to content

Commit

Permalink
Add a settings link to the footer with i18n options & pwa instructi…
Browse files Browse the repository at this point in the history
…ons (#10254)

* changes

* add changeset

* changes

* changes

* restore

* changes

* changes

* changes

* changes

* add changeset

* changes

* changes

* changes

* format

* changes

* changes

* changes

* changes

* add guard

* changes

* more changes

* format frontend

* add changeset

* add more translations

* format

* changes

* spacing

* changes

* format

---------

Co-authored-by: gradio-pr-bot <[email protected]>
  • Loading branch information
abidlabs and gradio-pr-bot authored Dec 30, 2024
1 parent f3bedd4 commit da07707
Show file tree
Hide file tree
Showing 36 changed files with 2,359 additions and 200 deletions.
7 changes: 7 additions & 0 deletions .changeset/orange-bugs-send.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@gradio/client": minor
"@gradio/core": minor
"gradio": minor
---

feat:Add a `settings` link to the footer with i18n options & pwa instructions
1 change: 1 addition & 0 deletions client/js/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export interface Config {
api_prefix?: string;
fill_height?: boolean;
fill_width?: boolean;
pwa?: boolean;
}

// todo: DRY up types
Expand Down
6 changes: 4 additions & 2 deletions gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,7 @@ def __init__(
self.renderables: list[Renderable] = []
self.state_holder: StateHolder
self.custom_mount_path: str | None = None
self.pwa = False

# For analytics_enabled and allow_flagging: (1) first check for
# parameter, (2) check for env variable, (3) default to True/"manual"
Expand Down Expand Up @@ -2171,6 +2172,7 @@ def get_config_file(self) -> BlocksConfigDict:
"fill_height": self.fill_height,
"fill_width": self.fill_width,
"theme_hash": self.theme_hash,
"pwa": self.pwa,
}
config.update(self.default_config.get_config()) # type: ignore
config["connect_heartbeat"] = utils.connect_heartbeat(
Expand Down Expand Up @@ -2450,9 +2452,10 @@ def reverse(text):
if block.key is None:
block.key = f"__{block._id}__"

self.config = self.get_config_file()
self.pwa = utils.get_space() is not None if pwa is None else pwa
self.max_threads = max_threads
self._queue.max_thread_count = max_threads
self.config = self.get_config_file()

self.ssr_mode = (
False
Expand Down Expand Up @@ -2532,7 +2535,6 @@ def reverse(text):
"http" if share_server_address is not None else "https"
)
self.has_launched = True
self.pwa = utils.get_space() is not None if pwa is None else pwa

self.protocol = (
"https"
Expand Down
1 change: 1 addition & 0 deletions gradio/data_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ class BlocksConfigDict(TypedDict):
root: NotRequired[str | None]
username: NotRequired[str | None]
api_prefix: str
pwa: NotRequired[bool]


class MediaStreamChunk(TypedDict):
Expand Down
80 changes: 76 additions & 4 deletions js/core/src/Blocks.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import type { ComponentMeta, Dependency, LayoutNode } from "./types";
import type { UpdateTransaction } from "./init";
import { setupi18n } from "./i18n";
import { ApiDocs, ApiRecorder } from "./api_docs/";
import { ApiDocs, ApiRecorder, Settings } from "./api_docs/";
import type { ThemeMode, Payload } from "./types";
import { Toast } from "@gradio/statustracker";
import type { ToastMessage } from "@gradio/statustracker";
Expand All @@ -18,6 +18,7 @@
import logo from "./images/logo.svg";
import api_logo from "./api_docs/img/api-logo.svg";
import settings_logo from "./api_docs/img/settings-logo.svg";
import { create_components, AsyncFunction } from "./init";
import type {
LogMessage,
Expand Down Expand Up @@ -85,8 +86,10 @@
export let search_params: URLSearchParams;
let api_docs_visible = search_params.get("view") === "api" && show_api;
let settings_visible = search_params.get("view") === "settings";
let api_recorder_visible =
search_params.get("view") === "api-recorder" && show_api;
function set_api_docs_visible(visible: boolean): void {
api_recorder_visible = false;
api_docs_visible = visible;
Expand All @@ -98,6 +101,18 @@
}
history.replaceState(null, "", "?" + params.toString());
}
function set_settings_visible(visible: boolean): void {
let params = new URLSearchParams(window.location.search);
if (visible) {
params.set("view", "settings");
} else {
params.delete("view");
}
history.replaceState(null, "", "?" + params.toString());
settings_visible = !settings_visible;
}
let api_calls: Payload[] = [];
export let render_complete = false;
Expand Down Expand Up @@ -758,8 +773,8 @@
>
{$_("errors.use_via_api")}
<img src={api_logo} alt={$_("common.logo")} />
<div>&nbsp;·</div>
</button>
<div>·</div>
{/if}
<a
href="https://gradio.app"
Expand All @@ -770,6 +785,16 @@
{$_("common.built_with_gradio")}
<img src={logo} alt={$_("common.logo")} />
</a>
<button
on:click={() => {
set_settings_visible(!settings_visible);
}}
class="settings"
>
<div>· &nbsp;</div>
{$_("common.settings")}
<img src={settings_logo} alt={$_("common.settings")} />
</button>
</footer>
{/if}
</div>
Expand Down Expand Up @@ -819,6 +844,30 @@
</div>
{/if}

{#if settings_visible && $_layout && app.config}
<div class="api-docs">
<!-- TODO: fix -->
<!-- svelte-ignore a11y-click-events-have-key-events-->
<!-- svelte-ignore a11y-no-static-element-interactions-->
<div
class="backdrop"
on:click={() => {
set_settings_visible(false);
}}
/>
<div class="api-docs-wrap">
<Settings
on:close={(event) => {
set_settings_visible(false);
}}
pwa_enabled={app.config.pwa}
{root}
{space_id}
/>
</div>
</div>
{/if}

{#if messages}
<Toast {messages} on:close={handle_error_close} />
{/if}
Expand Down Expand Up @@ -849,7 +898,8 @@
margin-left: var(--size-2);
}
.show-api {
.show-api,
.settings {
display: flex;
align-items: center;
}
Expand All @@ -863,12 +913,19 @@
width: var(--size-3);
}
.settings img {
margin-right: var(--size-1);
margin-left: var(--size-1);
width: var(--size-4);
}
.built-with {
display: flex;
align-items: center;
}
.built-with:hover {
.built-with:hover,
.settings:hover {
color: var(--body-text-color);
}
Expand Down Expand Up @@ -923,4 +980,19 @@
bottom: 10px;
z-index: 1000;
}
.show-api {
display: flex;
align-items: center;
}
@media (max-width: 640px) {
.show-api {
display: none;
}
}
.show-api:hover {
color: var(--body-text-color);
}
</style>
183 changes: 183 additions & 0 deletions js/core/src/api_docs/Settings.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<script lang="ts">
/* eslint-disable */
import { onMount } from "svelte";
import SettingsBanner from "./SettingsBanner.svelte";
export let root: string;
export let space_id: string | null;
export let pwa_enabled: boolean | undefined;
import { BaseDropdown as Dropdown } from "@gradio/dropdown";
import { language_choices, changeLocale } from "../i18n";
import { locale, _ } from "svelte-i18n";
import { setupi18n } from "../i18n";
if (root === "") {
root = location.protocol + "//" + location.host + location.pathname;
}
if (!root.endsWith("/")) {
root += "/";
}
function setTheme(theme: "light" | "dark" | "system") {
const url = new URL(window.location.href);
if (theme === "system") {
url.searchParams.delete("__theme");
current_theme = "system";
} else {
url.searchParams.set("__theme", theme);
current_theme = theme;
}
window.location.href = url.toString();
}
onMount(() => {
document.body.style.overflow = "hidden";
if ("parentIFrame" in window) {
window.parentIFrame?.scrollTo(0, 0);
}
const url = new URL(window.location.href);
const theme = url.searchParams.get("__theme");
current_theme = (theme as "light" | "dark" | "system") || "system";
return () => {
document.body.style.overflow = "auto";
};
});
let current_locale: string;
let current_theme: "light" | "dark" | "system" = "system";
locale.subscribe((value) => {
if (value) {
current_locale = value;
}
});
function handleLanguageChange(e: CustomEvent): void {
const new_locale = e.detail;
changeLocale(new_locale);
}
setupi18n();
</script>

<div class="banner-wrap">
<SettingsBanner on:close {root} />
</div>
{#if space_id === null}
<!-- on Spaces, the theme is set in HF settings -->
<div class="banner-wrap">
<h2>{$_("common.display_theme")}</h2>
<p class="padded theme-buttons">
<li
class="theme-button {current_theme === 'light'
? 'current-theme'
: 'inactive-theme'}"
on:click={() => setTheme("light")}
>
<button>☀︎ &nbsp;Light</button>
</li>
<li
class="theme-button {current_theme === 'dark'
? 'current-theme'
: 'inactive-theme'}"
on:click={() => setTheme("dark")}
>
<button>⏾ &nbsp; Dark</button>
</li>
<li
class="theme-button {current_theme === 'system'
? 'current-theme'
: 'inactive-theme'}"
on:click={() => setTheme("system")}
>
<button>🖥︎ &nbsp;System</button>
</li>
</p>
</div>
{/if}
<div class="banner-wrap">
<h2>{$_("common.language")}</h2>
<p class="padded">
<Dropdown
label="Language"
choices={language_choices}
show_label={false}
{root}
value={current_locale}
on:change={handleLanguageChange}
/>
</p>
</div>
<div class="banner-wrap">
<h2>{$_("common.pwa")}</h2>
<p class="padded">
{#if pwa_enabled}
You can install this app as a Progressive Web App on your device. Visit <a
href={root}>{root}</a
> and click the install button in the URL address bar of your browser.
{:else}
Progressive Web App is not enabled for this app. To enable it, start your
Gradio app with <code>launch(pwa=True)</code>.
{/if}
</p>
</div>

<style>
.banner-wrap {
position: relative;
border-bottom: 1px solid var(--border-color-primary);
padding: var(--size-4) var(--size-6);
font-size: var(--text-md);
}
.banner-wrap h2 {
font-size: var(--text-xl);
}
a {
text-decoration: underline;
}
p.padded {
padding: 15px 0px;
}
.theme-buttons {
display: flex;
align-items: center;
}
.theme-buttons > * + * {
margin-left: var(--size-2);
}
.theme-button {
display: flex;
align-items: center;
border: 1px solid var(--border-color-primary);
border-radius: var(--radius-md);
padding: var(--size-2) var(--size-2-5);
line-height: 1;
user-select: none;
text-transform: capitalize;
cursor: pointer;
}
.current-theme {
border: 1px solid var(--body-text-color-subdued);
color: var(--body-text-color);
}
.inactive-theme {
color: var(--body-text-color-subdued);
}
.inactive-theme:hover,
.inactive-theme:focus {
box-shadow: var(--shadow-drop);
color: var(--body-text-color);
}
.theme-button button {
all: unset;
cursor: pointer;
}
</style>
Loading

0 comments on commit da07707

Please sign in to comment.