tw-slide 0.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 +183 -0
- package/dist/core/Events.d.ts +8 -0
- package/dist/core/Navigation.d.ts +19 -0
- package/dist/core/State.d.ts +16 -0
- package/dist/core/TailSlide.d.ts +33 -0
- package/dist/fragments/index.d.ts +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/plugins/overview.d.ts +13 -0
- package/dist/plugins/progress.d.ts +10 -0
- package/dist/plugins/slideNumber.d.ts +10 -0
- package/dist/tailslide.es.js +564 -0
- package/dist/tailslide.umd.js +1 -0
- package/dist/transitions/index.d.ts +7 -0
- package/dist/tw-slide.css +1 -0
- package/dist/types.d.ts +99 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# tw-slide
|
|
2
|
+
|
|
3
|
+
Modern, lightweight presentation library powered by **Tailwind CSS**.
|
|
4
|
+
|
|
5
|
+
Style your slides with utility classes you already know. No themes, no config files — just HTML + Tailwind.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Tailwind-native** — style every slide with utility classes
|
|
10
|
+
- **Tiny** — ~4.5KB gzipped, zero runtime dependencies
|
|
11
|
+
- **6 transitions** — fade, slide, zoom, flip, cube, none
|
|
12
|
+
- **8 fragment animations** — fade-in, fade-up, fade-down, fade-left, fade-right, grow, shrink, highlight
|
|
13
|
+
- **Plugin system** — progress bar, slide numbers, overview mode
|
|
14
|
+
- **TypeScript-first** — full type safety and autocompletion
|
|
15
|
+
- **Keyboard & touch** — arrow keys, swipe gestures, hash navigation
|
|
16
|
+
- **Dark / light mode** — one class toggle
|
|
17
|
+
- **Accessible** — respects `prefers-reduced-motion`
|
|
18
|
+
- **Print-ready** — built-in PDF export styles
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install tw-slide
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### HTML
|
|
29
|
+
|
|
30
|
+
```html
|
|
31
|
+
<div class="ts-deck ts-dark">
|
|
32
|
+
<section class="ts-slide">
|
|
33
|
+
<div class="ts-content text-center">
|
|
34
|
+
<h1 class="text-6xl font-bold text-white">Hello, TailSlide</h1>
|
|
35
|
+
<p class="text-xl text-gray-400 mt-4">Press → to continue</p>
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
|
|
39
|
+
<section class="ts-slide">
|
|
40
|
+
<div class="ts-content">
|
|
41
|
+
<h2 class="text-4xl font-bold text-white">Fragments</h2>
|
|
42
|
+
<p class="ts-fragment text-gray-300" data-ts-animation="fade-up">I appear first</p>
|
|
43
|
+
<p class="ts-fragment text-gray-300" data-ts-animation="fade-up">I appear second</p>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
</div>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### JavaScript
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import TailSlide, { ProgressPlugin, SlideNumberPlugin, OverviewPlugin } from 'tw-slide';
|
|
53
|
+
import 'tw-slide/style.css';
|
|
54
|
+
|
|
55
|
+
const deck = new TailSlide({
|
|
56
|
+
transition: 'slide',
|
|
57
|
+
dark: true,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
deck.use(new ProgressPlugin());
|
|
61
|
+
deck.use(new SlideNumberPlugin());
|
|
62
|
+
deck.use(new OverviewPlugin());
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
new TailSlide({
|
|
69
|
+
el: '.ts-deck', // container selector or element
|
|
70
|
+
transition: 'slide', // none | fade | slide | zoom | flip | cube
|
|
71
|
+
transitionSpeed: 500, // transition duration in ms
|
|
72
|
+
easing: 'ease-in-out', // CSS easing function
|
|
73
|
+
keyboard: true, // enable keyboard navigation
|
|
74
|
+
touch: true, // enable touch/swipe
|
|
75
|
+
hash: true, // sync URL hash with current slide
|
|
76
|
+
progress: true, // show progress bar (needs ProgressPlugin)
|
|
77
|
+
slideNumber: true, // show slide numbers (needs SlideNumberPlugin)
|
|
78
|
+
dark: true, // dark mode
|
|
79
|
+
loop: false, // loop back to first slide
|
|
80
|
+
autoSlide: 0, // auto-advance interval in ms (0 = off)
|
|
81
|
+
startSlide: 0, // starting slide index
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Keyboard Shortcuts
|
|
86
|
+
|
|
87
|
+
| Key | Action |
|
|
88
|
+
|-----|--------|
|
|
89
|
+
| `→` `↓` `Space` `N` | Next slide / fragment |
|
|
90
|
+
| `←` `↑` `P` | Previous slide / fragment |
|
|
91
|
+
| `Home` | First slide |
|
|
92
|
+
| `End` | Last slide |
|
|
93
|
+
| `O` | Toggle overview mode |
|
|
94
|
+
| `Esc` | Toggle overview mode |
|
|
95
|
+
|
|
96
|
+
## Fragments
|
|
97
|
+
|
|
98
|
+
Add `ts-fragment` class to reveal elements step by step. Set animation type with `data-ts-animation`:
|
|
99
|
+
|
|
100
|
+
```html
|
|
101
|
+
<p class="ts-fragment" data-ts-animation="fade-up">Appears with fade-up</p>
|
|
102
|
+
<p class="ts-fragment" data-ts-animation="grow">Appears with grow</p>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Available animations:** `fade-in` (default), `fade-up`, `fade-down`, `fade-left`, `fade-right`, `grow`, `shrink`, `highlight`
|
|
106
|
+
|
|
107
|
+
## Plugins
|
|
108
|
+
|
|
109
|
+
### ProgressPlugin
|
|
110
|
+
|
|
111
|
+
Thin progress bar at the top of the viewport.
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
deck.use(new ProgressPlugin());
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### SlideNumberPlugin
|
|
118
|
+
|
|
119
|
+
Displays current / total slide number at bottom-right.
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
deck.use(new SlideNumberPlugin());
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### OverviewPlugin
|
|
126
|
+
|
|
127
|
+
Grid overview of all slides. Toggle with `O` key or click a slide to navigate.
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
deck.use(new OverviewPlugin());
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## API
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
deck.next(); // next fragment or slide
|
|
137
|
+
deck.prev(); // previous fragment or slide
|
|
138
|
+
deck.goTo(3); // jump to slide index
|
|
139
|
+
deck.getState(); // { currentSlide, currentFragment, totalSlides, ... }
|
|
140
|
+
deck.toggleOverview(); // toggle overview mode
|
|
141
|
+
deck.on('slide:changed', (e) => console.log(e.from, e.to));
|
|
142
|
+
deck.destroy(); // clean up
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Events
|
|
146
|
+
|
|
147
|
+
| Event | Payload |
|
|
148
|
+
|-------|---------|
|
|
149
|
+
| `slide:changed` | `{ from: number, to: number }` |
|
|
150
|
+
| `fragment:shown` | `{ slide: number, fragment: number, element: HTMLElement }` |
|
|
151
|
+
| `fragment:hidden` | `{ slide: number, fragment: number, element: HTMLElement }` |
|
|
152
|
+
| `deck:ready` | `{ totalSlides: number }` |
|
|
153
|
+
| `deck:destroyed` | `{}` |
|
|
154
|
+
| `overview:open` | `{}` |
|
|
155
|
+
| `overview:close` | `{}` |
|
|
156
|
+
|
|
157
|
+
## Custom Plugin
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import type { TailSlidePlugin, TailSlideAPI } from 'tw-slide';
|
|
161
|
+
|
|
162
|
+
class MyPlugin implements TailSlidePlugin {
|
|
163
|
+
name = 'my-plugin';
|
|
164
|
+
|
|
165
|
+
init(deck: TailSlideAPI) {
|
|
166
|
+
deck.on('slide:changed', ({ to }) => {
|
|
167
|
+
console.log(`Now on slide ${to}`);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
destroy() {}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
deck.use(new MyPlugin());
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Browser Support
|
|
178
|
+
|
|
179
|
+
All modern browsers (Chrome, Firefox, Safari, Edge). Uses [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
|
|
180
|
+
|
|
181
|
+
## License
|
|
182
|
+
|
|
183
|
+
MIT
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TailSlideEvents, EventCallback } from '../types';
|
|
2
|
+
export declare class EventEmitter {
|
|
3
|
+
private listeners;
|
|
4
|
+
on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
5
|
+
off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
6
|
+
emit<K extends keyof TailSlideEvents>(event: K, data: TailSlideEvents[K]): void;
|
|
7
|
+
removeAll(): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TailSlideAPI, TailSlideConfig } from '../types';
|
|
2
|
+
export declare class Navigation {
|
|
3
|
+
private deck;
|
|
4
|
+
private config;
|
|
5
|
+
private container;
|
|
6
|
+
private touchStartX;
|
|
7
|
+
private touchStartY;
|
|
8
|
+
private handleKeyDown;
|
|
9
|
+
private handleClick;
|
|
10
|
+
private handleTouchStart;
|
|
11
|
+
private handleTouchEnd;
|
|
12
|
+
constructor(deck: TailSlideAPI, config: Required<TailSlideConfig>);
|
|
13
|
+
private bind;
|
|
14
|
+
private onKeyDown;
|
|
15
|
+
private onClick;
|
|
16
|
+
private onTouchStart;
|
|
17
|
+
private onTouchEnd;
|
|
18
|
+
destroy(): void;
|
|
19
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DeckState } from '../types';
|
|
2
|
+
export declare class StateManager {
|
|
3
|
+
private state;
|
|
4
|
+
constructor(totalSlides: number);
|
|
5
|
+
get(): DeckState;
|
|
6
|
+
get currentSlide(): number;
|
|
7
|
+
set currentSlide(value: number);
|
|
8
|
+
get currentFragment(): number;
|
|
9
|
+
set currentFragment(value: number);
|
|
10
|
+
get totalSlides(): number;
|
|
11
|
+
set totalSlides(value: number);
|
|
12
|
+
get isOverview(): boolean;
|
|
13
|
+
set isOverview(value: boolean);
|
|
14
|
+
get isPaused(): boolean;
|
|
15
|
+
set isPaused(value: boolean);
|
|
16
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TailSlideConfig, TailSlideAPI, TailSlidePlugin, TailSlideEvents, DeckState, EventCallback } from '../types';
|
|
2
|
+
export declare class TailSlide implements TailSlideAPI {
|
|
3
|
+
private config;
|
|
4
|
+
private container;
|
|
5
|
+
private slides;
|
|
6
|
+
private events;
|
|
7
|
+
private state;
|
|
8
|
+
private navigation;
|
|
9
|
+
private plugins;
|
|
10
|
+
private fragmentManager;
|
|
11
|
+
private autoSlideTimer;
|
|
12
|
+
private hashChangeHandler;
|
|
13
|
+
constructor(config?: TailSlideConfig);
|
|
14
|
+
goTo(index: number): void;
|
|
15
|
+
next(): void;
|
|
16
|
+
prev(): void;
|
|
17
|
+
getState(): DeckState;
|
|
18
|
+
getConfig(): Required<TailSlideConfig>;
|
|
19
|
+
getContainer(): HTMLElement;
|
|
20
|
+
getSlides(): HTMLElement[];
|
|
21
|
+
getFragments(slideIndex: number): HTMLElement[];
|
|
22
|
+
on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
23
|
+
off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
24
|
+
use(plugin: TailSlidePlugin): void;
|
|
25
|
+
toggleOverview(): void;
|
|
26
|
+
destroy(): void;
|
|
27
|
+
private updateSlideClasses;
|
|
28
|
+
private clamp;
|
|
29
|
+
private getSlideFromHash;
|
|
30
|
+
private syncHash;
|
|
31
|
+
private startAutoSlide;
|
|
32
|
+
private stopAutoSlide;
|
|
33
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class FragmentManager {
|
|
2
|
+
getFragments(slide: HTMLElement): HTMLElement[];
|
|
3
|
+
show(el: HTMLElement): void;
|
|
4
|
+
hide(el: HTMLElement): void;
|
|
5
|
+
showAllUpTo(fragments: HTMLElement[], index: number): void;
|
|
6
|
+
hideAllFrom(fragments: HTMLElement[], index: number): void;
|
|
7
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { TailSlide } from './core/TailSlide';
|
|
2
|
+
export { TailSlide as default } from './core/TailSlide';
|
|
3
|
+
export { ProgressPlugin } from './plugins/progress';
|
|
4
|
+
export { SlideNumberPlugin } from './plugins/slideNumber';
|
|
5
|
+
export { OverviewPlugin } from './plugins/overview';
|
|
6
|
+
export type { TailSlideConfig, TailSlideAPI, TailSlidePlugin, TailSlideEvents, DeckState, EventCallback, TransitionType, FragmentAnimation, EasingFunction, } from './types';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TailSlidePlugin, TailSlideAPI } from '../types';
|
|
2
|
+
export declare class OverviewPlugin implements TailSlidePlugin {
|
|
3
|
+
readonly name = "overview";
|
|
4
|
+
private deck;
|
|
5
|
+
private wrapper;
|
|
6
|
+
private keyHandler;
|
|
7
|
+
private clickHandler;
|
|
8
|
+
init(deck: TailSlideAPI): void;
|
|
9
|
+
destroy(): void;
|
|
10
|
+
private toggle;
|
|
11
|
+
private wrapSlides;
|
|
12
|
+
private unwrapSlides;
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TailSlidePlugin, TailSlideAPI } from '../types';
|
|
2
|
+
export declare class ProgressPlugin implements TailSlidePlugin {
|
|
3
|
+
readonly name = "progress";
|
|
4
|
+
private bar;
|
|
5
|
+
private deck;
|
|
6
|
+
private handler;
|
|
7
|
+
init(deck: TailSlideAPI): void;
|
|
8
|
+
destroy(): void;
|
|
9
|
+
private update;
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TailSlidePlugin, TailSlideAPI } from '../types';
|
|
2
|
+
export declare class SlideNumberPlugin implements TailSlidePlugin {
|
|
3
|
+
readonly name = "slideNumber";
|
|
4
|
+
private el;
|
|
5
|
+
private deck;
|
|
6
|
+
private handler;
|
|
7
|
+
init(deck: TailSlideAPI): void;
|
|
8
|
+
destroy(): void;
|
|
9
|
+
private update;
|
|
10
|
+
}
|
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
const p = {
|
|
2
|
+
el: ".ts-deck",
|
|
3
|
+
transition: "slide",
|
|
4
|
+
transitionSpeed: 500,
|
|
5
|
+
easing: "ease-in-out",
|
|
6
|
+
keyboard: !0,
|
|
7
|
+
hash: !0,
|
|
8
|
+
progress: !0,
|
|
9
|
+
slideNumber: !0,
|
|
10
|
+
touch: !0,
|
|
11
|
+
clickToAdvance: !1,
|
|
12
|
+
autoSlide: 0,
|
|
13
|
+
loop: !1,
|
|
14
|
+
startSlide: 0,
|
|
15
|
+
dark: !0,
|
|
16
|
+
deckClass: ""
|
|
17
|
+
};
|
|
18
|
+
class m {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
21
|
+
}
|
|
22
|
+
on(t, e) {
|
|
23
|
+
this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(e);
|
|
24
|
+
}
|
|
25
|
+
off(t, e) {
|
|
26
|
+
var s;
|
|
27
|
+
(s = this.listeners.get(t)) == null || s.delete(e);
|
|
28
|
+
}
|
|
29
|
+
emit(t, e) {
|
|
30
|
+
var s;
|
|
31
|
+
(s = this.listeners.get(t)) == null || s.forEach((n) => n(e));
|
|
32
|
+
}
|
|
33
|
+
removeAll() {
|
|
34
|
+
this.listeners.clear();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
class y {
|
|
38
|
+
constructor(t) {
|
|
39
|
+
this.state = {
|
|
40
|
+
currentSlide: 0,
|
|
41
|
+
currentFragment: -1,
|
|
42
|
+
totalSlides: t,
|
|
43
|
+
isOverview: !1,
|
|
44
|
+
isPaused: !1
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
get() {
|
|
48
|
+
return { ...this.state };
|
|
49
|
+
}
|
|
50
|
+
get currentSlide() {
|
|
51
|
+
return this.state.currentSlide;
|
|
52
|
+
}
|
|
53
|
+
set currentSlide(t) {
|
|
54
|
+
this.state.currentSlide = t;
|
|
55
|
+
}
|
|
56
|
+
get currentFragment() {
|
|
57
|
+
return this.state.currentFragment;
|
|
58
|
+
}
|
|
59
|
+
set currentFragment(t) {
|
|
60
|
+
this.state.currentFragment = t;
|
|
61
|
+
}
|
|
62
|
+
get totalSlides() {
|
|
63
|
+
return this.state.totalSlides;
|
|
64
|
+
}
|
|
65
|
+
set totalSlides(t) {
|
|
66
|
+
this.state.totalSlides = t;
|
|
67
|
+
}
|
|
68
|
+
get isOverview() {
|
|
69
|
+
return this.state.isOverview;
|
|
70
|
+
}
|
|
71
|
+
set isOverview(t) {
|
|
72
|
+
this.state.isOverview = t;
|
|
73
|
+
}
|
|
74
|
+
get isPaused() {
|
|
75
|
+
return this.state.isPaused;
|
|
76
|
+
}
|
|
77
|
+
set isPaused(t) {
|
|
78
|
+
this.state.isPaused = t;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const v = 50;
|
|
82
|
+
class w {
|
|
83
|
+
constructor(t, e) {
|
|
84
|
+
this.touchStartX = 0, this.touchStartY = 0, this.deck = t, this.config = e, this.container = t.getContainer(), this.handleKeyDown = this.onKeyDown.bind(this), this.handleClick = this.onClick.bind(this), this.handleTouchStart = this.onTouchStart.bind(this), this.handleTouchEnd = this.onTouchEnd.bind(this), this.bind();
|
|
85
|
+
}
|
|
86
|
+
bind() {
|
|
87
|
+
this.config.keyboard && document.addEventListener("keydown", this.handleKeyDown), this.config.clickToAdvance && this.container.addEventListener("click", this.handleClick), this.config.touch && (this.container.addEventListener("touchstart", this.handleTouchStart, {
|
|
88
|
+
passive: !0
|
|
89
|
+
}), this.container.addEventListener("touchend", this.handleTouchEnd));
|
|
90
|
+
}
|
|
91
|
+
onKeyDown(t) {
|
|
92
|
+
if (!(t.metaKey || t.ctrlKey || t.altKey))
|
|
93
|
+
switch (t.key) {
|
|
94
|
+
case "ArrowRight":
|
|
95
|
+
case "ArrowDown":
|
|
96
|
+
case " ":
|
|
97
|
+
case "n":
|
|
98
|
+
t.preventDefault(), this.deck.next();
|
|
99
|
+
break;
|
|
100
|
+
case "ArrowLeft":
|
|
101
|
+
case "ArrowUp":
|
|
102
|
+
case "p":
|
|
103
|
+
t.preventDefault(), this.deck.prev();
|
|
104
|
+
break;
|
|
105
|
+
case "Home":
|
|
106
|
+
t.preventDefault(), this.deck.goTo(0);
|
|
107
|
+
break;
|
|
108
|
+
case "End":
|
|
109
|
+
t.preventDefault(), this.deck.goTo(this.deck.getSlides().length - 1);
|
|
110
|
+
break;
|
|
111
|
+
case "Escape":
|
|
112
|
+
t.preventDefault(), this.deck.toggleOverview();
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
onClick(t) {
|
|
117
|
+
this.deck.next();
|
|
118
|
+
}
|
|
119
|
+
onTouchStart(t) {
|
|
120
|
+
const e = t.touches[0];
|
|
121
|
+
this.touchStartX = e.clientX, this.touchStartY = e.clientY;
|
|
122
|
+
}
|
|
123
|
+
onTouchEnd(t) {
|
|
124
|
+
const e = t.changedTouches[0], s = e.clientX - this.touchStartX, n = e.clientY - this.touchStartY;
|
|
125
|
+
Math.abs(s) < v || Math.abs(n) > Math.abs(s) || (t.preventDefault(), s < 0 ? this.deck.next() : this.deck.prev());
|
|
126
|
+
}
|
|
127
|
+
destroy() {
|
|
128
|
+
document.removeEventListener("keydown", this.handleKeyDown), this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("touchstart", this.handleTouchStart), this.container.removeEventListener("touchend", this.handleTouchEnd);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const S = () => typeof window < "u" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
132
|
+
function l(i, t, e) {
|
|
133
|
+
return new Promise((s) => {
|
|
134
|
+
const n = i.animate(t, e);
|
|
135
|
+
n.onfinish = () => s(), n.oncancel = () => s();
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
async function k(i, t) {
|
|
139
|
+
i && (i.style.opacity = "0", i.style.pointerEvents = "none", i.classList.remove("ts-active")), t.style.opacity = "1", t.style.pointerEvents = "auto", t.classList.add("ts-active");
|
|
140
|
+
}
|
|
141
|
+
async function E(i, t, e, s) {
|
|
142
|
+
const n = [];
|
|
143
|
+
t.style.opacity = "0", t.style.pointerEvents = "auto", t.classList.add("ts-active"), n.push(
|
|
144
|
+
l(t, [{ opacity: 0 }, { opacity: 1 }], {
|
|
145
|
+
duration: e,
|
|
146
|
+
easing: s,
|
|
147
|
+
fill: "forwards"
|
|
148
|
+
})
|
|
149
|
+
), i && n.push(
|
|
150
|
+
l(i, [{ opacity: 1 }, { opacity: 0 }], {
|
|
151
|
+
duration: e,
|
|
152
|
+
easing: s,
|
|
153
|
+
fill: "forwards"
|
|
154
|
+
}).then(() => {
|
|
155
|
+
i.style.opacity = "0", i.style.pointerEvents = "none", i.classList.remove("ts-active");
|
|
156
|
+
})
|
|
157
|
+
), await Promise.all(n), t.style.opacity = "1";
|
|
158
|
+
}
|
|
159
|
+
async function L(i, t, e, s, n) {
|
|
160
|
+
const a = n === "forward" ? "100%" : "-100%", o = n === "forward" ? "-100%" : "100%", r = [];
|
|
161
|
+
t.style.opacity = "1", t.style.pointerEvents = "auto", t.classList.add("ts-active"), r.push(
|
|
162
|
+
l(
|
|
163
|
+
t,
|
|
164
|
+
[
|
|
165
|
+
{ transform: `translateX(${a})`, opacity: 1 },
|
|
166
|
+
{ transform: "translateX(0)", opacity: 1 }
|
|
167
|
+
],
|
|
168
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
169
|
+
)
|
|
170
|
+
), i && r.push(
|
|
171
|
+
l(
|
|
172
|
+
i,
|
|
173
|
+
[
|
|
174
|
+
{ transform: "translateX(0)", opacity: 1 },
|
|
175
|
+
{ transform: `translateX(${o})`, opacity: 1 }
|
|
176
|
+
],
|
|
177
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
178
|
+
).then(() => {
|
|
179
|
+
i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active");
|
|
180
|
+
})
|
|
181
|
+
), await Promise.all(r), t.style.transform = "";
|
|
182
|
+
}
|
|
183
|
+
async function T(i, t, e, s, n) {
|
|
184
|
+
const a = n === "forward" ? "scale(0.8)" : "scale(1.2)", o = n === "forward" ? "scale(1.2)" : "scale(0.8)", r = [];
|
|
185
|
+
t.style.opacity = "0", t.style.pointerEvents = "auto", t.classList.add("ts-active"), r.push(
|
|
186
|
+
l(
|
|
187
|
+
t,
|
|
188
|
+
[
|
|
189
|
+
{ transform: a, opacity: 0 },
|
|
190
|
+
{ transform: "scale(1)", opacity: 1 }
|
|
191
|
+
],
|
|
192
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
193
|
+
)
|
|
194
|
+
), i && r.push(
|
|
195
|
+
l(
|
|
196
|
+
i,
|
|
197
|
+
[
|
|
198
|
+
{ transform: "scale(1)", opacity: 1 },
|
|
199
|
+
{ transform: o, opacity: 0 }
|
|
200
|
+
],
|
|
201
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
202
|
+
).then(() => {
|
|
203
|
+
i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active");
|
|
204
|
+
})
|
|
205
|
+
), await Promise.all(r), t.style.opacity = "1", t.style.transform = "";
|
|
206
|
+
}
|
|
207
|
+
async function b(i, t, e, s, n) {
|
|
208
|
+
const a = n === "forward" ? -180 : 180, o = n === "forward" ? 180 : -180, r = e / 2, c = t.parentElement;
|
|
209
|
+
c && (c.style.perspective = "1200px"), i && (await l(
|
|
210
|
+
i,
|
|
211
|
+
[
|
|
212
|
+
{ transform: "rotateY(0deg)", opacity: 1 },
|
|
213
|
+
{ transform: `rotateY(${o}deg)`, opacity: 0 }
|
|
214
|
+
],
|
|
215
|
+
{ duration: r, easing: s, fill: "forwards" }
|
|
216
|
+
), i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active")), t.style.pointerEvents = "auto", t.classList.add("ts-active"), await l(
|
|
217
|
+
t,
|
|
218
|
+
[
|
|
219
|
+
{ transform: `rotateY(${a}deg)`, opacity: 0 },
|
|
220
|
+
{ transform: "rotateY(0deg)", opacity: 1 }
|
|
221
|
+
],
|
|
222
|
+
{ duration: r, easing: s, fill: "forwards" }
|
|
223
|
+
), t.style.opacity = "1", t.style.transform = "";
|
|
224
|
+
}
|
|
225
|
+
async function C(i, t, e, s, n) {
|
|
226
|
+
const a = t.parentElement;
|
|
227
|
+
a && (a.style.perspective = "1200px");
|
|
228
|
+
const o = n === "forward" ? 90 : -90, r = n === "forward" ? -90 : 90, c = "translateZ(-50vw)", h = [];
|
|
229
|
+
t.style.pointerEvents = "auto", t.classList.add("ts-active"), t.style.transformOrigin = n === "forward" ? "left center" : "right center", h.push(
|
|
230
|
+
l(
|
|
231
|
+
t,
|
|
232
|
+
[
|
|
233
|
+
{
|
|
234
|
+
transform: `${c} rotateY(${o}deg)`,
|
|
235
|
+
opacity: 0.6
|
|
236
|
+
},
|
|
237
|
+
{ transform: "translateZ(0) rotateY(0deg)", opacity: 1 }
|
|
238
|
+
],
|
|
239
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
240
|
+
).then(() => {
|
|
241
|
+
t.style.opacity = "1", t.style.transform = "", t.style.transformOrigin = "";
|
|
242
|
+
})
|
|
243
|
+
), i && (i.style.transformOrigin = n === "forward" ? "right center" : "left center", h.push(
|
|
244
|
+
l(
|
|
245
|
+
i,
|
|
246
|
+
[
|
|
247
|
+
{ transform: "translateZ(0) rotateY(0deg)", opacity: 1 },
|
|
248
|
+
{
|
|
249
|
+
transform: `${c} rotateY(${r}deg)`,
|
|
250
|
+
opacity: 0.6
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
{ duration: e, easing: s, fill: "forwards" }
|
|
254
|
+
).then(() => {
|
|
255
|
+
i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.style.transformOrigin = "", i.classList.remove("ts-active");
|
|
256
|
+
})
|
|
257
|
+
)), await Promise.all(h);
|
|
258
|
+
}
|
|
259
|
+
async function A(i, t, e, s) {
|
|
260
|
+
const n = S() ? "none" : e, { duration: a, easing: o, direction: r = "forward" } = s;
|
|
261
|
+
switch (n) {
|
|
262
|
+
case "none":
|
|
263
|
+
return k(i, t);
|
|
264
|
+
case "fade":
|
|
265
|
+
return E(i, t, a, o);
|
|
266
|
+
case "slide":
|
|
267
|
+
return L(i, t, a, o, r);
|
|
268
|
+
case "zoom":
|
|
269
|
+
return T(i, t, a, o, r);
|
|
270
|
+
case "flip":
|
|
271
|
+
return b(i, t, a, o, r);
|
|
272
|
+
case "cube":
|
|
273
|
+
return C(i, t, a, o, r);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const d = 300, u = "ease-out";
|
|
277
|
+
function f(i) {
|
|
278
|
+
switch (i) {
|
|
279
|
+
case "fade-in":
|
|
280
|
+
return {
|
|
281
|
+
from: { opacity: 0 },
|
|
282
|
+
to: { opacity: 1 }
|
|
283
|
+
};
|
|
284
|
+
case "fade-up":
|
|
285
|
+
return {
|
|
286
|
+
from: { opacity: 0, transform: "translateY(20px)" },
|
|
287
|
+
to: { opacity: 1, transform: "translateY(0)" }
|
|
288
|
+
};
|
|
289
|
+
case "fade-down":
|
|
290
|
+
return {
|
|
291
|
+
from: { opacity: 0, transform: "translateY(-20px)" },
|
|
292
|
+
to: { opacity: 1, transform: "translateY(0)" }
|
|
293
|
+
};
|
|
294
|
+
case "fade-left":
|
|
295
|
+
return {
|
|
296
|
+
from: { opacity: 0, transform: "translateX(20px)" },
|
|
297
|
+
to: { opacity: 1, transform: "translateX(0)" }
|
|
298
|
+
};
|
|
299
|
+
case "fade-right":
|
|
300
|
+
return {
|
|
301
|
+
from: { opacity: 0, transform: "translateX(-20px)" },
|
|
302
|
+
to: { opacity: 1, transform: "translateX(0)" }
|
|
303
|
+
};
|
|
304
|
+
case "grow":
|
|
305
|
+
return {
|
|
306
|
+
from: { opacity: 0, transform: "scale(0.5)" },
|
|
307
|
+
to: { opacity: 1, transform: "scale(1)" }
|
|
308
|
+
};
|
|
309
|
+
case "shrink":
|
|
310
|
+
return {
|
|
311
|
+
from: { opacity: 0, transform: "scale(1.5)" },
|
|
312
|
+
to: { opacity: 1, transform: "scale(1)" }
|
|
313
|
+
};
|
|
314
|
+
case "highlight":
|
|
315
|
+
return {
|
|
316
|
+
from: { backgroundColor: "transparent" },
|
|
317
|
+
to: { backgroundColor: "rgba(255, 213, 79, 0.4)" }
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function g(i) {
|
|
322
|
+
return i.dataset.tsAnimation || "fade-in";
|
|
323
|
+
}
|
|
324
|
+
class F {
|
|
325
|
+
getFragments(t) {
|
|
326
|
+
const e = t.querySelectorAll(".ts-fragment");
|
|
327
|
+
return Array.from(e).sort((s, n) => {
|
|
328
|
+
const a = parseInt(s.dataset.tsIndex || "0", 10), o = parseInt(n.dataset.tsIndex || "0", 10);
|
|
329
|
+
return a !== o ? a - o : 0;
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
show(t) {
|
|
333
|
+
const e = g(t), { from: s, to: n } = f(e);
|
|
334
|
+
t.classList.add("ts-fragment-visible"), t.animate([s, n], {
|
|
335
|
+
duration: d,
|
|
336
|
+
easing: u,
|
|
337
|
+
fill: "forwards"
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
hide(t) {
|
|
341
|
+
const e = g(t), { from: s, to: n } = f(e);
|
|
342
|
+
t.classList.remove("ts-fragment-visible"), t.animate([n, s], {
|
|
343
|
+
duration: d,
|
|
344
|
+
easing: u,
|
|
345
|
+
fill: "forwards"
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
showAllUpTo(t, e) {
|
|
349
|
+
for (let s = 0; s <= e && s < t.length; s++) {
|
|
350
|
+
const n = t[s];
|
|
351
|
+
n.classList.contains("ts-fragment-visible") || this.show(n);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
hideAllFrom(t, e) {
|
|
355
|
+
for (let s = e; s < t.length; s++) {
|
|
356
|
+
const n = t[s];
|
|
357
|
+
n.classList.contains("ts-fragment-visible") && this.hide(n);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
class H {
|
|
362
|
+
constructor(t = {}) {
|
|
363
|
+
this.slides = [], this.navigation = null, this.plugins = [], this.autoSlideTimer = null, this.hashChangeHandler = null, this.config = { ...p, ...t }, this.events = new m();
|
|
364
|
+
const e = this.config.el, s = typeof e == "string" ? document.querySelector(e) : e;
|
|
365
|
+
if (!s)
|
|
366
|
+
throw new Error(`TailSlide: container "${e}" not found`);
|
|
367
|
+
this.container = s, this.container.classList.add("ts-deck"), this.config.deckClass && this.container.classList.add(...this.config.deckClass.split(/\s+/)), this.config.dark && this.container.classList.add("ts-dark"), this.slides = Array.from(this.container.querySelectorAll(".ts-slide")), this.state = new y(this.slides.length), this.fragmentManager = new F();
|
|
368
|
+
const n = this.getSlideFromHash() ?? this.config.startSlide;
|
|
369
|
+
this.state.currentSlide = this.clamp(n), this.updateSlideClasses(), this.navigation = new w(this, this.config), this.config.hash && (this.hashChangeHandler = () => {
|
|
370
|
+
const a = this.getSlideFromHash();
|
|
371
|
+
a !== null && a !== this.state.currentSlide && this.goTo(a);
|
|
372
|
+
}, window.addEventListener("hashchange", this.hashChangeHandler), this.syncHash()), this.config.autoSlide > 0 && this.startAutoSlide(), this.events.emit("deck:ready", { totalSlides: this.slides.length });
|
|
373
|
+
}
|
|
374
|
+
// ─── Public API ────────────────────────────────────────────────
|
|
375
|
+
goTo(t) {
|
|
376
|
+
const e = this.clamp(t);
|
|
377
|
+
if (e === this.state.currentSlide) return;
|
|
378
|
+
const s = this.state.currentSlide, n = e > s ? "forward" : "backward";
|
|
379
|
+
A(
|
|
380
|
+
this.slides[s],
|
|
381
|
+
this.slides[e],
|
|
382
|
+
this.config.transition,
|
|
383
|
+
{
|
|
384
|
+
duration: this.config.transitionSpeed,
|
|
385
|
+
easing: this.config.easing,
|
|
386
|
+
direction: n
|
|
387
|
+
}
|
|
388
|
+
), this.state.currentSlide = e, this.state.currentFragment = -1, this.updateSlideClasses(), this.syncHash(), this.events.emit("slide:changed", { from: s, to: e });
|
|
389
|
+
}
|
|
390
|
+
next() {
|
|
391
|
+
if (this.state.isPaused) return;
|
|
392
|
+
const t = this.getFragments(this.state.currentSlide);
|
|
393
|
+
if (t.length > 0) {
|
|
394
|
+
const s = this.state.currentFragment + 1;
|
|
395
|
+
if (s < t.length) {
|
|
396
|
+
this.state.currentFragment = s, this.fragmentManager.show(t[s]), this.events.emit("fragment:shown", {
|
|
397
|
+
slide: this.state.currentSlide,
|
|
398
|
+
fragment: s,
|
|
399
|
+
element: t[s]
|
|
400
|
+
});
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const e = this.state.currentSlide + 1;
|
|
405
|
+
e < this.slides.length ? this.goTo(e) : this.config.loop && this.goTo(0);
|
|
406
|
+
}
|
|
407
|
+
prev() {
|
|
408
|
+
if (this.state.isPaused) return;
|
|
409
|
+
const t = this.getFragments(this.state.currentSlide);
|
|
410
|
+
if (t.length > 0 && this.state.currentFragment >= 0) {
|
|
411
|
+
const s = this.state.currentFragment;
|
|
412
|
+
this.fragmentManager.hide(t[s]), this.state.currentFragment = s - 1, this.events.emit("fragment:hidden", {
|
|
413
|
+
slide: this.state.currentSlide,
|
|
414
|
+
fragment: s,
|
|
415
|
+
element: t[s]
|
|
416
|
+
});
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const e = this.state.currentSlide - 1;
|
|
420
|
+
if (e >= 0) {
|
|
421
|
+
this.goTo(e);
|
|
422
|
+
const s = this.getFragments(e);
|
|
423
|
+
s.forEach((n) => this.fragmentManager.show(n)), this.state.currentFragment = s.length - 1;
|
|
424
|
+
} else this.config.loop && this.goTo(this.slides.length - 1);
|
|
425
|
+
}
|
|
426
|
+
getState() {
|
|
427
|
+
return this.state.get();
|
|
428
|
+
}
|
|
429
|
+
getConfig() {
|
|
430
|
+
return { ...this.config };
|
|
431
|
+
}
|
|
432
|
+
getContainer() {
|
|
433
|
+
return this.container;
|
|
434
|
+
}
|
|
435
|
+
getSlides() {
|
|
436
|
+
return [...this.slides];
|
|
437
|
+
}
|
|
438
|
+
getFragments(t) {
|
|
439
|
+
const e = this.slides[t];
|
|
440
|
+
return e ? Array.from(e.querySelectorAll(".ts-fragment")) : [];
|
|
441
|
+
}
|
|
442
|
+
on(t, e) {
|
|
443
|
+
this.events.on(t, e);
|
|
444
|
+
}
|
|
445
|
+
off(t, e) {
|
|
446
|
+
this.events.off(t, e);
|
|
447
|
+
}
|
|
448
|
+
use(t) {
|
|
449
|
+
this.plugins.push(t), t.init(this);
|
|
450
|
+
}
|
|
451
|
+
toggleOverview() {
|
|
452
|
+
this.state.isOverview = !this.state.isOverview, this.state.isOverview ? (this.container.classList.add("ts-overview"), this.events.emit("overview:open", {})) : (this.container.classList.remove("ts-overview"), this.events.emit("overview:close", {}));
|
|
453
|
+
}
|
|
454
|
+
destroy() {
|
|
455
|
+
var t;
|
|
456
|
+
this.stopAutoSlide(), (t = this.navigation) == null || t.destroy(), this.navigation = null, this.hashChangeHandler && (window.removeEventListener("hashchange", this.hashChangeHandler), this.hashChangeHandler = null), this.plugins.forEach((e) => e.destroy()), this.plugins = [], this.events.emit("deck:destroyed", {}), this.events.removeAll();
|
|
457
|
+
}
|
|
458
|
+
// ─── Private ───────────────────────────────────────────────────
|
|
459
|
+
updateSlideClasses() {
|
|
460
|
+
const t = this.state.currentSlide;
|
|
461
|
+
this.slides.forEach((s, n) => {
|
|
462
|
+
s.classList.remove("ts-active", "ts-past", "ts-future"), s.setAttribute("aria-hidden", String(n !== t)), n < t ? s.classList.add("ts-past") : n === t ? s.classList.add("ts-active") : s.classList.add("ts-future");
|
|
463
|
+
}), this.getFragments(t).forEach((s) => this.fragmentManager.hide(s)), this.state.currentFragment = -1;
|
|
464
|
+
}
|
|
465
|
+
clamp(t) {
|
|
466
|
+
return Math.max(0, Math.min(t, this.slides.length - 1));
|
|
467
|
+
}
|
|
468
|
+
getSlideFromHash() {
|
|
469
|
+
const t = window.location.hash.match(/^#\/(\d+)$/);
|
|
470
|
+
if (!t) return null;
|
|
471
|
+
const e = parseInt(t[1], 10);
|
|
472
|
+
return isNaN(e) ? null : e;
|
|
473
|
+
}
|
|
474
|
+
syncHash() {
|
|
475
|
+
if (!this.config.hash) return;
|
|
476
|
+
const t = `#/${this.state.currentSlide}`;
|
|
477
|
+
window.location.hash !== t && history.replaceState(null, "", t);
|
|
478
|
+
}
|
|
479
|
+
startAutoSlide() {
|
|
480
|
+
this.autoSlideTimer = setInterval(() => {
|
|
481
|
+
this.state.isPaused || this.next();
|
|
482
|
+
}, this.config.autoSlide);
|
|
483
|
+
}
|
|
484
|
+
stopAutoSlide() {
|
|
485
|
+
this.autoSlideTimer !== null && (clearInterval(this.autoSlideTimer), this.autoSlideTimer = null);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
class x {
|
|
489
|
+
constructor() {
|
|
490
|
+
this.name = "progress", this.bar = null, this.deck = null, this.handler = null;
|
|
491
|
+
}
|
|
492
|
+
init(t) {
|
|
493
|
+
this.deck = t, this.bar = document.createElement("div"), this.bar.className = "ts-progress", t.getContainer().appendChild(this.bar), this.handler = () => this.update(), t.on("slide:changed", this.handler), this.update();
|
|
494
|
+
}
|
|
495
|
+
destroy() {
|
|
496
|
+
var t;
|
|
497
|
+
this.handler && this.deck && this.deck.off("slide:changed", this.handler), (t = this.bar) == null || t.remove(), this.bar = null, this.deck = null, this.handler = null;
|
|
498
|
+
}
|
|
499
|
+
update() {
|
|
500
|
+
if (!this.bar || !this.deck) return;
|
|
501
|
+
const { currentSlide: t, totalSlides: e } = this.deck.getState(), s = e > 1 ? t / (e - 1) * 100 : 100;
|
|
502
|
+
this.bar.style.width = `${s}%`;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
class O {
|
|
506
|
+
constructor() {
|
|
507
|
+
this.name = "slideNumber", this.el = null, this.deck = null, this.handler = null;
|
|
508
|
+
}
|
|
509
|
+
init(t) {
|
|
510
|
+
this.deck = t, this.el = document.createElement("div"), this.el.className = "ts-slide-number", t.getContainer().appendChild(this.el), this.handler = () => this.update(), t.on("slide:changed", this.handler), this.update();
|
|
511
|
+
}
|
|
512
|
+
destroy() {
|
|
513
|
+
var t;
|
|
514
|
+
this.handler && this.deck && this.deck.off("slide:changed", this.handler), (t = this.el) == null || t.remove(), this.el = null, this.deck = null, this.handler = null;
|
|
515
|
+
}
|
|
516
|
+
update() {
|
|
517
|
+
if (!this.el || !this.deck) return;
|
|
518
|
+
const { currentSlide: t, totalSlides: e } = this.deck.getState();
|
|
519
|
+
this.el.textContent = `${t + 1} / ${e}`;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
class M {
|
|
523
|
+
constructor() {
|
|
524
|
+
this.name = "overview", this.deck = null, this.wrapper = null, this.keyHandler = null, this.clickHandler = null;
|
|
525
|
+
}
|
|
526
|
+
init(t) {
|
|
527
|
+
this.deck = t, this.keyHandler = (e) => {
|
|
528
|
+
if (e.key === "o" || e.key === "O") {
|
|
529
|
+
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
|
|
530
|
+
e.preventDefault(), this.toggle();
|
|
531
|
+
}
|
|
532
|
+
}, document.addEventListener("keydown", this.keyHandler), this.clickHandler = (e) => {
|
|
533
|
+
if (!t.getState().isOverview) return;
|
|
534
|
+
const s = e.target.closest(".ts-slide");
|
|
535
|
+
if (!s) return;
|
|
536
|
+
const a = t.getSlides().indexOf(s);
|
|
537
|
+
a !== -1 && (t.goTo(a), t.toggleOverview());
|
|
538
|
+
}, t.getContainer().addEventListener("click", this.clickHandler);
|
|
539
|
+
}
|
|
540
|
+
destroy() {
|
|
541
|
+
this.keyHandler && (document.removeEventListener("keydown", this.keyHandler), this.keyHandler = null), this.clickHandler && this.deck && (this.deck.getContainer().removeEventListener("click", this.clickHandler), this.clickHandler = null), this.unwrapSlides(), this.deck = null;
|
|
542
|
+
}
|
|
543
|
+
toggle() {
|
|
544
|
+
if (!this.deck) return;
|
|
545
|
+
this.deck.getState().isOverview ? this.unwrapSlides() : this.wrapSlides(), this.deck.toggleOverview();
|
|
546
|
+
}
|
|
547
|
+
wrapSlides() {
|
|
548
|
+
if (!this.deck || this.wrapper) return;
|
|
549
|
+
const t = this.deck.getContainer(), e = t.querySelectorAll(":scope > .ts-slide");
|
|
550
|
+
this.wrapper = document.createElement("div"), this.wrapper.className = "ts-slides-container", e.forEach((s) => this.wrapper.appendChild(s)), t.appendChild(this.wrapper);
|
|
551
|
+
}
|
|
552
|
+
unwrapSlides() {
|
|
553
|
+
if (!this.wrapper || !this.deck) return;
|
|
554
|
+
const t = this.deck.getContainer();
|
|
555
|
+
this.wrapper.querySelectorAll(".ts-slide").forEach((s) => t.appendChild(s)), this.wrapper.remove(), this.wrapper = null;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
export {
|
|
559
|
+
M as OverviewPlugin,
|
|
560
|
+
x as ProgressPlugin,
|
|
561
|
+
O as SlideNumberPlugin,
|
|
562
|
+
H as TailSlide,
|
|
563
|
+
H as default
|
|
564
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(l,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):(l=typeof globalThis<"u"?globalThis:l||self,h(l.TailSlide={}))})(this,(function(l){"use strict";const h={el:".ts-deck",transition:"slide",transitionSpeed:500,easing:"ease-in-out",keyboard:!0,hash:!0,progress:!0,slideNumber:!0,touch:!0,clickToAdvance:!1,autoSlide:0,loop:!1,startSlide:0,dark:!0,deckClass:""};class y{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var s;(s=this.listeners.get(t))==null||s.delete(e)}emit(t,e){var s;(s=this.listeners.get(t))==null||s.forEach(n=>n(e))}removeAll(){this.listeners.clear()}}class w{constructor(t){this.state={currentSlide:0,currentFragment:-1,totalSlides:t,isOverview:!1,isPaused:!1}}get(){return{...this.state}}get currentSlide(){return this.state.currentSlide}set currentSlide(t){this.state.currentSlide=t}get currentFragment(){return this.state.currentFragment}set currentFragment(t){this.state.currentFragment=t}get totalSlides(){return this.state.totalSlides}set totalSlides(t){this.state.totalSlides=t}get isOverview(){return this.state.isOverview}set isOverview(t){this.state.isOverview=t}get isPaused(){return this.state.isPaused}set isPaused(t){this.state.isPaused=t}}const S=50;class k{constructor(t,e){this.touchStartX=0,this.touchStartY=0,this.deck=t,this.config=e,this.container=t.getContainer(),this.handleKeyDown=this.onKeyDown.bind(this),this.handleClick=this.onClick.bind(this),this.handleTouchStart=this.onTouchStart.bind(this),this.handleTouchEnd=this.onTouchEnd.bind(this),this.bind()}bind(){this.config.keyboard&&document.addEventListener("keydown",this.handleKeyDown),this.config.clickToAdvance&&this.container.addEventListener("click",this.handleClick),this.config.touch&&(this.container.addEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.container.addEventListener("touchend",this.handleTouchEnd))}onKeyDown(t){if(!(t.metaKey||t.ctrlKey||t.altKey))switch(t.key){case"ArrowRight":case"ArrowDown":case" ":case"n":t.preventDefault(),this.deck.next();break;case"ArrowLeft":case"ArrowUp":case"p":t.preventDefault(),this.deck.prev();break;case"Home":t.preventDefault(),this.deck.goTo(0);break;case"End":t.preventDefault(),this.deck.goTo(this.deck.getSlides().length-1);break;case"Escape":t.preventDefault(),this.deck.toggleOverview();break}}onClick(t){this.deck.next()}onTouchStart(t){const e=t.touches[0];this.touchStartX=e.clientX,this.touchStartY=e.clientY}onTouchEnd(t){const e=t.changedTouches[0],s=e.clientX-this.touchStartX,n=e.clientY-this.touchStartY;Math.abs(s)<S||Math.abs(n)>Math.abs(s)||(t.preventDefault(),s<0?this.deck.next():this.deck.prev())}destroy(){document.removeEventListener("keydown",this.handleKeyDown),this.container.removeEventListener("click",this.handleClick),this.container.removeEventListener("touchstart",this.handleTouchStart),this.container.removeEventListener("touchend",this.handleTouchEnd)}}const E=()=>typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches;function c(i,t,e){return new Promise(s=>{const n=i.animate(t,e);n.onfinish=()=>s(),n.oncancel=()=>s()})}async function T(i,t){i&&(i.style.opacity="0",i.style.pointerEvents="none",i.classList.remove("ts-active")),t.style.opacity="1",t.style.pointerEvents="auto",t.classList.add("ts-active")}async function L(i,t,e,s){const n=[];t.style.opacity="0",t.style.pointerEvents="auto",t.classList.add("ts-active"),n.push(c(t,[{opacity:0},{opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&n.push(c(i,[{opacity:1},{opacity:0}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.classList.remove("ts-active")})),await Promise.all(n),t.style.opacity="1"}async function b(i,t,e,s,n){const a=n==="forward"?"100%":"-100%",o=n==="forward"?"-100%":"100%",r=[];t.style.opacity="1",t.style.pointerEvents="auto",t.classList.add("ts-active"),r.push(c(t,[{transform:`translateX(${a})`,opacity:1},{transform:"translateX(0)",opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&r.push(c(i,[{transform:"translateX(0)",opacity:1},{transform:`translateX(${o})`,opacity:1}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")})),await Promise.all(r),t.style.transform=""}async function C(i,t,e,s,n){const a=n==="forward"?"scale(0.8)":"scale(1.2)",o=n==="forward"?"scale(1.2)":"scale(0.8)",r=[];t.style.opacity="0",t.style.pointerEvents="auto",t.classList.add("ts-active"),r.push(c(t,[{transform:a,opacity:0},{transform:"scale(1)",opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&r.push(c(i,[{transform:"scale(1)",opacity:1},{transform:o,opacity:0}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")})),await Promise.all(r),t.style.opacity="1",t.style.transform=""}async function A(i,t,e,s,n){const a=n==="forward"?-180:180,o=n==="forward"?180:-180,r=e/2,d=t.parentElement;d&&(d.style.perspective="1200px"),i&&(await c(i,[{transform:"rotateY(0deg)",opacity:1},{transform:`rotateY(${o}deg)`,opacity:0}],{duration:r,easing:s,fill:"forwards"}),i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")),t.style.pointerEvents="auto",t.classList.add("ts-active"),await c(t,[{transform:`rotateY(${a}deg)`,opacity:0},{transform:"rotateY(0deg)",opacity:1}],{duration:r,easing:s,fill:"forwards"}),t.style.opacity="1",t.style.transform=""}async function F(i,t,e,s,n){const a=t.parentElement;a&&(a.style.perspective="1200px");const o=n==="forward"?90:-90,r=n==="forward"?-90:90,d="translateZ(-50vw)",u=[];t.style.pointerEvents="auto",t.classList.add("ts-active"),t.style.transformOrigin=n==="forward"?"left center":"right center",u.push(c(t,[{transform:`${d} rotateY(${o}deg)`,opacity:.6},{transform:"translateZ(0) rotateY(0deg)",opacity:1}],{duration:e,easing:s,fill:"forwards"}).then(()=>{t.style.opacity="1",t.style.transform="",t.style.transformOrigin=""})),i&&(i.style.transformOrigin=n==="forward"?"right center":"left center",u.push(c(i,[{transform:"translateZ(0) rotateY(0deg)",opacity:1},{transform:`${d} rotateY(${r}deg)`,opacity:.6}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.style.transformOrigin="",i.classList.remove("ts-active")}))),await Promise.all(u)}async function H(i,t,e,s){const n=E()?"none":e,{duration:a,easing:o,direction:r="forward"}=s;switch(n){case"none":return T(i,t);case"fade":return L(i,t,a,o);case"slide":return b(i,t,a,o,r);case"zoom":return C(i,t,a,o,r);case"flip":return A(i,t,a,o,r);case"cube":return F(i,t,a,o,r)}}const f=300,g="ease-out";function p(i){switch(i){case"fade-in":return{from:{opacity:0},to:{opacity:1}};case"fade-up":return{from:{opacity:0,transform:"translateY(20px)"},to:{opacity:1,transform:"translateY(0)"}};case"fade-down":return{from:{opacity:0,transform:"translateY(-20px)"},to:{opacity:1,transform:"translateY(0)"}};case"fade-left":return{from:{opacity:0,transform:"translateX(20px)"},to:{opacity:1,transform:"translateX(0)"}};case"fade-right":return{from:{opacity:0,transform:"translateX(-20px)"},to:{opacity:1,transform:"translateX(0)"}};case"grow":return{from:{opacity:0,transform:"scale(0.5)"},to:{opacity:1,transform:"scale(1)"}};case"shrink":return{from:{opacity:0,transform:"scale(1.5)"},to:{opacity:1,transform:"scale(1)"}};case"highlight":return{from:{backgroundColor:"transparent"},to:{backgroundColor:"rgba(255, 213, 79, 0.4)"}}}}function m(i){return i.dataset.tsAnimation||"fade-in"}class O{getFragments(t){const e=t.querySelectorAll(".ts-fragment");return Array.from(e).sort((s,n)=>{const a=parseInt(s.dataset.tsIndex||"0",10),o=parseInt(n.dataset.tsIndex||"0",10);return a!==o?a-o:0})}show(t){const e=m(t),{from:s,to:n}=p(e);t.classList.add("ts-fragment-visible"),t.animate([s,n],{duration:f,easing:g,fill:"forwards"})}hide(t){const e=m(t),{from:s,to:n}=p(e);t.classList.remove("ts-fragment-visible"),t.animate([n,s],{duration:f,easing:g,fill:"forwards"})}showAllUpTo(t,e){for(let s=0;s<=e&&s<t.length;s++){const n=t[s];n.classList.contains("ts-fragment-visible")||this.show(n)}}hideAllFrom(t,e){for(let s=e;s<t.length;s++){const n=t[s];n.classList.contains("ts-fragment-visible")&&this.hide(n)}}}class v{constructor(t={}){this.slides=[],this.navigation=null,this.plugins=[],this.autoSlideTimer=null,this.hashChangeHandler=null,this.config={...h,...t},this.events=new y;const e=this.config.el,s=typeof e=="string"?document.querySelector(e):e;if(!s)throw new Error(`TailSlide: container "${e}" not found`);this.container=s,this.container.classList.add("ts-deck"),this.config.deckClass&&this.container.classList.add(...this.config.deckClass.split(/\s+/)),this.config.dark&&this.container.classList.add("ts-dark"),this.slides=Array.from(this.container.querySelectorAll(".ts-slide")),this.state=new w(this.slides.length),this.fragmentManager=new O;const n=this.getSlideFromHash()??this.config.startSlide;this.state.currentSlide=this.clamp(n),this.updateSlideClasses(),this.navigation=new k(this,this.config),this.config.hash&&(this.hashChangeHandler=()=>{const a=this.getSlideFromHash();a!==null&&a!==this.state.currentSlide&&this.goTo(a)},window.addEventListener("hashchange",this.hashChangeHandler),this.syncHash()),this.config.autoSlide>0&&this.startAutoSlide(),this.events.emit("deck:ready",{totalSlides:this.slides.length})}goTo(t){const e=this.clamp(t);if(e===this.state.currentSlide)return;const s=this.state.currentSlide,n=e>s?"forward":"backward";H(this.slides[s],this.slides[e],this.config.transition,{duration:this.config.transitionSpeed,easing:this.config.easing,direction:n}),this.state.currentSlide=e,this.state.currentFragment=-1,this.updateSlideClasses(),this.syncHash(),this.events.emit("slide:changed",{from:s,to:e})}next(){if(this.state.isPaused)return;const t=this.getFragments(this.state.currentSlide);if(t.length>0){const s=this.state.currentFragment+1;if(s<t.length){this.state.currentFragment=s,this.fragmentManager.show(t[s]),this.events.emit("fragment:shown",{slide:this.state.currentSlide,fragment:s,element:t[s]});return}}const e=this.state.currentSlide+1;e<this.slides.length?this.goTo(e):this.config.loop&&this.goTo(0)}prev(){if(this.state.isPaused)return;const t=this.getFragments(this.state.currentSlide);if(t.length>0&&this.state.currentFragment>=0){const s=this.state.currentFragment;this.fragmentManager.hide(t[s]),this.state.currentFragment=s-1,this.events.emit("fragment:hidden",{slide:this.state.currentSlide,fragment:s,element:t[s]});return}const e=this.state.currentSlide-1;if(e>=0){this.goTo(e);const s=this.getFragments(e);s.forEach(n=>this.fragmentManager.show(n)),this.state.currentFragment=s.length-1}else this.config.loop&&this.goTo(this.slides.length-1)}getState(){return this.state.get()}getConfig(){return{...this.config}}getContainer(){return this.container}getSlides(){return[...this.slides]}getFragments(t){const e=this.slides[t];return e?Array.from(e.querySelectorAll(".ts-fragment")):[]}on(t,e){this.events.on(t,e)}off(t,e){this.events.off(t,e)}use(t){this.plugins.push(t),t.init(this)}toggleOverview(){this.state.isOverview=!this.state.isOverview,this.state.isOverview?(this.container.classList.add("ts-overview"),this.events.emit("overview:open",{})):(this.container.classList.remove("ts-overview"),this.events.emit("overview:close",{}))}destroy(){var t;this.stopAutoSlide(),(t=this.navigation)==null||t.destroy(),this.navigation=null,this.hashChangeHandler&&(window.removeEventListener("hashchange",this.hashChangeHandler),this.hashChangeHandler=null),this.plugins.forEach(e=>e.destroy()),this.plugins=[],this.events.emit("deck:destroyed",{}),this.events.removeAll()}updateSlideClasses(){const t=this.state.currentSlide;this.slides.forEach((s,n)=>{s.classList.remove("ts-active","ts-past","ts-future"),s.setAttribute("aria-hidden",String(n!==t)),n<t?s.classList.add("ts-past"):n===t?s.classList.add("ts-active"):s.classList.add("ts-future")}),this.getFragments(t).forEach(s=>this.fragmentManager.hide(s)),this.state.currentFragment=-1}clamp(t){return Math.max(0,Math.min(t,this.slides.length-1))}getSlideFromHash(){const t=window.location.hash.match(/^#\/(\d+)$/);if(!t)return null;const e=parseInt(t[1],10);return isNaN(e)?null:e}syncHash(){if(!this.config.hash)return;const t=`#/${this.state.currentSlide}`;window.location.hash!==t&&history.replaceState(null,"",t)}startAutoSlide(){this.autoSlideTimer=setInterval(()=>{this.state.isPaused||this.next()},this.config.autoSlide)}stopAutoSlide(){this.autoSlideTimer!==null&&(clearInterval(this.autoSlideTimer),this.autoSlideTimer=null)}}class x{constructor(){this.name="progress",this.bar=null,this.deck=null,this.handler=null}init(t){this.deck=t,this.bar=document.createElement("div"),this.bar.className="ts-progress",t.getContainer().appendChild(this.bar),this.handler=()=>this.update(),t.on("slide:changed",this.handler),this.update()}destroy(){var t;this.handler&&this.deck&&this.deck.off("slide:changed",this.handler),(t=this.bar)==null||t.remove(),this.bar=null,this.deck=null,this.handler=null}update(){if(!this.bar||!this.deck)return;const{currentSlide:t,totalSlides:e}=this.deck.getState(),s=e>1?t/(e-1)*100:100;this.bar.style.width=`${s}%`}}class P{constructor(){this.name="slideNumber",this.el=null,this.deck=null,this.handler=null}init(t){this.deck=t,this.el=document.createElement("div"),this.el.className="ts-slide-number",t.getContainer().appendChild(this.el),this.handler=()=>this.update(),t.on("slide:changed",this.handler),this.update()}destroy(){var t;this.handler&&this.deck&&this.deck.off("slide:changed",this.handler),(t=this.el)==null||t.remove(),this.el=null,this.deck=null,this.handler=null}update(){if(!this.el||!this.deck)return;const{currentSlide:t,totalSlides:e}=this.deck.getState();this.el.textContent=`${t+1} / ${e}`}}class M{constructor(){this.name="overview",this.deck=null,this.wrapper=null,this.keyHandler=null,this.clickHandler=null}init(t){this.deck=t,this.keyHandler=e=>{if(e.key==="o"||e.key==="O"){if(e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement)return;e.preventDefault(),this.toggle()}},document.addEventListener("keydown",this.keyHandler),this.clickHandler=e=>{if(!t.getState().isOverview)return;const s=e.target.closest(".ts-slide");if(!s)return;const a=t.getSlides().indexOf(s);a!==-1&&(t.goTo(a),t.toggleOverview())},t.getContainer().addEventListener("click",this.clickHandler)}destroy(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.clickHandler&&this.deck&&(this.deck.getContainer().removeEventListener("click",this.clickHandler),this.clickHandler=null),this.unwrapSlides(),this.deck=null}toggle(){if(!this.deck)return;this.deck.getState().isOverview?this.unwrapSlides():this.wrapSlides(),this.deck.toggleOverview()}wrapSlides(){if(!this.deck||this.wrapper)return;const t=this.deck.getContainer(),e=t.querySelectorAll(":scope > .ts-slide");this.wrapper=document.createElement("div"),this.wrapper.className="ts-slides-container",e.forEach(s=>this.wrapper.appendChild(s)),t.appendChild(this.wrapper)}unwrapSlides(){if(!this.wrapper||!this.deck)return;const t=this.deck.getContainer();this.wrapper.querySelectorAll(".ts-slide").forEach(s=>t.appendChild(s)),this.wrapper.remove(),this.wrapper=null}}l.OverviewPlugin=M,l.ProgressPlugin=x,l.SlideNumberPlugin=P,l.TailSlide=v,l.default=v,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TransitionType } from '../types';
|
|
2
|
+
export interface TransitionOptions {
|
|
3
|
+
duration: number;
|
|
4
|
+
easing: string;
|
|
5
|
+
direction?: 'forward' | 'backward';
|
|
6
|
+
}
|
|
7
|
+
export declare function applyTransition(from: HTMLElement | null, to: HTMLElement, type: TransitionType, options: TransitionOptions): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.ts-deck{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;font-family:ui-sans-serif,system-ui,-apple-system,sans-serif;background-color:#fff;color:#1a1a1a}.ts-deck.ts-dark{background-color:#0a0a0a;color:#f5f5f5}.ts-slide{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;padding:2rem;opacity:0;pointer-events:none;will-change:transform,opacity;z-index:0}.ts-slide.ts-active{opacity:1;pointer-events:auto;z-index:10}.ts-slide.ts-past,.ts-slide.ts-future{opacity:0;pointer-events:none}.ts-slide>.ts-content{width:100%;max-width:64rem;margin:0 auto}.ts-fragment{opacity:0;will-change:transform,opacity}.ts-fragment.ts-fragment-visible{opacity:1}.ts-progress{position:fixed;top:0;left:0;height:.1875rem;background-color:#3b82f6;transition:width .3s ease-out;z-index:50}.ts-dark .ts-progress{background-color:#60a5fa}.ts-slide-number{position:fixed;bottom:1rem;right:1rem;font-size:.875rem;line-height:1.25rem;opacity:.6;z-index:50;font-variant-numeric:tabular-nums}.ts-deck.ts-overview{overflow:auto}.ts-deck.ts-overview .ts-slide{position:relative;opacity:1;pointer-events:auto;cursor:pointer;border:2px solid transparent;border-radius:.5rem;transition:border-color .2s ease,box-shadow .2s ease}.ts-deck.ts-overview .ts-slide:hover{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f64d}.ts-deck.ts-overview .ts-slide.ts-active{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f666}.ts-overview .ts-slides-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1.5rem;padding:2rem;width:100%;min-height:100vh;align-content:start}.ts-overview .ts-slides-container .ts-slide{aspect-ratio:16 / 9;inset:auto;height:auto;padding:1rem;font-size:.5em}.ts-overview .ts-progress,.ts-overview .ts-slide-number{display:none}.ts-slide h1{font-size:clamp(1.5rem,5vw,3.5rem);font-weight:700;line-height:1.1;margin-bottom:.75em}.ts-slide h2{font-size:clamp(1.25rem,4vw,2.5rem);font-weight:600;line-height:1.2;margin-bottom:.5em}.ts-slide h3{font-size:clamp(1rem,3vw,1.75rem);font-weight:600;line-height:1.3;margin-bottom:.5em}.ts-slide p{font-size:clamp(.875rem,2vw,1.25rem);line-height:1.6;margin-bottom:.75em}.ts-slide ul,.ts-slide ol{font-size:clamp(.875rem,2vw,1.25rem);line-height:1.6;padding-left:1.5em;margin-bottom:.75em}.ts-slide li{margin-bottom:.25em}.ts-slide code{font-size:.9em;padding:.125em .375em;border-radius:.25rem;background-color:#0000000f}.ts-dark .ts-slide code{background-color:#ffffff1a}.ts-slide pre{font-size:clamp(.75rem,1.5vw,1rem);padding:1em;border-radius:.5rem;overflow-x:auto;background-color:#0000000a;margin-bottom:.75em}.ts-dark .ts-slide pre{background-color:#ffffff0f}.ts-slide pre code{padding:0;background:none}.ts-slide img{max-width:100%;height:auto;border-radius:.5rem}@media(min-width:640px){.ts-slide{padding:3rem}}@media(min-width:1024px){.ts-slide{padding:4rem}}.col-span-2{grid-column:span 2 / span 2}.row-span-2{grid-row:span 2 / span 2}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.w-10{width:2.5rem}.w-2{width:.5rem}.w-3{width:.75rem}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-xl{max-width:36rem}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-blue-500\/20{border-color:#3b82f633}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.border-pink-500\/30{border-color:#ec48994d}.border-purple-500\/20{border-color:#a855f733}.border-teal-500\/20{border-color:#14b8a633}.border-violet-500\/30{border-color:#8b5cf64d}.border-white\/\[0\.06\]{border-color:#ffffff0f}.border-white\/\[0\.08\]{border-color:#ffffff14}.bg-\[\#0d1117\]{--tw-bg-opacity: 1;background-color:rgb(13 17 23 / var(--tw-bg-opacity, 1))}.bg-\[\#111\]{--tw-bg-opacity: 1;background-color:rgb(17 17 17 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-green-500\/80{background-color:#22c55ecc}.bg-pink-500\/20{background-color:#ec489933}.bg-red-500\/80{background-color:#ef4444cc}.bg-violet-600\/20{background-color:#7c3aed33}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/\[0\.03\]{background-color:#ffffff08}.bg-white\/\[0\.04\]{background-color:#ffffff0a}.bg-white\/\[0\.06\]{background-color:#ffffff0f}.bg-yellow-500\/80{background-color:#eab308cc}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-amber-400{--tw-gradient-from: #fbbf24 var(--tw-gradient-from-position);--tw-gradient-to: rgb(251 191 36 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-400{--tw-gradient-from: #60a5fa var(--tw-gradient-from-position);--tw-gradient-to: rgb(96 165 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-600{--tw-gradient-from: #2563eb var(--tw-gradient-from-position);--tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-900\/40{--tw-gradient-from: rgb(30 58 138 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(30 58 138 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-cyan-400{--tw-gradient-from: #22d3ee var(--tw-gradient-from-position);--tw-gradient-to: rgb(34 211 238 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-400{--tw-gradient-from: #34d399 var(--tw-gradient-from-position);--tw-gradient-to: rgb(52 211 153 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-600{--tw-gradient-from: #059669 var(--tw-gradient-from-position);--tw-gradient-to: rgb(5 150 105 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-pink-400{--tw-gradient-from: #f472b6 var(--tw-gradient-from-position);--tw-gradient-to: rgb(244 114 182 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-600{--tw-gradient-from: #9333ea var(--tw-gradient-from-position);--tw-gradient-to: rgb(147 51 234 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-900\/40{--tw-gradient-from: rgb(88 28 135 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(88 28 135 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-rose-400{--tw-gradient-from: #fb7185 var(--tw-gradient-from-position);--tw-gradient-to: rgb(251 113 133 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-teal-400{--tw-gradient-from: #2dd4bf var(--tw-gradient-from-position);--tw-gradient-to: rgb(45 212 191 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-teal-900\/40{--tw-gradient-from: rgb(19 78 74 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(19 78 74 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-violet-400{--tw-gradient-from: #a78bfa var(--tw-gradient-from-position);--tw-gradient-to: rgb(167 139 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-300{--tw-gradient-from: #fde047 var(--tw-gradient-from-position);--tw-gradient-to: rgb(253 224 71 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-purple-500{--tw-gradient-to: rgb(168 85 247 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #a855f7 var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-violet-400{--tw-gradient-to: rgb(167 139 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #a78bfa var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-blue-500{--tw-gradient-to: #3b82f6 var(--tw-gradient-to-position)}.to-blue-800{--tw-gradient-to: #1e40af var(--tw-gradient-to-position)}.to-cyan-400{--tw-gradient-to: #22d3ee var(--tw-gradient-to-position)}.to-emerald-500{--tw-gradient-to: #10b981 var(--tw-gradient-to-position)}.to-emerald-900\/40{--tw-gradient-to: rgb(6 78 59 / .4) var(--tw-gradient-to-position)}.to-fuchsia-500{--tw-gradient-to: #d946ef var(--tw-gradient-to-position)}.to-indigo-900\/40{--tw-gradient-to: rgb(49 46 129 / .4) var(--tw-gradient-to-position)}.to-orange-400{--tw-gradient-to: #fb923c var(--tw-gradient-to-position)}.to-orange-500{--tw-gradient-to: #f97316 var(--tw-gradient-to-position)}.to-pink-500{--tw-gradient-to: #ec4899 var(--tw-gradient-to-position)}.to-pink-600{--tw-gradient-to: #db2777 var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to: #a855f7 var(--tw-gradient-to-position)}.to-purple-600{--tw-gradient-to: #9333ea var(--tw-gradient-to-position)}.to-red-500{--tw-gradient-to: #ef4444 var(--tw-gradient-to-position)}.to-rose-500{--tw-gradient-to: #f43f5e var(--tw-gradient-to-position)}.to-teal-700{--tw-gradient-to: #0f766e var(--tw-gradient-to-position)}.to-violet-900\/40{--tw-gradient-to: rgb(76 29 149 / .4) var(--tw-gradient-to-position)}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-6xl{font-size:3.75rem;line-height:1}.text-7xl{font-size:4.5rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-wider{letter-spacing:.05em}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-200{--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.text-blue-300{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.text-blue-300\/60{color:#93c5fd99}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-emerald-200{--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-pink-200{--tw-text-opacity: 1;color:rgb(251 207 232 / var(--tw-text-opacity, 1))}.text-pink-400{--tw-text-opacity: 1;color:rgb(244 114 182 / var(--tw-text-opacity, 1))}.text-purple-300\/60{color:#d8b4fe99}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-rose-400{--tw-text-opacity: 1;color:rgb(251 113 133 / var(--tw-text-opacity, 1))}.text-teal-300\/60{color:#5eead499}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity, 1))}.text-violet-300{--tw-text-opacity: 1;color:rgb(196 181 253 / var(--tw-text-opacity, 1))}.text-violet-400\/60{color:#a78bfa99}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-300{--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}@media print{.ts-deck{position:static;overflow:visible;background:#fff!important;color:#000!important}.ts-slide{position:relative!important;opacity:1!important;pointer-events:auto!important;page-break-after:always;page-break-inside:avoid;-moz-column-break-after:page;break-after:page;-moz-column-break-inside:avoid;break-inside:avoid;min-height:100vh;padding:2rem;z-index:auto!important}.ts-slide:last-child{page-break-after:auto;-moz-column-break-after:auto;break-after:auto}.ts-fragment{opacity:1!important;transform:none!important}.ts-progress,.ts-slide-number{display:none!important}}.hover\:border-violet-500\/40:hover{border-color:#8b5cf666}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-7xl{font-size:4.5rem;line-height:1}.md\:text-8xl{font-size:6rem;line-height:1}}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type TransitionType = 'none' | 'fade' | 'slide' | 'zoom' | 'flip' | 'cube';
|
|
2
|
+
export type FragmentAnimation = 'fade-in' | 'fade-up' | 'fade-down' | 'fade-left' | 'fade-right' | 'grow' | 'shrink' | 'highlight';
|
|
3
|
+
export type EasingFunction = 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' | string;
|
|
4
|
+
export interface TailSlideConfig {
|
|
5
|
+
/** CSS selector or element for the deck container */
|
|
6
|
+
el?: string | HTMLElement;
|
|
7
|
+
/** Default transition between slides */
|
|
8
|
+
transition?: TransitionType;
|
|
9
|
+
/** Transition duration in ms */
|
|
10
|
+
transitionSpeed?: number;
|
|
11
|
+
/** Easing function for transitions */
|
|
12
|
+
easing?: EasingFunction;
|
|
13
|
+
/** Enable keyboard navigation */
|
|
14
|
+
keyboard?: boolean;
|
|
15
|
+
/** Enable hash-based URL navigation */
|
|
16
|
+
hash?: boolean;
|
|
17
|
+
/** Show progress bar */
|
|
18
|
+
progress?: boolean;
|
|
19
|
+
/** Show slide numbers */
|
|
20
|
+
slideNumber?: boolean;
|
|
21
|
+
/** Enable touch/swipe navigation */
|
|
22
|
+
touch?: boolean;
|
|
23
|
+
/** Enable click to advance */
|
|
24
|
+
clickToAdvance?: boolean;
|
|
25
|
+
/** Auto-slide interval in ms (0 = disabled) */
|
|
26
|
+
autoSlide?: number;
|
|
27
|
+
/** Loop back to first slide after last */
|
|
28
|
+
loop?: boolean;
|
|
29
|
+
/** Start slide index (0-based) */
|
|
30
|
+
startSlide?: number;
|
|
31
|
+
/** Dark mode */
|
|
32
|
+
dark?: boolean;
|
|
33
|
+
/** Custom CSS classes for the deck */
|
|
34
|
+
deckClass?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const DEFAULT_CONFIG: Required<TailSlideConfig>;
|
|
37
|
+
export interface DeckState {
|
|
38
|
+
currentSlide: number;
|
|
39
|
+
currentFragment: number;
|
|
40
|
+
totalSlides: number;
|
|
41
|
+
isOverview: boolean;
|
|
42
|
+
isPaused: boolean;
|
|
43
|
+
}
|
|
44
|
+
export interface TailSlideEvents {
|
|
45
|
+
'slide:changed': {
|
|
46
|
+
from: number;
|
|
47
|
+
to: number;
|
|
48
|
+
};
|
|
49
|
+
'fragment:shown': {
|
|
50
|
+
slide: number;
|
|
51
|
+
fragment: number;
|
|
52
|
+
element: HTMLElement;
|
|
53
|
+
};
|
|
54
|
+
'fragment:hidden': {
|
|
55
|
+
slide: number;
|
|
56
|
+
fragment: number;
|
|
57
|
+
element: HTMLElement;
|
|
58
|
+
};
|
|
59
|
+
'deck:ready': {
|
|
60
|
+
totalSlides: number;
|
|
61
|
+
};
|
|
62
|
+
'deck:destroyed': {};
|
|
63
|
+
'overview:open': {};
|
|
64
|
+
'overview:close': {};
|
|
65
|
+
}
|
|
66
|
+
export type EventCallback<T = unknown> = (data: T) => void;
|
|
67
|
+
export interface TailSlidePlugin {
|
|
68
|
+
name: string;
|
|
69
|
+
init(deck: TailSlideAPI): void;
|
|
70
|
+
destroy(): void;
|
|
71
|
+
}
|
|
72
|
+
export interface TailSlideAPI {
|
|
73
|
+
/** Navigate to a specific slide */
|
|
74
|
+
goTo(index: number): void;
|
|
75
|
+
/** Go to next slide/fragment */
|
|
76
|
+
next(): void;
|
|
77
|
+
/** Go to previous slide/fragment */
|
|
78
|
+
prev(): void;
|
|
79
|
+
/** Get current state */
|
|
80
|
+
getState(): DeckState;
|
|
81
|
+
/** Get config */
|
|
82
|
+
getConfig(): Required<TailSlideConfig>;
|
|
83
|
+
/** Get the deck container element */
|
|
84
|
+
getContainer(): HTMLElement;
|
|
85
|
+
/** Get all slide elements */
|
|
86
|
+
getSlides(): HTMLElement[];
|
|
87
|
+
/** Get fragments for a specific slide */
|
|
88
|
+
getFragments(slideIndex: number): HTMLElement[];
|
|
89
|
+
/** Register an event listener */
|
|
90
|
+
on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
91
|
+
/** Remove an event listener */
|
|
92
|
+
off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
|
|
93
|
+
/** Register a plugin */
|
|
94
|
+
use(plugin: TailSlidePlugin): void;
|
|
95
|
+
/** Toggle overview mode */
|
|
96
|
+
toggleOverview(): void;
|
|
97
|
+
/** Destroy the instance */
|
|
98
|
+
destroy(): void;
|
|
99
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tw-slide",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Modern Tailwind-based presentation library for the web",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/tailslide.umd.js",
|
|
7
|
+
"module": "dist/tailslide.es.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/tailslide.es.js",
|
|
13
|
+
"require": "./dist/tailslide.umd.js"
|
|
14
|
+
},
|
|
15
|
+
"./style.css": "./dist/tail-slide.css"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "vite serve demo",
|
|
22
|
+
"build": "vite build",
|
|
23
|
+
"build:demo": "vite build --config vite.demo.config.ts",
|
|
24
|
+
"preview": "vite preview",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"presentation",
|
|
29
|
+
"slides",
|
|
30
|
+
"tailwind",
|
|
31
|
+
"html",
|
|
32
|
+
"javascript",
|
|
33
|
+
"typescript"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"autoprefixer": "^10.4.21",
|
|
38
|
+
"postcss": "^8.5.3",
|
|
39
|
+
"tailwindcss": "^3.4.17",
|
|
40
|
+
"typescript": "^5.7.3",
|
|
41
|
+
"vite": "^6.1.0",
|
|
42
|
+
"vite-plugin-dts": "^4.5.0"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": ""
|
|
47
|
+
}
|
|
48
|
+
}
|