@redot-src/glare 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -8
- package/dist/core/animation.d.ts +7 -0
- package/dist/core/bind.d.ts +8 -0
- package/dist/core/dom.d.ts +18 -0
- package/dist/core/glare.d.ts +65 -0
- package/dist/core/idle.d.ts +9 -0
- package/dist/core/interactions.d.ts +3 -0
- package/dist/core/loaders.d.ts +5 -0
- package/dist/core/options.d.ts +5 -0
- package/dist/core/registry.d.ts +9 -0
- package/dist/core/zoom.d.ts +36 -0
- package/dist/defaults.d.ts +5 -5
- package/dist/esm.d.ts +3 -0
- package/dist/glare.css +1 -1
- package/dist/glare.esm.js +1038 -1171
- package/dist/glare.esm.js.map +1 -1
- package/dist/glare.js +25 -23
- package/dist/glare.js.map +1 -1
- package/dist/i18n.d.ts +4 -0
- package/dist/icons.d.ts +12 -13
- package/dist/index.d.ts +5 -7
- package/dist/media/detect.d.ts +4 -0
- package/dist/media/items.d.ts +6 -0
- package/dist/media/providers.d.ts +6 -0
- package/dist/modules/fullscreen.d.ts +15 -0
- package/dist/modules/gestures.d.ts +45 -0
- package/dist/modules/hash.d.ts +22 -0
- package/dist/modules/share.d.ts +17 -0
- package/dist/modules/slideshow.d.ts +25 -0
- package/dist/modules/thumbs.d.ts +22 -0
- package/dist/modules/wheel.d.ts +19 -0
- package/dist/templates.d.ts +7 -0
- package/dist/types.d.ts +117 -131
- package/dist/umd.d.ts +3 -0
- package/dist/utils/dom.d.ts +20 -0
- package/dist/utils/env.d.ts +5 -0
- package/dist/utils/object.d.ts +3 -0
- package/dist/utils/template.d.ts +5 -0
- package/package.json +18 -24
- package/dist/defaults.d.ts.map +0 -1
- package/dist/fullscreen.d.ts +0 -14
- package/dist/fullscreen.d.ts.map +0 -1
- package/dist/gestures.d.ts +0 -24
- package/dist/gestures.d.ts.map +0 -1
- package/dist/hash.d.ts +0 -20
- package/dist/hash.d.ts.map +0 -1
- package/dist/icons.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/instance.d.ts +0 -103
- package/dist/instance.d.ts.map +0 -1
- package/dist/media.d.ts +0 -5
- package/dist/media.d.ts.map +0 -1
- package/dist/share.d.ts +0 -13
- package/dist/share.d.ts.map +0 -1
- package/dist/slideshow.d.ts +0 -19
- package/dist/slideshow.d.ts.map +0 -1
- package/dist/thumbs.d.ts +0 -17
- package/dist/thumbs.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -31
- package/dist/utils.d.ts.map +0 -1
- package/dist/wheel.d.ts +0 -11
- package/dist/wheel.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
Modern, touch-enabled lightbox for the web. **Zero dependencies.** MIT licensed.
|
|
4
4
|
|
|
5
|
-
Open images, HTML5 video, YouTube/Vimeo, maps, iframes, inline nodes, AJAX fragments, and custom HTML
|
|
5
|
+
Open images, HTML5 video, YouTube/Vimeo, maps, iframes, inline nodes, AJAX fragments, and custom HTML, with galleries, zoom, thumbnails, slideshow, fullscreen, deep links, and a polished toolbar.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Vanilla JS / TypeScript
|
|
9
|
+
- **Vanilla JS / TypeScript**, no jQuery, no framework lock-in
|
|
10
10
|
- **Galleries** with loop, arrows, keyboard, mouse wheel, and swipe
|
|
11
11
|
- **Content types**: image, video, iframe, inline, AJAX, HTML
|
|
12
12
|
- **Media helpers** for YouTube, Vimeo, and Google Maps URLs
|
|
13
|
-
- **Pinch-zoom
|
|
14
|
-
- **Thumbnails**, **slideshow**, **fullscreen**, **share**, **hash** deep
|
|
13
|
+
- **Pinch-zoom and pan**, click-to-zoom, protect mode
|
|
14
|
+
- **Thumbnails**, **slideshow**, **fullscreen**, **share**, **hash** deep links
|
|
15
15
|
- **Accessible** dialog: focus trap, ARIA, Escape, restored focus
|
|
16
16
|
- **Theming** via CSS custom properties
|
|
17
17
|
- ESM + UMD builds, full type declarations
|
|
@@ -65,14 +65,46 @@ Glare.open(
|
|
|
65
65
|
|
|
66
66
|
- Docs: [redot-src.github.io/glare](https://redot-src.github.io/glare/)
|
|
67
67
|
- Live demo: [redot-src.github.io/glare/demo](https://redot-src.github.io/glare/demo/)
|
|
68
|
-
|
|
68
|
+
|
|
69
|
+
## Development
|
|
69
70
|
|
|
70
71
|
```bash
|
|
71
72
|
npm install
|
|
72
|
-
npm run dev # interactive demo
|
|
73
|
+
npm run dev # interactive demo with live reload
|
|
74
|
+
npm run build # typecheck + library build → dist/
|
|
73
75
|
npm run docs:dev # VitePress documentation
|
|
74
|
-
npm run build
|
|
75
|
-
|
|
76
|
+
npm run pages:build # docs + demo, as deployed to GitHub Pages
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Project structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
src/
|
|
83
|
+
index.ts public API and type exports
|
|
84
|
+
esm.ts ESM build entry: the API plus the stylesheet
|
|
85
|
+
umd.ts UMD/CDN build entry: exposes the class as window.Glare
|
|
86
|
+
types.ts public types
|
|
87
|
+
defaults.ts default options
|
|
88
|
+
i18n.ts built-in strings
|
|
89
|
+
icons.ts inline SVG icons
|
|
90
|
+
templates.ts HTML templates for the dialog and buttons
|
|
91
|
+
core/ the Glare class and its collaborators
|
|
92
|
+
glare.ts lifecycle, navigation, public API
|
|
93
|
+
dom.ts building and updating the dialog markup
|
|
94
|
+
loaders.ts one loader per content type
|
|
95
|
+
interactions.ts clicks, keyboard, focus trap
|
|
96
|
+
animation.ts open animation and slide-transition settings
|
|
97
|
+
zoom.ts image zoom and pan maths
|
|
98
|
+
idle.ts idle timer that hides the controls
|
|
99
|
+
options.ts merges defaults, mobile overrides, and module shorthands
|
|
100
|
+
registry.ts stack of open instances
|
|
101
|
+
bind.ts declarative `Glare.bind()` and hash restore
|
|
102
|
+
media/ URL type detection, providers (YouTube, Vimeo, Maps), item normalization
|
|
103
|
+
modules/ optional features: fullscreen, gestures, hash, share, slideshow, thumbs, wheel
|
|
104
|
+
styles/ stylesheet split by concern; tokens.css holds the public CSS variables
|
|
105
|
+
utils/ small DOM, object, environment, and template helpers
|
|
106
|
+
demo/ Vite demo site (npm run dev)
|
|
107
|
+
docs/ VitePress documentation
|
|
76
108
|
```
|
|
77
109
|
|
|
78
110
|
## License
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ResolvedOptions, SlideItem } from '../types';
|
|
2
|
+
/** Writes the effect and duration settings onto the container for the stylesheet to use. */
|
|
3
|
+
export declare function applyMotionSettings(container: HTMLElement, opts: ResolvedOptions): void;
|
|
4
|
+
/** Marks the container so slide-change keyframes apply from now on. */
|
|
5
|
+
export declare function enableTransitions(container: HTMLElement, opts: ResolvedOptions): void;
|
|
6
|
+
/** Flies the opened image in from its trigger element. */
|
|
7
|
+
export declare function animateOpen(container: HTMLElement, item: SlideItem, opts: ResolvedOptions): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BoundGroup, GlareOptions } from '../types';
|
|
2
|
+
export type BindTarget = string | HTMLElement | HTMLElement[] | NodeListOf<HTMLElement>;
|
|
3
|
+
/** Opens `elements` as a gallery named `gallery`, starting at `index`. */
|
|
4
|
+
type Opener = (elements: HTMLElement[], index: number, gallery: string) => void;
|
|
5
|
+
/** Attaches click handlers that open a lightbox for the clicked element's gallery. */
|
|
6
|
+
export declare function bind(target: BindTarget, options: GlareOptions, open: Opener): BoundGroup;
|
|
7
|
+
export declare function unbindAll(): void;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GlareRefs, I18nDict, ResolvedOptions, SlideItem } from '../types';
|
|
2
|
+
export declare function buildContainer(opts: ResolvedOptions, dict: I18nDict, id: number, count: number): GlareRefs;
|
|
3
|
+
/** Creates a hidden slide with an empty content box and appends it to the stage. */
|
|
4
|
+
export declare function mountSlide(stage: HTMLElement, item: SlideItem, opts: ResolvedOptions): HTMLElement;
|
|
5
|
+
/** Makes a mounted slide the current one, fading it in unless `instant`. */
|
|
6
|
+
export declare function revealSlide(slide: HTMLElement, instant: boolean): void;
|
|
7
|
+
/** Fades out every slide except `keep` and removes it after `delay`. */
|
|
8
|
+
export declare function retireSlides(stage: HTMLElement, keep: HTMLElement, delay: number): void;
|
|
9
|
+
export declare function addSmallButton(slide: HTMLElement, opts: ResolvedOptions, dict: I18nDict): void;
|
|
10
|
+
export declare function showSpinner(stage: HTMLElement, opts: ResolvedOptions, dict: I18nDict): void;
|
|
11
|
+
export declare function hideSpinner(stage: HTMLElement): void;
|
|
12
|
+
export declare function showError(item: SlideItem, error: unknown, opts: ResolvedOptions, dict: I18nDict): void;
|
|
13
|
+
export declare function usesSmallButton(opts: ResolvedOptions, item: SlideItem): boolean;
|
|
14
|
+
/** Updates every piece of chrome that depends on the current slide. */
|
|
15
|
+
export declare function syncChrome(refs: GlareRefs, opts: ResolvedOptions, dict: I18nDict, item: SlideItem, total: number, caption: string): void;
|
|
16
|
+
export declare function syncZoomButton(container: HTMLElement, dict: I18nDict, zoomed: boolean, hasImage: boolean): void;
|
|
17
|
+
/** Swaps a toolbar toggle's label and icon and marks it active. */
|
|
18
|
+
export declare function setToggleState(button: HTMLElement, active: boolean, label: string, icon: string): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { BoundGroup, GlareInstance, GlareOptions, GlareRefs, I18nDict, ResolvedOptions, SlideItem, SlideSource } from '../types';
|
|
2
|
+
import { Fullscreen } from '../modules/fullscreen';
|
|
3
|
+
import { Share } from '../modules/share';
|
|
4
|
+
import { Slideshow } from '../modules/slideshow';
|
|
5
|
+
import { Thumbs } from '../modules/thumbs';
|
|
6
|
+
import { type BindTarget } from './bind';
|
|
7
|
+
import { Zoom, type Point } from './zoom';
|
|
8
|
+
export declare class Glare implements GlareInstance {
|
|
9
|
+
readonly id: number;
|
|
10
|
+
readonly opts: ResolvedOptions;
|
|
11
|
+
readonly group: SlideItem[];
|
|
12
|
+
readonly dict: I18nDict;
|
|
13
|
+
readonly zoom: Zoom;
|
|
14
|
+
current: SlideItem | null;
|
|
15
|
+
currIndex: number;
|
|
16
|
+
prevIndex: number;
|
|
17
|
+
isActive: boolean;
|
|
18
|
+
isClosing: boolean;
|
|
19
|
+
isIdle: boolean;
|
|
20
|
+
$refs: GlareRefs | null;
|
|
21
|
+
slideshow?: Slideshow;
|
|
22
|
+
thumbs?: Thumbs;
|
|
23
|
+
fullscreen?: Fullscreen;
|
|
24
|
+
share?: Share;
|
|
25
|
+
private readonly galleryName;
|
|
26
|
+
private readonly idle;
|
|
27
|
+
private hash;
|
|
28
|
+
private gestures;
|
|
29
|
+
private wheel;
|
|
30
|
+
private cleanups;
|
|
31
|
+
private previouslyFocused;
|
|
32
|
+
constructor(items: Array<SlideSource | string> | HTMLElement[], options?: GlareOptions, index?: number, galleryName?: string);
|
|
33
|
+
open(index?: number): void;
|
|
34
|
+
close(): void;
|
|
35
|
+
next(): void;
|
|
36
|
+
prev(): void;
|
|
37
|
+
jumpTo(index: number): void;
|
|
38
|
+
toggleZoom(focus?: Point): void;
|
|
39
|
+
update(): void;
|
|
40
|
+
focus(): void;
|
|
41
|
+
toggleControls(force?: boolean): void;
|
|
42
|
+
/** True once per drag gesture, so the click that follows it can be ignored. */
|
|
43
|
+
consumeGesture(): boolean;
|
|
44
|
+
private showSlide;
|
|
45
|
+
private syncChrome;
|
|
46
|
+
private captionFor;
|
|
47
|
+
private syncZoomState;
|
|
48
|
+
private resolveParent;
|
|
49
|
+
private startModules;
|
|
50
|
+
private onActivity;
|
|
51
|
+
private teardown;
|
|
52
|
+
private emit;
|
|
53
|
+
private emitSlide;
|
|
54
|
+
private clampIndex;
|
|
55
|
+
static defaults: ResolvedOptions;
|
|
56
|
+
static open(items: Array<SlideSource | string> | HTMLElement[], options?: GlareOptions, index?: number): Glare;
|
|
57
|
+
static bind(target: BindTarget, options?: GlareOptions): BoundGroup;
|
|
58
|
+
static close(all?: boolean): void;
|
|
59
|
+
static getInstance(id?: number): Glare | null;
|
|
60
|
+
static getInstances(): Glare[];
|
|
61
|
+
/** Closes every instance and removes all `bind()` handlers. */
|
|
62
|
+
static destroy(): void;
|
|
63
|
+
/** Binds every `[data-glare]` element once the DOM is ready. */
|
|
64
|
+
static autoBind(options?: GlareOptions): void;
|
|
65
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Calls `onIdle` after `seconds` of no activity; `false` disables it. */
|
|
2
|
+
export declare class IdleTimer {
|
|
3
|
+
private readonly seconds;
|
|
4
|
+
private readonly onIdle;
|
|
5
|
+
private timer;
|
|
6
|
+
constructor(seconds: number | false, onIdle: () => void);
|
|
7
|
+
reset(): void;
|
|
8
|
+
stop(): void;
|
|
9
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { I18nDict, ResolvedOptions, SlideItem } from '../types';
|
|
2
|
+
/** Renders the slide's content into `content` and resolves once it can be shown. */
|
|
3
|
+
export declare function loadContent(item: SlideItem, content: HTMLElement, opts: ResolvedOptions, dict: I18nDict): Promise<void>;
|
|
4
|
+
/** Warms the browser cache for neighbouring images. */
|
|
5
|
+
export declare function preloadNeighbours(group: SlideItem[], index: number): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { GlareOptions, ResolvedOptions } from '../types';
|
|
2
|
+
/** Merges user options over the defaults, then applies `mobile` overrides on touch devices. */
|
|
3
|
+
export declare function resolveOptions(options: GlareOptions): ResolvedOptions;
|
|
4
|
+
/** Normalizes a `T | boolean` module option: `true` yields the defaults, falsy disables it. */
|
|
5
|
+
export declare function moduleOptions<T extends object>(value: Partial<T> | boolean | undefined, fallback: T): T | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface Point {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ZoomState extends Point {
|
|
6
|
+
scale: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ZoomTarget {
|
|
9
|
+
image(): HTMLImageElement | null;
|
|
10
|
+
stage(): HTMLElement | null;
|
|
11
|
+
onChange(zoomed: boolean): void;
|
|
12
|
+
}
|
|
13
|
+
export declare const ZOOM_MIN = 1;
|
|
14
|
+
export declare const ZOOM_MAX = 5;
|
|
15
|
+
/**
|
|
16
|
+
* Controls the transform of the current image.
|
|
17
|
+
* The image is scaled around its centre and then translated by (x, y).
|
|
18
|
+
*/
|
|
19
|
+
export declare class Zoom {
|
|
20
|
+
private readonly target;
|
|
21
|
+
scale: number;
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
constructor(target: ZoomTarget);
|
|
25
|
+
get isZoomed(): boolean;
|
|
26
|
+
get state(): ZoomState;
|
|
27
|
+
/** Centre of the image in viewport coordinates, ignoring the current translation. */
|
|
28
|
+
center(): Point | null;
|
|
29
|
+
apply(scale: number, x: number, y: number, duration?: number): void;
|
|
30
|
+
toFit(duration?: number): void;
|
|
31
|
+
/** Zooms to the image's natural size (at least 1.5x), keeping `focus` under the pointer. */
|
|
32
|
+
toActual(focus?: Partial<Point>, duration?: number): void;
|
|
33
|
+
reset(): void;
|
|
34
|
+
/** Keeps the scaled image from being dragged fully out of the stage. */
|
|
35
|
+
private bounded;
|
|
36
|
+
}
|
package/dist/defaults.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
|
|
1
|
+
import type { FullscreenOptions, ResolvedOptions, SlideshowOptions, ThumbsOptions } from './types';
|
|
2
|
+
export declare const thumbsDefaults: Required<Omit<ThumbsOptions, 'parentEl'>> & ThumbsOptions;
|
|
3
|
+
export declare const slideshowDefaults: Required<SlideshowOptions>;
|
|
4
|
+
export declare const fullscreenDefaults: Required<FullscreenOptions>;
|
|
5
|
+
export declare const defaults: ResolvedOptions;
|
package/dist/esm.d.ts
ADDED
package/dist/glare.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--glare-bg: rgba(12, 14, 18, .92);--glare-bg-solid: #0c0e12;--glare-fg: #f4f6f8;--glare-muted: rgba(244, 246, 248, .62);--glare-accent: #ff4d4d;--glare-accent-soft: rgba(255, 77, 77, .18);--glare-toolbar-bg: rgba(12, 14, 18, .55);--glare-button-bg: rgba(255, 255, 255, .08);--glare-button-hover: rgba(255, 255, 255, .16);--glare-button-size: 44px;--glare-radius: 14px;--glare-shadow: 0 24px 80px rgba(0, 0, 0, .45);--glare-ease: cubic-bezier(.22, 1, .36, 1);--glare-duration: 366ms;--glare-transition-duration: 366ms;--glare-caption-bg: linear-gradient(180deg, transparent, rgba(0, 0, 0, .72));--glare-z: 100000;--glare-font: "Segoe UI", system-ui, -apple-system, sans-serif}.glare-lock{overflow:hidden!important}.glare-container{position:fixed;inset:0;z-index:var(--glare-z);display:flex;color:var(--glare-fg);font-family:var(--glare-font);outline:none;opacity:0;visibility:hidden;transition:opacity var(--glare-duration) var(--glare-ease),visibility var(--glare-duration);-webkit-tap-highlight-color:transparent}.glare-container.glare-is-open{opacity:1;visibility:visible}.glare-container.glare-is-closing{opacity:0}.glare-bg{position:absolute;inset:0;background:var(--glare-bg);backdrop-filter:blur(18px) saturate(1.2);-webkit-backdrop-filter:blur(18px) saturate(1.2)}.glare-inner{position:relative;z-index:1;display:grid;grid-template-rows:auto 1fr auto;width:100%;height:100%;min-height:0}.glare-toolbar,.glare-infobar,.glare-navigation,.glare-caption{transition:opacity .22s var(--glare-ease),transform .22s var(--glare-ease)}.glare-container.glare-is-idle .glare-toolbar,.glare-container.glare-is-idle .glare-infobar,.glare-container.glare-is-idle .glare-navigation,.glare-container.glare-is-idle .glare-caption:not(:hover){opacity:0;pointer-events:none}.glare-toolbar{position:absolute;top:12px;right:12px;z-index:5;display:flex;gap:6px;padding:6px;border-radius:999px;background:var(--glare-toolbar-bg);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:var(--glare-shadow)}.glare-infobar{position:absolute;top:18px;left:18px;z-index:5;padding:8px 14px;border-radius:999px;background:var(--glare-toolbar-bg);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);font-size:13px;font-variant-numeric:tabular-nums;letter-spacing:.02em;color:var(--glare-muted)}.glare-button{appearance:none;border:0;margin:0;padding:0;width:var(--glare-button-size);height:var(--glare-button-size);display:inline-flex;align-items:center;justify-content:center;border-radius:50%;background:var(--glare-button-bg);color:var(--glare-fg);cursor:pointer;text-decoration:none;transition:background .16s ease,transform .16s ease,color .16s ease}.glare-button svg{width:20px;height:20px;display:block}.glare-button:hover,.glare-button:focus-visible{background:var(--glare-button-hover);outline:none}.glare-button:focus-visible{box-shadow:0 0 0 2px var(--glare-accent)}.glare-button.is-active{background:var(--glare-accent-soft);color:var(--glare-accent)}.glare-button.glare-disabled,.glare-button:disabled{opacity:.35;pointer-events:none}.glare-navigation{position:absolute;inset:0;z-index:4;pointer-events:none}.glare-button--prev,.glare-button--next{position:absolute;top:50%;transform:translateY(-50%);pointer-events:auto;width:52px;height:52px;background:var(--glare-toolbar-bg);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}.glare-button--prev{left:16px}.glare-button--next{right:16px}.glare-button--prev:hover,.glare-button--next:hover{transform:translateY(-50%) scale(1.04)}.glare-stage{position:relative;grid-row:1 / -1;width:100%;height:100%;overflow:hidden;touch-action:none}.glare-slide{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity var(--glare-transition-duration) var(--glare-ease)}.glare-slide--current{opacity:1;z-index:2}.glare-slide--out{opacity:0;z-index:1;pointer-events:none}.glare-space{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;padding:64px 72px 88px;box-sizing:border-box}.glare-content{position:relative;max-width:100%;max-height:100%;display:flex;align-items:center;justify-content:center;border-radius:var(--glare-radius);box-shadow:var(--glare-shadow)}.glare-content--image{background:transparent;box-shadow:none;overflow:visible}.glare-image{display:block;max-width:min(100vw - 48px,100%);max-height:min(100vh - 160px,100%);width:auto;height:auto;object-fit:contain;-webkit-user-select:none;user-select:none;-webkit-user-drag:none;transform-origin:center center;transition:transform var(--glare-duration) var(--glare-ease),opacity var(--glare-duration) var(--glare-ease);border-radius:8px}.glare-content--html,.glare-content--inline,.glare-content--ajax{background:#11151c;color:var(--glare-fg);padding:28px;max-width:min(720px,calc(100vw - 48px));max-height:min(80vh,calc(100vh - 160px));overflow:auto;border:1px solid rgba(255,255,255,.08)}.glare-content--video,.glare-content--iframe{background:#000;overflow:hidden}.glare-video{display:block;max-width:min(960px,calc(100vw - 48px));max-height:min(80vh,calc(100vh - 160px));width:100%;background:#000}.glare-iframe-wrap{width:min(960px,calc(100vw - 48px));height:min(70vh,calc(100vh - 180px));max-width:100%}.glare-iframe{width:100%;height:100%;border:0;display:block;background:#000}.glare-caption{position:absolute;left:0;right:0;bottom:0;z-index:5;padding:48px 24px 24px;background:var(--glare-caption-bg);text-align:center;font-size:15px;line-height:1.5;pointer-events:none}.glare-caption a{color:var(--glare-accent);pointer-events:auto}.glare-close-small{position:absolute;top:12px;right:12px;z-index:6}.glare-spinner{position:absolute;top:50%;left:50%;width:42px;height:42px;margin:-21px 0 0 -21px;border-radius:50%;border:3px solid rgba(255,255,255,.18);border-top-color:var(--glare-accent);animation:glare-spin .8s linear infinite;z-index:3}@keyframes glare-spin{to{transform:rotate(360deg)}}.glare-error{padding:28px 32px;border-radius:var(--glare-radius);background:#161a22;border:1px solid rgba(255,255,255,.08);text-align:center;max-width:420px;color:var(--glare-muted)}.glare-hidden{display:none!important}.glare-thumbs{position:absolute;z-index:6;opacity:0;pointer-events:none;transition:opacity .22s ease,transform .22s ease}.glare-thumbs--active{opacity:1;pointer-events:auto}.glare-thumbs--y{top:72px;right:12px;bottom:88px;width:88px;transform:translate(12px)}.glare-thumbs--y.glare-thumbs--active{transform:translate(0)}.glare-thumbs--x{left:12px;right:12px;bottom:72px;height:78px;transform:translateY(12px)}.glare-thumbs--x.glare-thumbs--active{transform:translateY(0)}.glare-thumbs-list{display:flex;gap:8px;height:100%;padding:8px;border-radius:16px;background:var(--glare-toolbar-bg);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);overflow:auto;scrollbar-width:thin}.glare-thumbs--y .glare-thumbs-list{flex-direction:column}.glare-thumbs--x .glare-thumbs-list{flex-direction:row}.glare-thumbs-item{appearance:none;border:2px solid transparent;padding:0;margin:0;width:64px;height:64px;border-radius:10px;overflow:hidden;background:#ffffff0f;cursor:pointer;flex:0 0 auto;color:var(--glare-muted);font-size:12px}.glare-thumbs-item img{width:100%;height:100%;object-fit:cover;display:block}.glare-thumbs-item.is-active{border-color:var(--glare-accent)}.glare-container.glare-show-thumbs.glare-thumbs-axis-y .glare-space,.glare-show-thumbs .glare-space{padding-right:110px}.glare-share-overlay{position:absolute;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;background:#0000008c;padding:24px}.glare-share{width:min(420px,100%);background:#12161e;border:1px solid rgba(255,255,255,.08);border-radius:18px;padding:24px;box-shadow:var(--glare-shadow)}.glare-share-title{margin:0 0 16px;font-size:18px}.glare-share p{margin:0 0 10px}.glare-share-link{color:var(--glare-fg);text-decoration:none;display:inline-flex;padding:10px 12px;border-radius:10px;background:#ffffff0f;width:100%;box-sizing:border-box}.glare-share-link:hover{background:#ffffff1f}.glare-share-input{width:100%;box-sizing:border-box;border-radius:10px;border:1px solid rgba(255,255,255,.12);background:#00000059;color:var(--glare-fg);padding:10px 12px;font:inherit}.glare-container[data-transition=slide] .glare-slide--out{transform:translate3d(-40px,0,0)}.glare-container[data-transition=circular] .glare-slide--current{animation:glare-circular var(--glare-transition-duration) var(--glare-ease)}.glare-container[data-transition=tube] .glare-slide--current{animation:glare-tube var(--glare-transition-duration) var(--glare-ease)}.glare-container[data-transition=rotate] .glare-slide--current{animation:glare-rotate var(--glare-transition-duration) var(--glare-ease)}.glare-container[data-transition=zoom-in-out] .glare-slide--current{animation:glare-zoom-inout var(--glare-transition-duration) var(--glare-ease)}@keyframes glare-circular{0%{transform:scale(.85) rotate(-8deg);opacity:0}to{transform:none;opacity:1}}@keyframes glare-tube{0%{transform:scaleX(.2);opacity:0}to{transform:none;opacity:1}}@keyframes glare-rotate{0%{transform:rotate(12deg) scale(.92);opacity:0}to{transform:none;opacity:1}}@keyframes glare-zoom-inout{0%{transform:scale(1.18);opacity:0}to{transform:none;opacity:1}}.glare-container.glare-is-slideshow .glare-button--slideshow{color:var(--glare-accent)}.glare-container.glare-is-modal .glare-bg{pointer-events:none}@media(max-width:720px){.glare-space{padding:56px 16px 96px}.glare-button--prev,.glare-button--next{width:44px;height:44px}.glare-button--prev{left:8px}.glare-button--next{right:8px}.glare-toolbar{top:8px;right:8px;gap:4px;padding:4px}.glare-button{width:40px;height:40px}.glare-thumbs--y{display:none}.glare-infobar{top:12px;left:12px;font-size:12px}}@media(prefers-reduced-motion:reduce){.glare-container,.glare-slide,.glare-image,.glare-toolbar,.glare-infobar,.glare-navigation,.glare-caption,.glare-thumbs{transition:none!important;animation:none!important}}
|
|
1
|
+
:root{--glare-z: 100000;--glare-font: system-ui, -apple-system, "Segoe UI", sans-serif;--glare-bg: rgba(12, 14, 18, .92);--glare-fg: #f4f6f8;--glare-muted: rgba(244, 246, 248, .62);--glare-surface: #11151c;--glare-border: rgba(255, 255, 255, .08);--glare-accent: #ff4d4d;--glare-accent-soft: rgba(255, 77, 77, .18);--glare-toolbar-bg: rgba(12, 14, 18, .55);--glare-toolbar-bg-hover: rgba(12, 14, 18, .8);--glare-button-bg: rgba(255, 255, 255, .08);--glare-button-hover: rgba(255, 255, 255, .16);--glare-button-size: 44px;--glare-caption-bg: linear-gradient(180deg, transparent, rgba(0, 0, 0, .72));--glare-radius: 14px;--glare-shadow: 0 24px 80px rgba(0, 0, 0, .45);--glare-backdrop: blur(14px);--glare-blur: blur(12px);--glare-ease: cubic-bezier(.22, 1, .36, 1);--glare-iframe-bg: #fff;--glare-iframe-radius: 5px;--glare-thumbs-size: 95px}.glare-lock{overflow:hidden!important}.glare-container{position:fixed;inset:0;z-index:var(--glare-z);color:var(--glare-fg);font-family:var(--glare-font);outline:none;visibility:hidden;transition:visibility var(--glare-duration);-webkit-tap-highlight-color:transparent}.glare-container.glare-is-open{visibility:visible}.glare-bg,.glare-inner{opacity:0;transition:opacity var(--glare-duration) var(--glare-ease);will-change:opacity}.glare-is-open .glare-bg,.glare-is-open .glare-inner{opacity:1}.glare-is-closing .glare-bg,.glare-is-closing .glare-inner,.glare-is-closing .glare-thumbs,.glare-is-closing .glare-share-overlay{opacity:0;pointer-events:none}.glare-bg{position:absolute;inset:0;background:var(--glare-bg);-webkit-backdrop-filter:var(--glare-backdrop);backdrop-filter:var(--glare-backdrop)}.glare-inner{position:relative;z-index:1;width:100%;height:100%}.glare-hidden{display:none!important}.glare-sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.glare-button{appearance:none;display:inline-flex;align-items:center;justify-content:center;width:var(--glare-button-size);height:var(--glare-button-size);margin:0;padding:0;border:0;border-radius:50%;background:var(--glare-button-bg);color:var(--glare-fg);cursor:pointer;text-decoration:none;transition:background .16s ease,color .16s ease,transform .16s ease}.glare-button svg{display:block;width:20px;height:20px}.glare-toolbar .glare-button{background:transparent}.glare-button:hover,.glare-button:focus-visible{background:var(--glare-button-hover);outline:none}.glare-button:focus-visible{box-shadow:0 0 0 2px var(--glare-accent)}.glare-button.glare-is-active{background:var(--glare-accent-soft);color:var(--glare-accent)}.glare-button.glare-is-disabled{opacity:.35;pointer-events:none}.glare-toolbar,.glare-infobar,.glare-button--prev,.glare-button--next,.glare-close-small{border:1px solid var(--glare-border);background:var(--glare-toolbar-bg);-webkit-backdrop-filter:var(--glare-blur);backdrop-filter:var(--glare-blur)}.glare-button--prev:hover,.glare-button--next:hover,.glare-close-small:hover,.glare-button--prev:focus-visible,.glare-button--next:focus-visible,.glare-close-small:focus-visible{background:var(--glare-toolbar-bg-hover)}.glare-toolbar,.glare-infobar{position:absolute;top:12px;z-index:5;border-radius:999px}.glare-toolbar{right:12px;display:flex;gap:6px;padding:5px}.glare-infobar{top:18px;left:18px;padding:8px 14px;color:var(--glare-muted);font-size:13px;font-variant-numeric:tabular-nums;letter-spacing:.02em}.glare-navigation{position:absolute;inset:0;z-index:4;pointer-events:none}.glare-button--prev,.glare-button--next{position:absolute;top:50%;width:52px;height:52px;transform:translateY(-50%);pointer-events:auto}.glare-button--prev{left:16px}.glare-button--next{right:16px}.glare-close-small{position:absolute;top:12px;right:12px;z-index:6}.glare-caption{position:absolute;inset:auto 0 0;z-index:5;padding:48px 24px 24px;background:var(--glare-caption-bg);font-size:15px;line-height:1.5;text-align:center;pointer-events:none}.glare-caption a{color:var(--glare-accent);pointer-events:auto}.glare-infobar,.glare-navigation,.glare-caption{transition:opacity .22s var(--glare-ease),visibility .22s}.glare-is-idle .glare-infobar,.glare-is-idle .glare-navigation,.glare-is-idle .glare-caption:not(:hover){opacity:0;visibility:hidden;pointer-events:none}.glare-progress{position:absolute;top:0;left:0;right:0;z-index:30;height:3px;background:var(--glare-accent);transform:scaleX(0);transform-origin:left center;transition:transform 0s linear;pointer-events:none}.glare-spinner{position:absolute;top:50%;left:50%;z-index:3;pointer-events:none;width:42px;height:42px;margin:-21px 0 0 -21px;border:3px solid rgba(255,255,255,.18);border-top-color:var(--glare-accent);border-radius:50%;animation:glare-spin .8s linear infinite}@keyframes glare-spin{to{transform:rotate(360deg)}}.glare-error{max-width:420px;padding:28px 32px;border:1px solid var(--glare-border);border-radius:var(--glare-radius);background:var(--glare-surface);color:var(--glare-muted);text-align:center}.glare-container{--glare-thumbs-inset: 0px;--glare-inset-top: 64px;--glare-inset-x: 72px;--glare-inset-bottom: max(88px, var(--glare-thumbs-inset))}.glare-show-thumbs.glare-thumbs-axis-x{--glare-thumbs-inset: calc(var(--glare-thumbs-size) + 16px)}.glare-show-thumbs.glare-thumbs-axis-y{--glare-inset-x: 110px}.glare-slide:where(:not(.glare-slide--image)){--glare-inset-top: 30px;--glare-inset-x: 30px;--glare-inset-bottom: max(30px, var(--glare-thumbs-inset))}.glare-stage{position:absolute;inset:0;overflow:hidden;touch-action:none;transition:transform .2s var(--glare-ease)}.glare-slide{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;box-sizing:border-box;padding:var(--glare-inset-top) var(--glare-inset-x) var(--glare-inset-bottom);opacity:0;transition:opacity var(--glare-transition-duration) var(--glare-ease),transform var(--glare-transition-duration) var(--glare-ease)}.glare-slide--current{z-index:2;opacity:1}.glare-slide--out{z-index:1;opacity:0;pointer-events:none}.glare-content{position:relative;display:flex;align-items:center;justify-content:center;max-width:100%;max-height:100%}.glare-image{display:block;width:auto;height:auto;max-width:calc(100vw - 2 * var(--glare-inset-x));max-height:calc(100vh - var(--glare-inset-top) - var(--glare-inset-bottom));max-height:calc(100dvh - var(--glare-inset-top) - var(--glare-inset-bottom));border-radius:8px;object-fit:contain;-webkit-user-select:none;user-select:none;-webkit-user-drag:none;transform-origin:center;will-change:transform;transition:transform var(--glare-duration) var(--glare-ease),opacity var(--glare-duration) var(--glare-ease)}.glare-can-zoom-in .glare-image{cursor:zoom-in}.glare-can-zoom-out .glare-image{cursor:zoom-out}.glare-video{display:block;width:min(960px,100vw - 2 * var(--glare-inset-x));max-width:100%;max-height:calc(100vh - var(--glare-inset-top) - var(--glare-inset-bottom));max-height:calc(100dvh - var(--glare-inset-top) - var(--glare-inset-bottom));border-radius:var(--glare-iframe-radius);background:#000;box-shadow:var(--glare-shadow);object-fit:contain}.glare-content--iframe{width:100%;height:100%}.glare-iframe-wrap{width:100%;height:100%;max-width:100%;max-height:100%;overflow:hidden;border-radius:var(--glare-iframe-radius);background:var(--glare-iframe-bg);box-shadow:var(--glare-shadow)}.glare-iframe{display:block;width:100%;height:100%;border:0}.glare-content--html,.glare-content--inline,.glare-content--ajax{display:block;box-sizing:border-box;max-width:min(720px,100%);padding:28px;overflow:auto;border:1px solid var(--glare-border);border-radius:var(--glare-radius);background:var(--glare-surface);box-shadow:var(--glare-shadow)}.glare-content--html>:first-child,.glare-content--inline>:first-child,.glare-content--ajax>:first-child{margin-top:0}.glare-content--html>:last-child,.glare-content--inline>:last-child,.glare-content--ajax>:last-child{margin-bottom:0}.glare-thumbs{position:absolute;z-index:6;opacity:0;pointer-events:none;transition:opacity .22s var(--glare-ease),transform .22s var(--glare-ease)}.glare-thumbs--active{opacity:1;pointer-events:auto;transform:none}.glare-thumbs--x{left:0;right:0;bottom:0;height:var(--glare-thumbs-size);transform:translateY(8px)}.glare-thumbs--y{top:72px;right:12px;bottom:88px;width:88px;transform:translate(12px)}.glare-thumbs-list{display:flex;gap:8px;height:100%;box-sizing:border-box;overflow:auto;scrollbar-width:thin;-webkit-backdrop-filter:var(--glare-blur);backdrop-filter:var(--glare-blur)}.glare-thumbs--x .glare-thumbs-list{padding:10px 10px 5px;background:#0000004d}.glare-thumbs--y .glare-thumbs-list{flex-direction:column;padding:8px;border:1px solid var(--glare-border);border-radius:16px;background:var(--glare-toolbar-bg)}.glare-thumbs-item{appearance:none;flex:0 0 auto;box-sizing:border-box;width:70px;height:70px;margin:0;padding:0;border:4px solid transparent;border-radius:10px;overflow:hidden;background:var(--glare-button-bg);color:var(--glare-muted);font-size:12px;cursor:pointer}.glare-thumbs-item img{display:block;width:100%;height:100%;object-fit:cover}.glare-thumbs-item.glare-is-active{border-color:var(--glare-accent)}.glare-thumbs-item:focus-visible{outline:2px solid var(--glare-accent);outline-offset:-4px}.glare-show-thumbs.glare-thumbs-axis-x .glare-caption{bottom:var(--glare-thumbs-size)}.glare-share-overlay{position:absolute;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;padding:24px;background:#0000008c}.glare-share{width:min(420px,100%);padding:24px;border:1px solid var(--glare-border);border-radius:var(--glare-radius);background:var(--glare-surface);box-shadow:var(--glare-shadow)}.glare-share-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}.glare-share-title{margin:0;font-size:18px}.glare-share-close{width:36px;height:36px}.glare-share p{margin:0 0 10px}.glare-share-row{display:flex;gap:8px}.glare-share-link,.glare-share-input,.glare-share-copy{display:block;box-sizing:border-box;padding:10px 12px;border-radius:10px;color:var(--glare-fg);font:inherit}.glare-share-link{width:100%;background:var(--glare-button-bg);text-decoration:none}.glare-share-link:hover,.glare-share-copy:hover{background:var(--glare-button-hover)}.glare-share-input{flex:1;min-width:0;border:1px solid var(--glare-border);background:#00000059}.glare-share-copy{flex:0 0 auto;border:0;background:var(--glare-button-bg);cursor:pointer}[data-transition=slide] .glare-slide--out{transform:translate3d(-40px,0,0)}[data-transition=circular] .glare-slide--current{animation:glare-circular var(--glare-transition-duration) var(--glare-ease)}[data-transition=tube] .glare-slide--current{animation:glare-tube var(--glare-transition-duration) var(--glare-ease)}[data-transition=rotate] .glare-slide--current{animation:glare-rotate var(--glare-transition-duration) var(--glare-ease)}[data-transition=zoom-in-out] .glare-slide--current{animation:glare-zoom-in-out var(--glare-transition-duration) var(--glare-ease)}@keyframes glare-circular{0%{transform:scale(.85) rotate(-8deg);opacity:0}}@keyframes glare-tube{0%{transform:scaleX(.2);opacity:0}}@keyframes glare-rotate{0%{transform:rotate(12deg) scale(.92);opacity:0}}@keyframes glare-zoom-in-out{0%{transform:scale(1.18);opacity:0}}@media(prefers-reduced-motion:reduce){.glare-container,.glare-container *{transition:none!important;animation:none!important}}@media(max-width:720px){.glare-container{--glare-button-size: 40px;--glare-inset-top: 56px;--glare-inset-x: 16px;--glare-inset-bottom: max(96px, var(--glare-thumbs-inset))}.glare-slide:where(:not(.glare-slide--image)){--glare-inset-top: 15px;--glare-inset-x: 15px;--glare-inset-bottom: max(15px, var(--glare-thumbs-inset))}.glare-toolbar{top:8px;right:8px;gap:4px;padding:3px}.glare-close-small{top:8px;right:8px}.glare-infobar{top:12px;left:12px;font-size:12px}.glare-button--prev,.glare-button--next{width:44px;height:44px}.glare-button--prev{left:8px}.glare-button--next{right:8px}.glare-thumbs--y,.glare-thumbs-axis-y [data-glare-thumbs]{display:none}.glare-show-thumbs.glare-thumbs-axis-y{--glare-inset-x: 16px}}
|