React Slides

* Adds useState
* State
* useEffect
* Side Effects
This commit is contained in:
2024-02-05 04:15:02 +05:30
commit f05a472585
42 changed files with 2979 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

15
.prettierrc Normal file
View File

@@ -0,0 +1,15 @@
{
"semi": false,
"useTabs": true,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],
"overrides": [
{
"files": "*.svelte",
"options": { "parser": "svelte" }
}
]
}

3
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"recommendations": ["svelte.svelte-vscode"]
}

23
README.md Normal file
View File

@@ -0,0 +1,23 @@
# Animotion
This is an Animotion presentation.
## Setup
Install dependencies.
```sh
pnpm i
```
Run the development server at http://localhost:5173/.
```sh
pnpm run dev
```
Build and preview deploy.
```sh
pnpm run build && pnpm run preview
```

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="https://fav.farm/🪄" />
<title>Animotion</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

37
package.json Normal file
View File

@@ -0,0 +1,37 @@
{
"name": "animotion",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^2.5.2",
"@tsconfig/svelte": "^5.0.2",
"@types/d3-interpolate": "^3.0.4",
"@types/node": "^20.9.0",
"@types/reveal.js": "^4.4.6",
"autoprefixer": "^10.4.16",
"postcss": "^8.4.31",
"postcss-load-config": "^4.0.1",
"prettier": "^3.1.0",
"prettier-plugin-svelte": "^3.1.0",
"prettier-plugin-tailwindcss": "^0.5.7",
"svelte": "^4.2.3",
"svelte-check": "^3.6.0",
"tailwindcss": "^3.3.5",
"tslib": "^2.6.2",
"typescript": "^5.2.2",
"vite": "^4.5.0"
},
"dependencies": {
"@fontsource-variable/jetbrains-mono": "^5.0.18",
"@fontsource-variable/manrope": "^5.0.17",
"d3-interpolate": "^3.0.1",
"reveal.js": "^5.0.2"
}
}

1487
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

13
postcss.config.js Normal file
View File

@@ -0,0 +1,13 @@
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer,
],
}
export default config

11
src/<!DOCTYPE html>.html Normal file
View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Indrajith Makes Games</title>
</head>
<body>
<h4>Site Under Maintenance</h4>
</body>
</html>

52
src/config.ts Normal file
View File

@@ -0,0 +1,52 @@
import Markdown from 'reveal.js/plugin/markdown/markdown'
import Highlight from 'reveal.js/plugin/highlight/highlight'
import Math from 'reveal.js/plugin/math/math'
import Notes from 'reveal.js/plugin/notes/notes'
import { registerLanguages } from '@languages'
const options: Reveal.Options = {
// presentation size respecting aspect ratio
width: 960,
height: 700,
// content padding
margin: 0.04,
// smallest and largest possible scale
minScale: 0.2,
maxScale: 2.0,
// plugins
plugins: [Markdown, Highlight, Math.KaTeX, Notes],
// syntax highlight options
highlight: {
// add new languages
beforeHighlight: registerLanguages,
// disable automatic syntax highlighting
highlightOnLoad: false,
},
// slide controls
controls: true,
// slide progress bar
progress: true,
// slide transition
transition: 'slide',
// bring your own layout
disableLayout: false,
// display mode used to show slides
display: 'block',
// center slides on the screen
center: true,
// auto-animate duration
autoAnimateDuration: 1,
// auto-animate easing
autoAnimateEasing: 'ease',
// animate unmatched elements
autoAnimateUnmatched: true,
// hide cursor
hideInactiveCursor: true,
// time before cursor is hidden (ms)
hideCursorTime: 5000,
// show current slide
hash: true,
}
export default options

6
src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
declare namespace svelteHTML {
interface HTMLAttributes<T> {
'on:in'?: (event: CustomEvent) => void
'on:out'?: (event: CustomEvent) => void
}
}

View File

@@ -0,0 +1,22 @@
<script lang="ts">
type Lines = string | boolean | null
type Offset = string | null
type Language = string | null
export let id = 'code-animation'
export let lines: Lines = true
export let offset: Offset = null
export let lang: Language = null
delete $$restProps.class
</script>
<pre data-id={id} class={$$props.class || ''} {...$$restProps}>
<code
data-trim
data-line-numbers={lines || null}
data-ln-start-from={offset}
class="language-{lang}">
<slot />
</code>
</pre>

