mirror of
https://github.com/gradio-app/gradio.git
synced 2025-03-07 11:46:51 +08:00
Refactor full screen logic to be reusable (#10098)
This commit is contained in:
parent
3a6151e942
commit
9a6ce6f6b0
10
.changeset/kind-laws-heal.md
Normal file
10
.changeset/kind-laws-heal.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
"@gradio/annotatedimage": minor
|
||||
"@gradio/atoms": minor
|
||||
"@gradio/chatbot": minor
|
||||
"@gradio/gallery": minor
|
||||
"@gradio/image": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:Refactor full screen logic to be reusable
|
@ -6,8 +6,8 @@
|
||||
Block,
|
||||
BlockLabel,
|
||||
Empty,
|
||||
IconButton,
|
||||
IconButtonWrapper
|
||||
IconButtonWrapper,
|
||||
FullscreenButton
|
||||
} from "@gradio/atoms";
|
||||
import { Image, Maximize, Minimize } from "@gradio/icons";
|
||||
import { StatusTracker } from "@gradio/statustracker";
|
||||
@ -47,22 +47,8 @@
|
||||
export let loading_status: LoadingStatus;
|
||||
export let show_fullscreen_button = true;
|
||||
|
||||
let is_full_screen = false;
|
||||
let image_container: HTMLElement;
|
||||
|
||||
onMount(() => {
|
||||
document.addEventListener("fullscreenchange", () => {
|
||||
is_full_screen = !!document.fullscreenElement;
|
||||
});
|
||||
});
|
||||
|
||||
const toggle_full_screen = async (): Promise<void> => {
|
||||
if (!is_full_screen) {
|
||||
await image_container.requestFullscreen();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
}
|
||||
};
|
||||
let is_full_screen = false;
|
||||
|
||||
// `value` can be updated before the Promises from `resolve_wasm_src` are resolved.
|
||||
// In such a case, the resolved values for the old `value` have to be discarded,
|
||||
@ -166,19 +152,10 @@
|
||||
{:else}
|
||||
<div class="image-container" bind:this={image_container}>
|
||||
<IconButtonWrapper>
|
||||
{#if !is_full_screen && show_fullscreen_button}
|
||||
<IconButton
|
||||
Icon={Maximize}
|
||||
label="View in full screen"
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if is_full_screen}
|
||||
<IconButton
|
||||
Icon={Minimize}
|
||||
label="Exit full screen"
|
||||
on:click={toggle_full_screen}
|
||||
{#if show_fullscreen_button}
|
||||
<FullscreenButton
|
||||
container={image_container}
|
||||
on:fullscreenchange={(e) => (is_full_screen = e.detail)}
|
||||
/>
|
||||
{/if}
|
||||
</IconButtonWrapper>
|
||||
|
46
js/atoms/src/FullscreenButton.svelte
Normal file
46
js/atoms/src/FullscreenButton.svelte
Normal file
@ -0,0 +1,46 @@
|
||||
<script lang="ts">
|
||||
import { onMount, createEventDispatcher } from "svelte";
|
||||
import { IconButton } from "@gradio/atoms";
|
||||
import { Maximize, Minimize } from "@gradio/icons";
|
||||
|
||||
export let container: HTMLElement | undefined = undefined;
|
||||
const dispatch = createEventDispatcher<{
|
||||
fullscreenchange: boolean;
|
||||
}>();
|
||||
|
||||
let is_full_screen = false;
|
||||
|
||||
onMount(() => {
|
||||
document.addEventListener("fullscreenchange", () => {
|
||||
is_full_screen = !!document.fullscreenElement;
|
||||
dispatch("fullscreenchange", is_full_screen);
|
||||
});
|
||||
});
|
||||
|
||||
const toggle_full_screen = async (): Promise<void> => {
|
||||
if (!container) return;
|
||||
|
||||
if (!is_full_screen) {
|
||||
await container.requestFullscreen();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
is_full_screen = !is_full_screen;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if !is_full_screen}
|
||||
<IconButton
|
||||
Icon={Maximize}
|
||||
label="View in full screen"
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if is_full_screen}
|
||||
<IconButton
|
||||
Icon={Minimize}
|
||||
label="Exit full screen"
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
@ -9,5 +9,6 @@ export { default as UploadText } from "./UploadText.svelte";
|
||||
export { default as Toolbar } from "./Toolbar.svelte";
|
||||
export { default as SelectSource } from "./SelectSource.svelte";
|
||||
export { default as IconButtonWrapper } from "./IconButtonWrapper.svelte";
|
||||
export { default as FullscreenButton } from "./FullscreenButton.svelte";
|
||||
|
||||
export const BLOCK_KEY = {};
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
import { dequal } from "dequal/lite";
|
||||
import {
|
||||
afterUpdate,
|
||||
createEventDispatcher,
|
||||
type SvelteComponent,
|
||||
type ComponentType,
|
||||
@ -24,13 +23,7 @@
|
||||
} from "svelte";
|
||||
import { Image } from "@gradio/image/shared";
|
||||
|
||||
import {
|
||||
Clear,
|
||||
Trash,
|
||||
Community,
|
||||
ScrollDownArrow,
|
||||
Download
|
||||
} from "@gradio/icons";
|
||||
import { Trash, Community, ScrollDownArrow } from "@gradio/icons";
|
||||
import { IconButtonWrapper, IconButton } from "@gradio/atoms";
|
||||
import type { SelectData, LikeData } from "@gradio/utils";
|
||||
import type { ExampleMessage } from "../types";
|
||||
@ -173,24 +166,6 @@
|
||||
};
|
||||
});
|
||||
|
||||
let image_preview_source: string;
|
||||
let image_preview_source_alt: string;
|
||||
let is_image_preview_open = false;
|
||||
|
||||
afterUpdate(() => {
|
||||
if (!div) return;
|
||||
div.querySelectorAll("img").forEach((n) => {
|
||||
n.addEventListener("click", (e) => {
|
||||
const target = e.target as HTMLImageElement;
|
||||
if (target) {
|
||||
image_preview_source = target.src;
|
||||
image_preview_source_alt = target.alt;
|
||||
is_image_preview_open = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$: {
|
||||
if (!dequal(value, old_value)) {
|
||||
old_value = value;
|
||||
@ -300,26 +275,6 @@
|
||||
{@const role = messages[0].role === "user" ? "user" : "bot"}
|
||||
{@const avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
||||
{@const opposite_avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
||||
{#if is_image_preview_open}
|
||||
<div class="image-preview">
|
||||
<img src={image_preview_source} alt={image_preview_source_alt} />
|
||||
<IconButtonWrapper>
|
||||
<IconButton
|
||||
Icon={Clear}
|
||||
on:click={() => (is_image_preview_open = false)}
|
||||
label={"Clear"}
|
||||
/>
|
||||
{#if allow_file_downloads}
|
||||
<DownloadLink
|
||||
href={image_preview_source}
|
||||
download={image_preview_source_alt || "image"}
|
||||
>
|
||||
<IconButton Icon={Download} label={"Download"} />
|
||||
</DownloadLink>
|
||||
{/if}
|
||||
</IconButtonWrapper>
|
||||
</div>
|
||||
{/if}
|
||||
<Message
|
||||
{messages}
|
||||
{opposite_avatar_img}
|
||||
@ -641,20 +596,6 @@
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: var(--background-fill-secondary);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.options {
|
||||
margin-left: auto;
|
||||
padding: var(--spacing-xxl);
|
||||
|
@ -1,5 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { BlockLabel, Empty, ShareButton } from "@gradio/atoms";
|
||||
import {
|
||||
BlockLabel,
|
||||
Empty,
|
||||
ShareButton,
|
||||
IconButton,
|
||||
IconButtonWrapper,
|
||||
FullscreenButton
|
||||
} from "@gradio/atoms";
|
||||
import { ModifyUpload } from "@gradio/upload";
|
||||
import type { SelectData } from "@gradio/utils";
|
||||
import { Image } from "@gradio/image/shared";
|
||||
@ -19,7 +26,6 @@
|
||||
} from "@gradio/icons";
|
||||
import { FileData } from "@gradio/client";
|
||||
import { format_gallery_for_sharing } from "./utils";
|
||||
import { IconButton, IconButtonWrapper } from "@gradio/atoms";
|
||||
import type { I18nFormatter } from "@gradio/utils";
|
||||
|
||||
type GalleryData = GalleryImage | GalleryVideo;
|
||||
@ -44,7 +50,7 @@
|
||||
export let show_fullscreen_button = true;
|
||||
|
||||
let is_full_screen = false;
|
||||
let gallery_container: HTMLElement;
|
||||
let image_container: HTMLElement;
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
change: undefined;
|
||||
@ -221,14 +227,6 @@
|
||||
is_full_screen = !!document.fullscreenElement;
|
||||
});
|
||||
});
|
||||
|
||||
const toggle_full_screen = async (): Promise<void> => {
|
||||
if (!is_full_screen) {
|
||||
await gallery_container.requestFullscreen();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerHeight={window_height} />
|
||||
@ -239,7 +237,7 @@
|
||||
{#if value == null || resolved_value == null || resolved_value.length === 0}
|
||||
<Empty unpadded_box={true} size="large"><ImageIcon /></Empty>
|
||||
{:else}
|
||||
<div class="gallery-container" bind:this={gallery_container}>
|
||||
<div class="gallery-container" bind:this={image_container}>
|
||||
{#if selected_media && allow_preview}
|
||||
<button
|
||||
on:keydown={on_keydown}
|
||||
@ -267,23 +265,10 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if show_fullscreen_button && !is_full_screen}
|
||||
<IconButton
|
||||
Icon={is_full_screen ? Minimize : Maximize}
|
||||
label={is_full_screen
|
||||
? "Exit full screen"
|
||||
: "View in full screen"}
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{#if show_fullscreen_button}
|
||||
<FullscreenButton container={image_container} />
|
||||
{/if}
|
||||
|
||||
{#if show_fullscreen_button && is_full_screen}
|
||||
<IconButton
|
||||
Icon={Minimize}
|
||||
label="Exit full screen"
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
||||
{#if show_share_button}
|
||||
<div class="icon-button">
|
||||
<ShareButton
|
||||
|
@ -7,17 +7,16 @@
|
||||
Empty,
|
||||
IconButton,
|
||||
ShareButton,
|
||||
IconButtonWrapper
|
||||
IconButtonWrapper,
|
||||
FullscreenButton
|
||||
} from "@gradio/atoms";
|
||||
import { Download } from "@gradio/icons";
|
||||
import { Download, Image as ImageIcon } from "@gradio/icons";
|
||||
import { get_coordinates_of_clicked_image } from "./utils";
|
||||
import Image from "./Image.svelte";
|
||||
import { Image } from "@gradio/image/shared";
|
||||
import { DownloadLink } from "@gradio/wasm/svelte";
|
||||
import { Maximize, Minimize } from "@gradio/icons";
|
||||
|
||||
import { Image as ImageIcon } from "@gradio/icons";
|
||||
import { type FileData } from "@gradio/client";
|
||||
import type { I18nFormatter } from "@gradio/utils";
|
||||
import type { FileData } from "@gradio/client";
|
||||
|
||||
export let value: null | FileData;
|
||||
export let label: string | undefined = undefined;
|
||||
@ -40,23 +39,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
let is_full_screen = false;
|
||||
let image_container: HTMLElement;
|
||||
|
||||
onMount(() => {
|
||||
document.addEventListener("fullscreenchange", () => {
|
||||
is_full_screen = !!document.fullscreenElement;
|
||||
});
|
||||
});
|
||||
|
||||
const toggle_full_screen = async (): Promise<void> => {
|
||||
if (!is_full_screen) {
|
||||
await image_container.requestFullscreen();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
is_full_screen = !is_full_screen;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<BlockLabel
|
||||
@ -69,20 +52,8 @@
|
||||
{:else}
|
||||
<div class="image-container" bind:this={image_container}>
|
||||
<IconButtonWrapper>
|
||||
{#if !is_full_screen && show_fullscreen_button}
|
||||
<IconButton
|
||||
Icon={Maximize}
|
||||
label={is_full_screen ? "Exit full screen" : "View in full screen"}
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if is_full_screen && show_fullscreen_button}
|
||||
<IconButton
|
||||
Icon={Minimize}
|
||||
label={is_full_screen ? "Exit full screen" : "View in full screen"}
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{#if show_fullscreen_button}
|
||||
<FullscreenButton container={image_container} />
|
||||
{/if}
|
||||
|
||||
{#if show_download_button}
|
||||
|
@ -1,7 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
import { BlockLabel, IconButtonWrapper, IconButton } from "@gradio/atoms";
|
||||
import { Clear, Image as ImageIcon, Maximize, Minimize } from "@gradio/icons";
|
||||
import { Clear, Image as ImageIcon } from "@gradio/icons";
|
||||
import { FullscreenButton } from "@gradio/atoms";
|
||||
import {
|
||||
type SelectData,
|
||||
type I18nFormatter,
|
||||
@ -122,17 +123,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let is_full_screen = false;
|
||||
let image_container: HTMLElement;
|
||||
|
||||
const toggle_full_screen = async (): Promise<void> => {
|
||||
if (!is_full_screen) {
|
||||
await image_container.requestFullscreen();
|
||||
} else {
|
||||
await document.exitFullscreen();
|
||||
is_full_screen = !is_full_screen;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<BlockLabel {show_label} Icon={ImageIcon} label={label || "Image"} />
|
||||
@ -140,19 +131,8 @@
|
||||
<div data-testid="image" class="image-container" bind:this={image_container}>
|
||||
<IconButtonWrapper>
|
||||
{#if value?.url && !active_streaming}
|
||||
{#if !is_full_screen && show_fullscreen_button}
|
||||
<IconButton
|
||||
Icon={Maximize}
|
||||
label={is_full_screen ? "Exit full screen" : "View in full screen"}
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{/if}
|
||||
{#if is_full_screen && show_fullscreen_button}
|
||||
<IconButton
|
||||
Icon={Minimize}
|
||||
label={is_full_screen ? "Exit full screen" : "View in full screen"}
|
||||
on:click={toggle_full_screen}
|
||||
/>
|
||||
{#if show_fullscreen_button}
|
||||
<FullscreenButton container={image_container} />
|
||||
{/if}
|
||||
<IconButton
|
||||
Icon={Clear}
|
||||
|
Loading…
Reference in New Issue
Block a user