View File

@@ -0,0 +1,13 @@
<script lang="ts">
export let type = 'h2'
delete $$restProps.class
</script>
<svelte:element
this={type}
class="r-fit-text {$$props.class || ''}"
{...$$restProps}
>
<slot />
</svelte:element>

View File

@@ -0,0 +1,25 @@
import Code from './code.svelte'
import FitText from './fit.svelte'
import Markdown from './markdown.svelte'
import Media from './media.svelte'
import Notes from './notes.svelte'
import Presentation from './presentation.svelte'
import Slide from './slide.svelte'
import Stack from './stack.svelte'
import Step from './step.svelte'
import Stretch from './stretch.svelte'
import Vertical from './vertical.svelte'
export {
Code,
FitText,
Markdown,
Media,
Notes,
Presentation,
Slide,
Stack,
Step,
Stretch,
Vertical,
}

View File

@@ -0,0 +1,13 @@
<script lang="ts">
export let file: string | null = null
</script>
{#if file}
<section data-markdown={file} />
{:else}
<section data-markdown>
<div data-template>
<slot />
</div>
</section>
{/if}

View File

@@ -0,0 +1,22 @@
<script lang="ts">
type Bool = boolean | null
type Element = 'video' | 'img' | 'iframe'
export let type: Element
export let src: string
export let autoplay: Bool = null
export let preload: Bool = null
delete $$restProps.class
</script>
<svelte:element
this={type}
data-src={src}
data-autoplay={autoplay}
data-prelod={preload}
class={$$props.class || ''}
{...$$restProps}
>
<slot />
</svelte:element>

View File

@@ -0,0 +1,3 @@
<aside class="notes">
<slot />
</aside>

View File

@@ -0,0 +1,77 @@
<script lang="ts">
import { onMount } from 'svelte'
import Reveal from 'reveal.js'
import options from '@config'
import 'reveal.js/dist/reveal.css'
import '@styles/theme.css'
import '@styles/code.css'
onMount(() => {
// create deck instance
const deck = new Reveal(options)
// custom event listeners
const inEvent = new CustomEvent('in')
const outEvent = new CustomEvent('out')
// keep track of current slide
deck.on('slidechanged', (event) => {
if ('currentSlide' in event) {
const currentSlideEl = event.currentSlide as HTMLElement
currentSlideEl.dispatchEvent(inEvent)
}
if ('previousSlide' in event) {
const currentPreviousEl = event.previousSlide as HTMLElement
currentPreviousEl.dispatchEvent(outEvent)
}
})
deck.on('fragmentshown', (event) => {
if ('fragment' in event) {
const fragmentEl = event.fragment as HTMLElement
fragmentEl.dispatchEvent(inEvent)
}
})
deck.on('fragmenthidden', (event) => {
if ('fragment' in event) {
const fragmentEl = event.fragment as HTMLElement
fragmentEl.dispatchEvent(outEvent)
}
})
deck.initialize().then(() => {
// we pass the language to the `<Code>` block
// and higlight code blocks after initialization
highlightCodeBlocks(deck)
})
// reload page after update to avoid HMR issues
// reloadPageAfterUpdate()
})
function highlightCodeBlocks(deck: Reveal.Api) {
const highlight = deck.getPlugin('highlight')
const codeBlocks = [...document.querySelectorAll('code')]
codeBlocks.forEach((block) => {
// @ts-ignore
highlight.highlightBlock(block)
})
}
function reloadPageAfterUpdate() {
if (import.meta.hot) {
import.meta.hot.on('vite:afterUpdate', () => {
location.reload()
})
}
}
</script>
<div class="reveal">
<div class="slides">
<slot />
</div>
</div>

View File

@@ -0,0 +1,48 @@
<script lang="ts">
type Bool = boolean | null
type String = string | null
type Transition =
| 'none'
| 'fade'
| 'slide'
| 'convex'
| 'concave'
| 'zoom'
| null
export let animate: Bool = null
export let animateEasing: String = null
export let animateUnmatched: Bool = null
export let animateId: String = null
export let animateRestart: Bool = null
export let background: String = null
export let gradient: String = null
export let image: String = null
export let video: String = null
export let iframe: String = null
export let interactive: Bool = null
export let transition: Transition = null
delete $$restProps.class
</script>
<section
on:in
on:out
data-auto-animate={animate}
data-auto-animate-easing={animateEasing}
data-auto-animate-unmatched={animateUnmatched}
data-auto-animate-id={animateId}
data-auto-animate-restart={animateRestart}
data-background-color={background}
data-background-gradient={gradient}
data-background-image={image}
data-background-video={video}
data-background-iframe={iframe}
data-background-interactive={interactive}
data-transition={transition}
class={$$props.class || ''}
{...$$restProps}
>
<slot />
</section>

View File

@@ -0,0 +1,3 @@
<div class="r-stack">
<slot />
</div>

View File

@@ -0,0 +1,53 @@
<script lang="ts">
export let order: string | null = null
export let fadeIn = false
export let fadeOut = false
export let fadeUp = false
export let fadeDown = false
export let fadeLeft = false
export let fadeRight = false
export let fadeInThenOut = false
export let currentVisible = false
export let fadeInThenSemiOut = false
export let semiFadeOut = false
export let highlightRed = false
export let highlightGreen = false
export let highlightBlue = false
export let highlightCurrentRed = false
export let highlightCurrentGreen = false
export let highlightCurrentBlue = false
export let grow = false
export let shrink = false
export let strike = false
delete $$restProps.class
</script>
<p
on:in
on:out
class:fade-in={fadeIn}
class:fade-out={fadeOut}
class:fade-up={fadeUp}
class:fade-down={fadeDown}
class:fade-left={fadeLeft}
class:fade-right={fadeRight}
class:fade-in-then-out={fadeInThenOut}
class:current-visible={currentVisible}
class:fade-in-then-semi-out={fadeInThenSemiOut}
class:semi-fade-out={semiFadeOut}
class:highlight-red={highlightRed}
class:highlight-green={highlightGreen}
class:highlight-blue={highlightBlue}
class:highlight-current-red={highlightCurrentRed}
class:highlight-current-green={highlightCurrentGreen}
class:highlight-current-blue={highlightCurrentBlue}
class:grow
class:shrink
class:strike
class="fragment {$$props.class || ''}"
data-fragment-index={order}
{...$$restProps}
>
<slot />
</p>

View File

@@ -0,0 +1,13 @@
<script lang="ts">
export let type = 'p'
delete $$restProps.class
</script>
<svelte:element
this={type}
class="r-stretch {$$props.class || ''}"
{...$$restProps}
>
<slot />
</svelte:element>

View File

@@ -0,0 +1,3 @@
<section>
<slot />
</section>

View File

@@ -0,0 +1,6 @@
import { svelte } from './svelte'
import type { Hljs } from './types'
export function registerLanguages(hljs: Hljs) {
hljs.registerLanguage('svelte', svelte)
}

View File

@@ -0,0 +1,50 @@
import type { Hljs } from './types'
export function svelte(hljs: Hljs) {
return {
subLanguage: 'xml',
contains: [
hljs.COMMENT('<!--', '-->', {
relevance: 10,
}),
{
begin: /^(\s*)(<script(\s*context="module")?>)/gm,
end: /^(\s*)(<\/script>)/gm,
subLanguage: 'javascript',
excludeBegin: true,
excludeEnd: true,
contains: [
{
begin: /^(\s*)(\$:)/gm,
end: /(\s*)/gm,
className: 'keyword',
},
],
},
{
begin: /^(\s*)(<style.*>)/gm,
end: /^(\s*)(<\/style>)/gm,
subLanguage: 'css',
excludeBegin: true,
excludeEnd: true,
},
{
begin: /\{/gm,
end: /\}/gm,
subLanguage: 'javascript',
contains: [
{
begin: /[\{]/,
end: /[\}]/,
skip: true,
},
{
begin: /([#:\/@])(if|else|each|await|then|catch|debug|html)/gm,
className: 'keyword',
relevance: 10,
},
],
},
],
}
}

View File

@@ -0,0 +1,3 @@
import hljs from 'highlight.js'
export type Hljs = typeof hljs

4
src/lib/motion/index.ts Normal file
View File

@@ -0,0 +1,4 @@
import { signal } from './signal'
import { animate, all } from './utils'
export { signal, animate, all }

61
src/lib/motion/signal.ts Normal file
View File

@@ -0,0 +1,61 @@
import { tweened, type TweenedOptions } from 'svelte/motion'
import { cubicInOut } from 'svelte/easing'
import { interpolate } from 'd3-interpolate'
import type { AnimationFn, Resolve } from './types'
export function signal<TweenValues>(
values: TweenValues,
options: TweenedOptions<TweenValues> = {}
) {
const { subscribe, update, set } = tweened<TweenValues>(values, {
duration: 1000,
easing: cubicInOut,
interpolate,
...options,
})
let tasks: AnimationFn[] = []
function to(
this: any,
values: Partial<TweenValues>,
toOptions: TweenedOptions<TweenValues> = {}
) {
if (typeof values === 'object') {
tasks.push(() => update((prev) => ({ ...prev, ...values }), toOptions))
} else {
tasks.push(() => set(values, toOptions))
}
return this
}
function reset() {
set(values, { duration: 0 })
tasks = []
}
function sfx(this: any, sound: string, { volume = 0.5 } = {}) {
const audio = new Audio(sound)
audio.volume = volume
tasks.push(async () => {
audio
.play()
.catch(() =>
console.error('To play sounds interact with the page first.')
)
})
return this
}
async function then(resolve: Resolve) {
for (const task of tasks) {
await task()
}
resolve()
tasks = []
}
return { subscribe, to, reset, sfx, then }
}

2
src/lib/motion/types.ts Normal file
View File

@@ -0,0 +1,2 @@
export type AnimationFn = () => Promise<void>
export type Resolve = (value?: any) => Promise<void>

10
src/lib/motion/utils.ts Normal file
View File

@@ -0,0 +1,10 @@
import { onMount } from 'svelte'
import type { AnimationFn } from './types'
export function animate(fn: AnimationFn) {
onMount(fn)
}
export function all(...animations: AnimationFn[]) {
return Promise.all(animations)
}

56
src/lib/styles/code.css Normal file
View File

@@ -0,0 +1,56 @@
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #e4f0fb;
background-color: var(--r-background-color);
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-selector-class,
.hljs-literal,
.hljs-strong,
.hljs-name,
.hljs-string {
color: #5de4c7;
}
.hljs-code {
color: #66d9ef;
}
.hljs-class .hljs-title {
color: #add7ff;
}
.hljs-symbol,
.hljs-regexp,
.hljs-link {
color: #e4f0fb;
}
.hljs-bullet,
.hljs-subst,
.hljs-title,
.hljs-section,
.hljs-emphasis,
.hljs-type,
.hljs-built_in,
.hljs-builtin-name,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-addition,
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-attr {
color: #add7ff;
}
.hljs-comment,
.hljs-quote,
.hljs-deletion,
.hljs-meta {
color: #a6accd;
}

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

127
src/lib/styles/theme.css Normal file
View File

@@ -0,0 +1,127 @@
@import '@fontsource-variable/manrope';
@import '@fontsource-variable/jetbrains-mono';
:root {
--r-background-color: hsl(226 19% 13%);
--r-main-font: 'Manrope Variable';
--r-main-font-size: 42px;
--r-main-color: hsl(226 19% 98%);
--r-heading-font: 'Manrope';
--r-code-font: 'JetBrains Mono Variable';
--r-link-color: hsl(180 100% 50%);
}
/* required for Reveal.js to work */
#app {
display: contents;
}
.reveal-viewport {
background-color: var(--r-background-color);
}
.reveal {
color: var(--r-main-color);
font-family: var(--r-main-font);
font-size: var(--r-main-font-size);
font-weight: normal;
}
.reveal pre {
display: block;
position: relative;
margin-inline: auto;
font-family: var(--r-code-font);
font-size: 0.55em;
line-height: 1.6em;
text-align: left;
word-wrap: break-word;
}
.reveal code {
font-family: var(--r-code-font);
text-transform: none;
tab-size: 2;
}
.reveal code::-webkit-scrollbar {
display: none;
scrollbar-width: none;
}
.reveal pre code {
max-height: 600px;
display: block;
padding: 5px;
overflow: auto;
word-wrap: normal;
}
.reveal .code-wrapper {
white-space: normal;
}
.reveal .code-wrapper code {
white-space: pre;
}
.reveal table {
margin: auto;
border-collapse: collapse;
border-spacing: 0;
}
.reveal table th {
font-weight: bold;
}
.reveal table th,
.reveal table td {
padding: 0.2em 0.5em 0.2em 0.5em;
text-align: left;
border-bottom: 1px solid;
}
.reveal table th[align='center'],
.reveal table td[align='center'] {
text-align: center;
}
.reveal table th[align='right'],
.reveal table td[align='right'] {
text-align: right;
}
.reveal table tbody tr:last-child th,
.reveal table tbody tr:last-child td {
border-bottom: none;
}
.reveal sup {
vertical-align: super;
font-size: smaller;
}
.reveal sub {
vertical-align: sub;
font-size: smaller;
}
.reveal small {
display: inline-block;
font-size: 0.6em;
line-height: 1.2em;
vertical-align: top;
}
.reveal small * {
vertical-align: top;
}
.reveal .controls {
color: var(--r-link-color);
}
.reveal .progress {
color: var(--r-link-color);
}

323
src/lib/types/highlight.js/index.d.ts vendored Normal file
View File

@@ -0,0 +1,323 @@
/*
Yoinked from https://github.com/highlightjs/highlight.js/blob/main/types/index.d.ts
*/
/* eslint-disable no-unused-vars */
/* eslint-disable no-use-before-define */
// For TS consumers who use Node and don't have dom in their tsconfig lib, import the necessary types here.
/// <reference lib="dom" />
declare module 'highlight.js/private' {
import { CompiledMode, Mode, Language } from 'highlight.js'
type MatchType = 'begin' | 'end' | 'illegal'
type EnhancedMatch = RegExpMatchArray & {
rule: CompiledMode
type: MatchType
}
type AnnotatedError = Error & {
mode?: Mode | Language
languageName?: string
badRule?: Mode
}
type KeywordData = [string, number]
type KeywordDict = Record<string, KeywordData>
}
declare module 'highlight.js' {
import { KeywordDict } from 'highlight.js/private'
export type HLJSApi = PublicApi & ModesAPI
export interface VuePlugin {
install: (vue: any) => void
}
// perhaps make this an interface?
type RegexEitherOptions = {
capture?: boolean
}
interface PublicApi {
highlight: (
codeOrLanguageName: string,
optionsOrCode: string | HighlightOptions,
ignoreIllegals?: boolean
) => HighlightResult
highlightAuto: (
code: string,
languageSubset?: string[]
) => AutoHighlightResult
highlightBlock: (element: HTMLElement) => void
highlightElement: (element: HTMLElement) => void
configure: (options: Partial<HLJSOptions>) => void
initHighlighting: () => void
initHighlightingOnLoad: () => void
highlightAll: () => void
registerLanguage: (languageName: string, language: LanguageFn) => void
unregisterLanguage: (languageName: string) => void
listLanguages: () => string[]
registerAliases: (
aliasList: string | string[],
{ languageName }: { languageName: string }
) => void
getLanguage: (languageName: string) => Language | undefined
autoDetection: (languageName: string) => boolean
inherit: <T>(original: T, ...args: Record<string, any>[]) => T
addPlugin: (plugin: HLJSPlugin) => void
removePlugin: (plugin: HLJSPlugin) => void
debugMode: () => void
safeMode: () => void
versionString: string
vuePlugin: () => VuePlugin
regex: {
concat: (...args: (RegExp | string)[]) => string
lookahead: (re: RegExp | string) => string
either: (
...args:
| (RegExp | string)[]
| [...(RegExp | string)[], RegexEitherOptions]
) => string
optional: (re: RegExp | string) => string
anyNumberOfTimes: (re: RegExp | string) => string
}
newInstance: () => HLJSApi
}
interface ModesAPI {
SHEBANG: (mode?: Partial<Mode> & { binary?: string | RegExp }) => Mode
BACKSLASH_ESCAPE: Mode
QUOTE_STRING_MODE: Mode
APOS_STRING_MODE: Mode
PHRASAL_WORDS_MODE: Mode
COMMENT: (
begin: string | RegExp,
end: string | RegExp,
modeOpts?: Mode | {}
) => Mode
C_LINE_COMMENT_MODE: Mode
C_BLOCK_COMMENT_MODE: Mode
HASH_COMMENT_MODE: Mode
NUMBER_MODE: Mode
C_NUMBER_MODE: Mode
BINARY_NUMBER_MODE: Mode
REGEXP_MODE: Mode
TITLE_MODE: Mode
UNDERSCORE_TITLE_MODE: Mode
METHOD_GUARD: Mode
END_SAME_AS_BEGIN: (mode: Mode) => Mode
// built in regex
IDENT_RE: string
UNDERSCORE_IDENT_RE: string
MATCH_NOTHING_RE: string
NUMBER_RE: string
C_NUMBER_RE: string
BINARY_NUMBER_RE: string
RE_STARTERS_RE: string
}
export type LanguageFn = (hljs: HLJSApi) => Language
export type CompilerExt = (mode: Mode, parent: Mode | Language | null) => void
export interface HighlightResult {
code?: string
relevance: number
value: string
language?: string
illegal: boolean
errorRaised?: Error
// * for auto-highlight
secondBest?: Omit<HighlightResult, 'second_best'>
// private
_illegalBy?: illegalData
_emitter: Emitter
_top?: Language | CompiledMode
}
export interface AutoHighlightResult extends HighlightResult {}
export interface illegalData {
message: string
context: string
index: number
resultSoFar: string
mode: CompiledMode
}
export type BeforeHighlightContext = {
code: string
language: string
result?: HighlightResult
}
export type PluginEvent = keyof HLJSPlugin
export type HLJSPlugin = {
'after:highlight'?: (result: HighlightResult) => void
'before:highlight'?: (context: BeforeHighlightContext) => void
'after:highlightElement'?: (data: {
el: Element
result: HighlightResult
text: string
}) => void
'before:highlightElement'?: (data: {
el: Element
language: string
}) => void
// TODO: Old API, remove with v12
'after:highlightBlock'?: (data: {
block: Element
result: HighlightResult
text: string
}) => void
'before:highlightBlock'?: (data: {
block: Element
language: string
}) => void
}
interface EmitterConstructor {
new (opts: any): Emitter
}
export interface HighlightOptions {
language: string
ignoreIllegals?: boolean
}
export interface HLJSOptions {
noHighlightRe: RegExp
languageDetectRe: RegExp
classPrefix: string
cssSelector: string
languages?: string[]
__emitter: EmitterConstructor
ignoreUnescapedHTML?: boolean
throwUnescapedHTML?: boolean
}
export interface CallbackResponse {
data: Record<string, any>
ignoreMatch: () => void
isMatchIgnored: boolean
}
export type ModeCallback = (
match: RegExpMatchArray,
response: CallbackResponse
) => void
export type Language = LanguageDetail & Partial<Mode>
export interface Mode extends ModeCallbacks, ModeDetails {}
export interface LanguageDetail {
name?: string
unicodeRegex?: boolean
rawDefinition?: () => Language
aliases?: string[]
disableAutodetect?: boolean
contains: Mode[]
case_insensitive?: boolean
keywords?: string | string[] | Record<string, string | string[]>
isCompiled?: boolean
exports?: any
classNameAliases?: Record<string, string>
compilerExtensions?: CompilerExt[]
supersetOf?: string
}
// technically private, but exported for convenience as this has
// been a pretty stable API and is quite useful
export interface Emitter {
startScope(name: string): void
endScope(): void
addText(text: string): void
toHTML(): string
finalize(): void
__addSublanguage(emitter: Emitter, subLanguageName: string): void
}
export type HighlightedHTMLElement = HTMLElement & {
result?: object
secondBest?: object
parentNode: HTMLElement
}
/* modes */
interface ModeCallbacks {
'on:end'?: Function
'on:begin'?: ModeCallback
}
export interface CompiledLanguage extends LanguageDetail, CompiledMode {
isCompiled: true
contains: CompiledMode[]
keywords: Record<string, any>
}
export type CompiledScope = Record<number, string> & {
_emit?: Record<number, boolean>
_multi?: boolean
_wrap?: string
}
export type CompiledMode = Omit<Mode, 'contains'> & {
begin?: RegExp | string
end?: RegExp | string
scope?: string
contains: CompiledMode[]
keywords: KeywordDict
data: Record<string, any>
terminatorEnd: string
keywordPatternRe: RegExp
beginRe: RegExp
endRe: RegExp
illegalRe: RegExp
matcher: any
isCompiled: true
starts?: CompiledMode
parent?: CompiledMode
beginScope?: CompiledScope
endScope?: CompiledScope
}
interface ModeDetails {
begin?: RegExp | string | (RegExp | string)[]
match?: RegExp | string | (RegExp | string)[]
end?: RegExp | string | (RegExp | string)[]
// deprecated in favor of `scope`
className?: string
scope?: string | Record<number, string>
beginScope?: string | Record<number, string>
endScope?: string | Record<number, string>
contains?: ('self' | Mode)[]
endsParent?: boolean
endsWithParent?: boolean
endSameAsBegin?: boolean
skip?: boolean
excludeBegin?: boolean
excludeEnd?: boolean
returnBegin?: boolean
returnEnd?: boolean
__beforeBegin?: Function
parent?: Mode
starts?: Mode
lexemes?: string | RegExp
keywords?: string | string[] | Record<string, string | string[]>
beginKeywords?: string
relevance?: number
illegal?: string | RegExp | Array<string | RegExp>
variants?: Mode[]
cachedVariants?: Mode[]
// parsed
subLanguage?: string | string[]
isCompiled?: boolean
label?: string
}
const hljs: HLJSApi
export default hljs
}
declare module 'highlight.js/lib/languages/*' {
import { LanguageFn } from 'highlight.js'
const defineLanguage: LanguageFn
export default defineLanguage
}

8
src/main.ts Normal file
View File

@@ -0,0 +1,8 @@
import Slides from './slides.svelte'
import '@styles/tailwind.css'
const app = new Slides({
target: document.getElementById('app'),
})
export default app

276
src/slides.svelte Normal file
View File

@@ -0,0 +1,276 @@
<script lang="ts">
import {
Presentation,
Slide,
FitText,
Step,
Notes,
Media,
Code
} from '@components'
import { signal } from '@motion'
const circle = signal(
{ x: 0, y: 200, r: 80, fill: '#00ffff' },
{ duration: 2000 }
)
async function animate() {
await circle.to({ x: 400, fill: '#ffff00' }, { delay: 600 })
await circle.to({ x: 0, fill: '#00ffff' }, { delay: 300 })
}
function resetAnimation() {
circle.reset()
}
</script>
<Presentation>
<Slide animate>
<p class="font-bold text-8xl text-pink-700">React Builtin Hooks</p>
</Slide>
<!-- <Slide on:in={animate} on:out={resetAnimation} animate>
<p class="font-bold text-6xl">React Builtin Hooks</p>
<div>
<ul>
<li>useState()</li>
</ul>
</div>
</Slide> -->
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-pink-700">React Builtin Hooks</p>
<ul class="mx-auto w-[200px] list-disc">
<Step>
<li>useState()</li>
</Step>
<Step>
<li>useEffect()</li>
</Step>
<Step>
<li>useContext()</li>
</Step>
<Step>
<li>useReducer()</li>
</Step>
<Step>
<li>useRef()</li>
</Step>
<Step>
<li>useMemo()</li>
</Step>
<Step>
<li>useCallback()</li>
</Step>
</ul>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-pink-700">What is a State?</p>
<Notes>
<ul>
<li>
State is something which holds the info or details about a Component's State at a TIME
</li>
<li>
It can change over time.
</li>
<li>
Whenever the state changes the COMPONENT attached to it re-renders
</li>
</ul>
</Notes>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-pink-700">useState()</p>
<Notes>
<ul>
<li>
useState hooks allows to have state variable inside a FUNCTIONAL COMPONENT
</li>
<li>
useState ENCAPSULATES only a single value
</li>
<li>
For mulatiple values you may need to call multiple useState's
</li>
<li>
useState arguments
<ul>
<li>
Initialization of a state variable
</li>
<li>
Passing function as initial value - to calculate an initial value
</li>
</ul>
</li>
<li>
Managing multiple states
<ul>
<li>
Multi-variable's
</li>
<li>
Object as value
</li>
</ul>
</li>
</ul>
</Notes>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">Side Effects</p>
<Media
class="h-[600px] w-full"
src="https://giphy.com/embed/39sYm1hvWRPN3NxHdI"
type="iframe"
>
</Media>
<Notes>
<ul>
<li>
Something which is outside the scope of REACT
<ul>
<li>
Calling AJAX requests
</li>
<li>
Calling Web API stuffs (document.get...)
</li>
<li>
localStorage etc...
</li>
<li>
setTimeout, setInterval
</li>
</ul>
</li>
<li>
Everything which is not part of React Library
</li>
<li>
Fun Fact - What happens if you call setTimeout without any arguments
<ul>
<li>
Executes outside the execution queue
</li>
</ul>
</li>
</ul>
</Notes>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="1-3|3">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
})
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}) ← No Arguments means this will be called each time
this component re-renders
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}, []) ← An empty array as an argument will run the
effect once the component is mounted
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}, [prop1]) ← We can pass value
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}, [prop1, state1]) ← Actually we can pass multiple-values
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}, [prop1, state1]) ← This is called dependency list
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="3-4">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect"
}, [prop1, state1]) ← Effect will run whenever any
of the values on dependency list changes
`}
</Code>
</div>
</Slide>
<Slide on:in={animate} animate>
<p class="font-bold text-6xl mb-4 text-yellow-500">useEffect</p>
<div class="mx-auto w-[800px]">
<Code lang="js" lines="4-6">
{`
useEffect(() => {
document.title = "Hey There, I'm from useEffect";
return () => {
// Clean Up function 🧹
}
}, [prop1, state1]);
`}
</Code>
</div>
<Notes>
<ul>
<li>
You can do removeListeners, unsubscribes, reset layouts etc
</li>
<li>
This will be called by default when component unmouts.
</li>
</ul>
</Notes>
</Slide>
</Presentation>

2
src/vite-env.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference types="svelte" />
/// <reference types="vite/client" />

7
svelte.config.js Normal file
View File

@@ -0,0 +1,7 @@
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: [vitePreprocess()],
}

10
tailwind.config.js Normal file
View File

@@ -0,0 +1,10 @@
/** @type {import('tailwindcss').Config}*/
const config = {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {},
},
plugins: [],
}
export default config

24
tsconfig.json Normal file
View File

@@ -0,0 +1,24 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@config": ["./src/config.ts"],
"@components": ["./src/lib/components/index.ts"],
"@motion": ["./src/lib/motion/index.ts"],
"@languages": ["./src/lib/languages/index.ts"],
"@lib/*": ["./src/lib/*"],
"@stores/*": ["./src/lib/stores/*"],
"@styles/*": ["./src/lib/styles/*"]
},
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": true,
"isolatedModules": true
},
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
"references": [{ "path": "./tsconfig.node.json" }]
}

9
tsconfig.node.json Normal file
View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler"
},
"include": ["vite.config.ts"]
}

19
vite.config.ts Normal file
View File

@@ -0,0 +1,19 @@
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [svelte()],
resolve: {
alias: {
'@config': path.resolve(__dirname, './src/config.ts'),
'@components': path.resolve(__dirname, './src/lib/components/index.ts'),
'@motion': path.resolve(__dirname, './src/lib/motion/index.ts'),
'@languages': path.resolve(__dirname, './src/lib/languages/index.ts'),
'@lib': path.resolve(__dirname, './src/lib'),
'@stores': path.resolve(__dirname, './src/lib/stores'),
'@styles': path.resolve(__dirname, './src/lib/styles'),
},
},
})