199 changed files with 668 additions and 38417 deletions
+1 -64
View File
@@ -1,6 +1,6 @@
# ThothII — Project State
Last updated: 2026-09-24 (11-slide deck, consolidated project opening and final contacts).
Last updated: 2026-09-06.
This file is the short operational snapshot. Stable commands and the architecture mental model
live in `AGENTS.md`; current design and runtime contracts live under `docs/architecture/`,
@@ -12,69 +12,6 @@ Authentik, internal catalog/embedding services, and the PSD workspace repository
`docs/operations/server-upgrade-gitea-workspace-v2.md`. Treat its operator gates and rollback
requirements as mandatory; do not replace the running server stack in place.
## Presentation publishing
The deck now has 11 slides. The cover remains; “Where we started” is folded into
“What we wanted to build”, now slide 2. Its speaker notes open with the four goals,
and its existing popups include the disconnected sources and missing capabilities.
Speaker notes now read as continuous prose without titles. On slide 2 and slides
7–10, parenthesized cues identify the corresponding popup button at the start of
its paragraph or dedicated popup text. The closing slide has no popup cues.
The console reading area also omits slide and popup headings; popup controls
remain below the preview. Edits preserve the content and keep the spoken text close
to its previous length; actual delivery time still depends on rehearsal. The former
penultimate “One datamart — many questions answered” slide is removed. The ThothII
tour leads directly to “Thank you”, with both contact emails in bold 32px type.
Slide 8 now has four popups: Home page, Patient data (original PNG 3),
Dashboard catalogue (PNG 6), and Brugada dashboard (PNG 7), numbered 1–4.
Each has dedicated presenter notes; the opening explains the portal's breadth,
the limited time, and Marco and Sara's availability for an in-person or remote
follow-up. The overview uses a two-by-two grid; unused PNGs remain on disk.
Presentation PNG source (user instruction, 2026-09-23): all PNGs to import come from
`/Users/mp/Desktop/ScreenshotPresentation/ThothIIScreens/`. This is the verified on-disk
path the user refers to as `desktop/screenshot/presentation/thothIIscreens`.
Copy supplied files unchanged into `presentation/deck/screenshots/thothii/`, preserving
their embedded annotations. The 12 source PNGs retain their `01` through `12` filenames.
The shortened slide 10 tour uses PNGs 01, 02, 05, 07, 08 and 09, numbered 1–6
in the interface; unused images remain on disk. The 284-word presenter script
covers all eight phases, explicitly introduces Human in the Loop, and includes
the invitation to a longer presentation at the conference or remotely.
The planned duration is 2:50, to be confirmed by rehearsal.
Slide 11 prominently displays Marco Pancotti's and Sara Paratico's email addresses.
Local preview uses `python3 -m http.server 8000 --bind 127.0.0.1 --directory presentation`.
The first popup uses
`01-StartingPoint.png`; popup 2 uses `02-Disambiguation01.png`. Refresh the image
cache version when replacing a PNG. During the current editing session, refresh both
operational browser windows after every modification, as explicitly requested.
Popup 3 uses `05-CloseSchemaLinking.png`, popup 4 uses `07-CTE01.png`,
popup 5 uses `08-FinalSQL.png`, and popup 6 uses `09-DatamartProduction.png`.
The HTML references PNGs by relative URL: they are external static assets, not
compiled or embedded. Keep `presentation/deck/screenshots/thothii/` with the deck;
the Desktop source folder is not a runtime dependency.
On 2026-09-23, the complete source folder was backed up to
`/Users/mp/Desktop/ThothIIScreens-backup-20260923-FkCqV3/` and verified by SHA-256.
The four unused PNGs (original prefixes 02, 05, 09, and 10) were removed from the
source folder and, on 2026-09-24, from the deck after verifying backup equality.
The backup retains all 16 original PNGs under their original names. Renumbering
preserved each file's bytes; the existing Starting point images in the source and
deck differ and were each retained unchanged.
On 2026-09-24, annotated PNGs 08–12 were updated directly in the deck and verified
visually; these deck copies are newer than the Desktop source copies. Preserve
them when importing images. Their image cache version is `v=5`. Presenter notes
for popups 09–12 are also updated in `presentation/deck/index.html`. The two Snagit
comment boxes in PNG 12 share the same horizontal centre (1676.5 px in the
3830 px source image); their text is centred within each box.
The user confirmed the public AritmoLab presentation and presenter console working on
2026-09-20. Updates use the `feat/ai-etl-presentation` branch on Gitea: commit and push
locally, then the user runs `git pull --ff-only origin feat/ai-etl-presentation` in
`/var/www/aritmolab/presentation` on the remote server. No SSH tunnel is available;
the user can operate an authenticated remote terminal in VS Code. Nginx routes are
already configured, so ordinary slide updates need no Nginx reload. Exact URLs,
paths, checks and cache behavior: [Presentation publishing](docs/operations/presentation-publishing.md).
## Current product shape
ThothII is a human-in-the-loop datamart builder with three independently built layers:
+43 -21
View File
@@ -16,6 +16,8 @@ import { loadSettings } from "./settings/settings-store.js";
import { ThtRunner, type SessionRow } from "./tht/tht-runner.js";
import { WorkspaceRegistry } from "./workspaces/registry.js";
import { WorkspaceSecretStore } from "./workspaces/secret-store.js";
import { createCatalogRepository } from "./catalog/repository.js";
import type { CatalogRepository } from "./catalog/types.js";
type OperatorAction = "maintenance-activate" | "maintenance-deactivate" | "maintenance-status"
| "session-inventory" | "workflow-doctor" | "workspace-integrity"
@@ -30,7 +32,7 @@ const lifecyclePrincipal: PrincipalContext = {
isAdmin: true,
};
function operatorRunner(config: AppConfig): ThtRunner {
function operatorRunner(config: AppConfig, catalogRepository: CatalogRepository): ThtRunner {
const workspaceSecretStore = new WorkspaceSecretStore({
root: config.workspaceSecretStoreRoot,
runtimeRoot: config.workspaceSecretRuntimeRoot,
@@ -46,6 +48,7 @@ function operatorRunner(config: AppConfig): ThtRunner {
secretsFile: config.secretsFile,
secretFiles: config.secretFiles,
workspaceSecretStore,
catalogRepository,
semanticRuntime: {
internalQdrantUrl: config.internalQdrantUrl,
internalEmbeddingUrl: config.internalEmbeddingUrl,
@@ -55,36 +58,55 @@ function operatorRunner(config: AppConfig): ThtRunner {
}).withPrincipal(lifecyclePrincipal);
}
async function withOperatorRunner<T>(
config: AppConfig,
operation: (runner: ThtRunner) => Promise<T>,
): Promise<T> {
const catalogRepository = createCatalogRepository(config.catalogDatabase);
try {
return await operation(operatorRunner(config, catalogRepository));
} finally {
await catalogRepository.close?.();
}
}
async function sessionInventory(config: AppConfig): Promise<Array<Pick<SessionRow, "status" | "archived">>> {
const registry = new WorkspaceRegistry(config.workspaceRegistry);
const revisions = await registry.listRetainedSnapshots();
const runner = operatorRunner(config);
const sessions = new Map<string, SessionRow>();
for (const revision of revisions) {
for (const session of await runner.sessionList(revision.snapshotPath)) sessions.set(session.id, session);
}
return [...sessions.values()].map(({ status, archived }) => ({ status, archived: archived === true }));
return await withOperatorRunner(config, async (runner) => {
const sessions = new Map<string, SessionRow>();
for (const revision of revisions) {
for (const session of await runner.sessionList(revision.snapshotPath)) sessions.set(session.id, session);
}
return [...sessions.values()].map(({ status, archived }) => ({ status, archived: archived === true }));
});
}
async function workflowDiagnostics(config: AppConfig): Promise<{ ready: true; workspaces: number }> {
const registry = new WorkspaceRegistry(config.workspaceRegistry);
const revisions = await registry.listRetainedSnapshots();
if (revisions.length === 0) throw new Error("workflow diagnostics unavailable");
const runner = operatorRunner(config);
for (const revision of revisions) {
const result = await runner.run(["doctor", "--json"], revision.snapshotPath);
let payload: unknown;
try {
payload = JSON.parse(result.stdout);
} catch {
throw new Error("workflow diagnostics failed");
return await withOperatorRunner(config, async (runner) => {
for (const revision of revisions) {
const runtime = await runner.acquireWorkspaceRuntime(revision.snapshotPath);
try {
const result = await runner.run(["doctor", "--json"], runtime.path);
let payload: unknown;
try {
payload = JSON.parse(result.stdout);
} catch {
throw new Error("workflow diagnostics failed");
}
if (
result.code !== 0 || !payload || typeof payload !== "object"
|| (payload as { ok?: unknown }).ok !== true
) throw new Error("workflow diagnostics failed");
} finally {
runtime.release();
}
}
if (
result.code !== 0 || !payload || typeof payload !== "object"
|| (payload as { ok?: unknown }).ok !== true
) throw new Error("workflow diagnostics failed");
}
return { ready: true, workspaces: revisions.length };
return { ready: true, workspaces: revisions.length };
});
}
async function workspaceIntegrity(config: AppConfig): Promise<{
+29 -7
View File
@@ -150,13 +150,34 @@ export function sessionRoutes(
});
app.addHook("onResponse", async (req) => { admissionLeases.get(req)?.(); });
type SessionRevisionScan = {
revisions: Awaited<ReturnType<typeof d.workspaceRegistry.list>>;
retainedComplete: boolean;
};
let retainedSnapshotWarning: string | null = null;
/** Include retained historical descriptors so removed workspaces remain resumable. */
const sessionRevisions = async () => {
const sessionRevisions = async (): Promise<SessionRevisionScan> => {
const registry = d.workspaceRegistry as Partial<WorkspaceRegistry>;
if (typeof registry.listRetainedSnapshots === "function") {
return await registry.listRetainedSnapshots();
try {
const revisions = await registry.listRetainedSnapshots();
retainedSnapshotWarning = null;
return { revisions, retainedComplete: true };
} catch (error) {
// A legacy/corrupt historical snapshot must not make active sessions (and their SSE
// reviewer gates) unreachable. The registry still rejects that snapshot; this fallback
// exposes only descriptors from the verified active state and deliberately disables
// retention reconciliation because the resulting session view is incomplete.
const detail = error instanceof Error ? error.message : "unknown error";
if (retainedSnapshotWarning !== detail) {
console.warn("[sessions] retained snapshot discovery failed; using active snapshots:", detail);
retainedSnapshotWarning = detail;
}
return { revisions: await d.workspaceRegistry.list(), retainedComplete: false };
}
}
return await d.workspaceRegistry.list();
return { revisions: await d.workspaceRegistry.list(), retainedComplete: true };
};
const isNotFound = (error: unknown) =>
@@ -200,7 +221,7 @@ export function sessionRoutes(
};
let revisions: Awaited<ReturnType<typeof d.workspaceRegistry.list>>;
try {
revisions = await sessionRevisions();
({ revisions } = await sessionRevisions());
} catch (registryError) {
// Sessions created before revision pinning still live under the installation's legacy
// default config. Keep that compatibility path available when a fresh installation has
@@ -559,8 +580,8 @@ export function sessionRoutes(
? { ...principal, isAdmin: false }
: ownershipPrincipal(principal, "session.read_all");
const runner = runnerFor(scopedPrincipal);
const revisions = await sessionRevisions();
const lists = await Promise.all(revisions
const revisionScan = await sessionRevisions();
const lists = await Promise.all(revisionScan.revisions
.map((revision) => runner.sessionList(revision.snapshotPath) as Promise<SessionRow[]>));
const sessions = new Map<string, SessionRow>();
for (const row of lists.flat()) {
@@ -570,7 +591,8 @@ export function sessionRoutes(
// Only an administrator-visible complete list (or the single local principal) is safe
// input for retention. A remote per-user view can never discard another principal's pin.
const reconcileSnapshotRetention = (d.workspaceRegistry as Partial<WorkspaceRegistry>).reconcileSnapshotRetention;
const hasCompleteRetentionView = (scope === "all" || principal.issuer === "local")
const hasCompleteRetentionView = revisionScan.retainedComplete
&& (scope === "all" || principal.issuer === "local")
&& hasPermission(principal, "session.read_all");
if (hasCompleteRetentionView && typeof reconcileSnapshotRetention === "function") {
const retained = [...new Set(list
+100
View File
@@ -0,0 +1,100 @@
import { beforeEach, expect, test, vi } from "vitest";
import type { AppConfig } from "../src/config.js";
const fakes = vi.hoisted(() => ({
catalogRepository: { close: vi.fn(async () => {}) },
createCatalogRepository: vi.fn(),
runnerConfig: undefined as Record<string, unknown> | undefined,
acquireWorkspaceRuntime: vi.fn(),
releaseWorkspaceRuntime: vi.fn(),
run: vi.fn(async () => ({
code: 0,
stdout: JSON.stringify({ ok: true }),
stderr: "",
})),
}));
vi.mock("../src/catalog/repository.js", () => ({
createCatalogRepository: fakes.createCatalogRepository,
}));
vi.mock("../src/tht/tht-runner.js", () => ({
ThtRunner: class {
constructor(config: Record<string, unknown>) {
fakes.runnerConfig = config;
}
run = fakes.run;
acquireWorkspaceRuntime = fakes.acquireWorkspaceRuntime;
withPrincipal() {
return this;
}
},
}));
vi.mock("../src/workspaces/registry.js", () => ({
WorkspaceRegistry: class {
async listRetainedSnapshots() {
return [{ snapshotPath: "/data/workspace-registry/snapshots/revision/workspace.yaml" }];
}
},
}));
vi.mock("../src/workspaces/secret-store.js", () => ({
WorkspaceSecretStore: class {},
}));
import { runOperatorAction } from "../src/operator-command.js";
const config = {
catalogDatabase: { host: "catalog-db" },
workspaceSecretStoreRoot: "/data/workspace-secrets",
workspaceSecretRuntimeRoot: "/tmp/workspace-secrets",
workspaceRegistry: {
installationId: "test",
root: "/data/workspace-registry",
secretRoots: ["/run/secrets"],
},
thtBin: "/opt/venv/bin/tht",
harnessDir: "/app/harness",
dataRoot: "/data",
internalQdrantUrl: "http://qdrant:6333",
internalEmbeddingUrl: "http://embedding:11434",
internalEmbeddingModel: "qwen3-embedding:0.6b",
internalEmbeddingDimensions: 1024,
} as AppConfig;
beforeEach(() => {
fakes.catalogRepository.close.mockClear();
fakes.createCatalogRepository.mockReset();
fakes.createCatalogRepository.mockReturnValue(fakes.catalogRepository);
fakes.run.mockClear();
fakes.acquireWorkspaceRuntime.mockReset();
fakes.acquireWorkspaceRuntime.mockResolvedValue({
path: "/data/workspace-registry/snapshots/runtime/workspace.yaml",
release: fakes.releaseWorkspaceRuntime,
});
fakes.releaseWorkspaceRuntime.mockClear();
fakes.runnerConfig = undefined;
});
test("workflow doctor gives schema-v4 runtime rendering a live Catalog repository", async () => {
await expect(runOperatorAction("workflow-doctor", config)).resolves.toEqual({
ready: true,
workspaces: 1,
});
expect(fakes.createCatalogRepository).toHaveBeenCalledWith(config.catalogDatabase);
expect(fakes.runnerConfig?.catalogRepository).toBe(fakes.catalogRepository);
expect(fakes.acquireWorkspaceRuntime).toHaveBeenCalledWith(
"/data/workspace-registry/snapshots/revision/workspace.yaml",
);
expect(fakes.run).toHaveBeenCalledWith(
["doctor", "--json"],
"/data/workspace-registry/snapshots/runtime/workspace.yaml",
);
expect(fakes.releaseWorkspaceRuntime).toHaveBeenCalledOnce();
expect(fakes.catalogRepository.close).toHaveBeenCalledOnce();
});
+59
View File
@@ -364,6 +364,65 @@ test("retention scans a removed workspace's retained snapshot", async () => {
expect(response.json()).toEqual([expect.objectContaining({ id: "resumable" })]);
});
test("active sessions remain available when retained snapshot discovery is unreadable", async () => {
const activeSnapshot = "/registry/snapshots/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/active.yaml";
const retainedFailure = "invalid retained snapshot /registry/snapshots/secret/legacy.yaml";
const reconcileSnapshotRetention = vi.fn(async () => {});
const subscribed = vi.fn();
const warning = vi.spyOn(console, "warn").mockImplementation(() => {});
const manifest = {
id: "live-session", status: "open", archived: false,
workspace_id: "active", workspace_revision: "a".repeat(40),
};
const app = buildApp(loadConfig({ AUTH_MODE: "upstream", THT_HARNESS_DIR: "../harness" }), {
thtRunner: {
withPrincipal: () => ({
sessionList: async (snapshotPath: string) => {
expect(snapshotPath).toBe(activeSnapshot);
return [manifest];
},
sessionShow: async (id: string, snapshotPath?: string) => {
if (id === manifest.id && snapshotPath === activeSnapshot) return manifest;
throw new Error("session not found");
},
}),
} as any,
mgr: { get: () => undefined } as any,
hub: {
subscribe: (_id: string, _send: unknown, options: { close?: () => void }) => {
subscribed();
options.close?.();
return () => {};
},
} as any,
workspaceRegistry: {
listRetainedSnapshots: async () => { throw new Error(retainedFailure); },
list: async () => [{
id: "active", commit: "a".repeat(40), blob: "b".repeat(40), snapshotPath: activeSnapshot,
}],
reconcileSnapshotRetention,
} as any,
});
try {
const list = await app.inject({ method: "GET", url: "/sessions", headers: aliceHeaders });
const detail = await app.inject({ method: "GET", url: `/sessions/${manifest.id}`, headers: aliceHeaders });
const events = await app.inject({ method: "GET", url: `/sessions/${manifest.id}/events`, headers: aliceHeaders });
expect(list.statusCode).toBe(200);
expect(list.json()).toEqual([expect.objectContaining({ id: manifest.id, active: false })]);
expect(detail.statusCode).toBe(200);
expect(detail.json()).toMatchObject(manifest);
expect(events.statusCode).toBe(200);
expect(subscribed).toHaveBeenCalledOnce();
expect(reconcileSnapshotRetention).not.toHaveBeenCalled();
expect(list.body + detail.body + events.body).not.toContain(retainedFailure);
} finally {
warning.mockRestore();
await app.close();
}
});
test("the single local installation listing reconciles its resumable workspace pins", async () => {
const retained = vi.fn(async () => {});
const retainedRevision = "d".repeat(40);
+14 -6
View File
@@ -5,12 +5,20 @@ COPY tools/tht/go.mod tools/tht/go.sum ./
RUN go mod download
COPY tools/tht ./
RUN mkdir -p /out \
&& CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags='-s -w' -o /out/tht-windows-amd64.exe ./cmd/tht \
&& CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags='-s -w' -o /out/tht-darwin-amd64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags='-s -w' -o /out/tht-darwin-arm64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags='-s -w' -o /out/tht-linux-amd64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags='-s -w' -o /out/tht-linux-arm64 ./cmd/tht
ARG THT_VERSION=0.0.0-dev
ARG THT_COMMIT=unknown
ARG THT_BUILD_TIME=unknown
RUN linker_flags="-s -w \
-X github.com/aritmolab/thothii/tools/tht/internal/version.semanticVersion=${THT_VERSION} \
-X github.com/aritmolab/thothii/tools/tht/internal/version.commit=${THT_COMMIT} \
-X github.com/aritmolab/thothii/tools/tht/internal/version.buildTime=${THT_BUILD_TIME}" \
&& mkdir -p /out \
&& CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="$linker_flags" -o /out/tht-windows-amd64.exe ./cmd/tht \
&& CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -trimpath -ldflags="$linker_flags" -o /out/tht-darwin-amd64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -trimpath -ldflags="$linker_flags" -o /out/tht-darwin-arm64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags="$linker_flags" -o /out/tht-linux-amd64 ./cmd/tht \
&& CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -trimpath -ldflags="$linker_flags" -o /out/tht-linux-arm64 ./cmd/tht
FROM scratch AS export
COPY --from=build /out/ /
-105
View File
@@ -1,105 +0,0 @@
# Updating the AritmoLab presentation
Last confirmed by the user: 2026-09-20, after deploying commit `5217c574`.
The user reported both the presentation and presenter console working. This is
the static presentation deployment, separate from the ThothII application stack.
## Locations
- Local worktree: `/Users/mp/projects/ThothII-presentazione`.
- Source: `presentation/deck/` and `presentation/presenter/`.
- Git remote: `origin`, `https://git.tylconsulting.it/mptyl/ThothII.git`.
- Publication branch: `feat/ai-etl-presentation`.
- Remote checkout: `/var/www/aritmolab/presentation`.
Presentation:
```text
https://aritmolab.policlinicosandonato.it/presentation/
```
Presenter console:
```text
https://aritmolab.policlinicosandonato.it/presentation/presenter/
```
Give these URLs as copyable plain text when providing instructions: the user
reported difficulty clicking Markdown links.
## Routine update
1. In the local worktree, review and validate the requested presentation changes,
then commit and push the intended files to `origin/feat/ai-etl-presentation`.
Include new images, styles, scripts and presenter files. A remote pull cannot
receive changes that remain uncommitted or unpushed. Leave unrelated changes alone.
2. The user connects to the remote server and runs:
```bash
cd /var/www/aritmolab/presentation
git branch --show-current
git status --short
```
Continue only when the branch is `feat/ai-etl-presentation` and there are no
unexpected local changes. If either differs, inspect before updating; do not
reset, discard files or merge the presentation branch into another branch.
```bash
git pull --ff-only origin feat/ai-etl-presentation
git log -1 --oneline
```
3. Refresh both browser windows. Static responses advertise
`Cache-Control: public, max-age=300`, so a browser may reuse assets for five
minutes. Use a hard refresh if the old version remains visible; bump asset
query versions when changing cached JavaScript or CSS.
4. When network access is available, verify the expected version at both URLs,
including screenshots and synchronization of presenter and audience popups.
Distinguish a successful Git push from a completed remote deployment.
Changes to slides, notes, images, CSS and JavaScript need no build, application
restart or Nginx reload. A reload is necessary only if Nginx configuration changes.
## Remote access
The site was reachable from the user's Mac while connected to the VPN.
Do not use SSH tunnels for this deployment. A non-interactive direct SSH attempt
on 2026-09-20 failed authentication. The user offered an authenticated SSH session
inside VS Code, then chose to execute the remote commands personally. The normal
workflow is to push locally and provide the remote pull command to the user;
do not assume autonomous remote access or ask for passwords in chat.
## Nginx routing already configured
The existing `/presentation` route redirects to `/presentation/`.
The user supplied the original deck alias and subsequently confirmed successful
setup of the two additional routes for the console:
| URL prefix | Filesystem alias |
| --- | --- |
| `/presentation/` | `/var/www/aritmolab/presentation/presentation/deck/` |
| `/presentation/deck/` | `/var/www/aritmolab/presentation/presentation/deck/` |
| `/presentation/presenter/` | `/var/www/aritmolab/presentation/presentation/presenter/` |
These are sibling `location ^~` blocks within the site's `server` block. The
specific `deck/` route supports the console's relative links to fonts and slide
iframes. The configuration filename was not recorded.
The presentation is intentionally public static content, bypassing Django and
Authentik. Preserve its existing routing and protections: directory listings off,
`index index.html`, GET/HEAD only, five-minute cache, `nosniff`, `SAMEORIGIN`, and
`noindex, nofollow, noarchive`. Do not expose the entire repository or change
unrelated application routes.
Only if routing needs diagnosis:
```bash
sudo nginx -T 2>/dev/null | grep -n -A 12 -B 3 '/presentation'
```
Only after an intentional configuration edit:
```bash
sudo nginx -t && sudo systemctl reload nginx
```
@@ -0,0 +1,107 @@
import { expect, test, type Page, type Route } from "@playwright/test";
import { createAuthenticationStack } from "./fixtures/auth-stack.mjs";
test.describe.configure({ mode: "serial" });
test.use({ viewport: { width: 1660, height: 822 } });
let stack: Awaited<ReturnType<typeof createAuthenticationStack>>;
function json(route: Route, body: unknown) {
return route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(body),
});
}
async function signInAsAdmin(page: Page) {
const account = stack.localAccount("admin");
await page.getByLabel("Username").fill(account.username);
await page.locator('input[name="password"]').fill(account.password);
await page.getByRole("button", { name: "Sign in", exact: true }).click();
await expect(page.getByTestId("app-shell")).toBeVisible({ timeout: 30_000 });
}
test.beforeAll(async () => {
stack = await createAuthenticationStack({ withF1Workspace: true });
await stack.useLocalMode();
});
test.afterAll(async () => {
await stack?.close();
});
test("Administration stays within its rail when hosted by the Omics portal", async ({ page }) => {
await page.route("**/api/settings", (route) => json(route, {
workspace: "fixture-workspace",
provider: "zai",
model: "glm-5.2",
thinking: "medium",
}));
await page.route("**/api/workspaces", (route) => json(route, [{
id: "fixture-workspace",
name: "fixture-workspace",
file: "fixture-workspace/workspace.yaml",
displayName: "Fixture workspace",
configurationState: "ready",
revision: {
id: "fixture-workspace",
commit: "a".repeat(40),
blob: "b".repeat(40),
snapshotPath: `/snapshots/${"a".repeat(40)}/fixture-workspace.yaml`,
},
}]));
await page.route("**/api/workspaces/fixture-workspace/preprocessing", (route) => json(route, {
schemaVersion: 1,
workspaceId: "fixture-workspace",
state: "running",
actionable: false,
clearable: false,
detail: "Building schema and LSH.",
progress: {
stage: "schema_index",
step: 2,
totalSteps: 4,
},
}));
await page.goto(stack.publicUrl);
await signInAsAdmin(page);
await expect(page.getByRole("combobox", { name: "Workspace" })).toHaveValue("fixture-workspace");
// Hyper/Bootstrap and Thoth currently share the portal document. These
// utility names are therefore resolved with the portal's !important values.
await page.addStyleTag({ content: `
.px-2 { padding-right: 0.75rem !important; padding-left: 0.75rem !important; }
.px-3 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; }
.px-4 { padding-right: 2.25rem !important; padding-left: 2.25rem !important; }
` });
const rail = page.getByRole("complementary", { name: "Session navigation" });
await rail.getByRole("button", { name: "Administration", exact: true }).click();
const administration = rail.getByRole("region", { name: "Administration" });
const boundary = rail.getByTestId("administration-boundary");
await expect(administration).toBeVisible();
await expect(rail.getByText("2 / 4", { exact: true })).toBeVisible();
const containment = await administration.evaluate((panel) => {
const elements = Array.from(panel.querySelectorAll<HTMLElement>('button, [role="progressbar"], span'))
.filter((element) => element.matches('button, [role="progressbar"]') || element.textContent?.trim() === "2 / 4");
return elements.map((element) => {
const box = element.getBoundingClientRect();
return {
label: element.textContent?.trim() || element.getAttribute("aria-label") || element.tagName,
left: box.left,
right: box.right,
};
});
});
const boundaryBox = await boundary.boundingBox();
expect(boundaryBox).not.toBeNull();
if (!boundaryBox) return;
for (const item of containment) {
expect.soft(item.left, `${item.label} crosses the Administration left edge`).toBeGreaterThanOrEqual(boundaryBox.x - 1);
expect.soft(item.right, `${item.label} crosses the Administration right edge`).toBeLessThanOrEqual(boundaryBox.x + boundaryBox.width + 1);
}
});
@@ -426,12 +426,15 @@ test("context panels stay inside the manager and the Tables grid sits in a sideb
const administrationPanel = adminNavigationRail.getByRole("region", { name: "Administration" });
await expect(administrationPanel).toBeVisible();
expect(await administrationPanel.locator(":scope > *").evaluateAll((elements) => elements.map((element) => (
element.getAttribute("role") === "separator" ? "separator" : element.textContent?.trim()
element.getAttribute("role") === "separator"
? "separator"
: element.getAttribute("aria-label") ?? element.textContent?.trim()
)))).toEqual([
"Database management",
"separator",
"Workspace management",
"Pi management",
"Workspace preprocessing",
]);
await administration.click();
+15
View File
@@ -181,6 +181,21 @@
* Scoped so it never leaks into widgets.
*/
@layer components {
/* Omics Portal and Thoth share one document in the embedded deployment.
Keep rail geometry on product-specific class names so Hyper/Bootstrap's
global spacing utilities (for example .px-4 !important) cannot resize it. */
.thot-session-navigation__header {
padding: 1.25rem 1rem 0.75rem;
}
.thot-session-navigation__primary-controls {
display: flex;
min-width: 0;
flex-direction: column;
gap: 0.5rem;
padding: 0 1rem 0.75rem;
}
/* Standard micro-label: panel headers, nav sections, meta rows. Set in the
mono register so labels/meta read as a distinct typographic layer from the
sans body prose (mono needs less tracking than the sans did). */
+12 -11
View File
@@ -855,7 +855,7 @@ export function AppShell({ canLogout }: AppShellProps) {
{/* Right session rail */}
{(activeSurface === "database-management" || !showActivity) && (
<aside aria-label="Session navigation" className="flex w-64 shrink-0 flex-col bg-sidebar">
<div className="relative px-4 pb-3 pt-5 text-center">
<div className="thot-session-navigation__header relative text-center">
<h1 className="font-heading text-xl font-semibold leading-none tracking-tight text-foreground">
Thoth<span className="text-primary">II</span>
</h1>
@@ -878,11 +878,11 @@ export function AppShell({ canLogout }: AppShellProps) {
)}
</div>
<div className="flex flex-col gap-2 px-4 pb-3">
<div className="thot-session-navigation__primary-controls">
<Button
variant={currentNavigation === "core" ? "navigationActive" : "outline"}
size="sm"
className="w-full"
className="w-full min-w-0 max-w-full gap-[0.25rem] px-[0.75rem]"
aria-current={currentNavigation === "core" ? "page" : undefined}
data-navigation-state={preprocessingBlocksNewSession
? "unavailable"
@@ -897,15 +897,16 @@ export function AppShell({ canLogout }: AppShellProps) {
<Accordion.Root
value={adminNavigationValue}
onValueChange={setAdminNavigationValue}
className="rounded-lg border border-border/80 bg-card/45 p-1.5"
data-testid="administration-boundary"
className="min-w-0 max-w-full rounded-lg border border-border/80 bg-card/45 p-1.5"
>
<Accordion.Item value="administration">
<Accordion.Header className="m-0">
<Accordion.Item value="administration" className="min-w-0 max-w-full">
<Accordion.Header className="m-0 min-w-0 max-w-full">
<Accordion.Trigger
className={buttonVariants({
variant: !adminNavigationOpen && managementNavigationCurrent ? "navigationActive" : "outline",
size: "sm",
className: "w-full justify-between px-2.5",
className: "w-full min-w-0 max-w-full justify-between px-2.5",
})}
data-navigation-state={!adminNavigationOpen && managementNavigationCurrent ? "current" : "available"}
>
@@ -917,11 +918,11 @@ export function AppShell({ canLogout }: AppShellProps) {
/>
</Accordion.Trigger>
</Accordion.Header>
<Accordion.Panel className="grid gap-1.5 px-0.5 pt-1.5">
<Accordion.Panel className="grid min-w-0 max-w-full gap-1.5 px-0.5 pt-1.5">
<Button
variant={currentNavigation === "database" ? "navigationActive" : "outline"}
size="sm"
className="w-full"
className="w-full min-w-0 max-w-full gap-[0.25rem] px-[0.75rem]"
aria-current={currentNavigation === "database" ? "page" : undefined}
data-navigation-state={currentNavigation === "database" ? "current" : canManageDatabase ? "available" : "unavailable"}
disabled={!canManageDatabase}
@@ -937,7 +938,7 @@ export function AppShell({ canLogout }: AppShellProps) {
<Button
variant={currentNavigation === "workspace" ? "navigationActive" : "outline"}
size="sm"
className="w-full"
className="w-full min-w-0 max-w-full gap-[0.25rem] px-[0.75rem]"
aria-current={currentNavigation === "workspace" ? "page" : undefined}
aria-expanded={activeManagementPanel === "workspace"}
data-navigation-state={currentNavigation === "workspace" ? "current" : "available"}
@@ -952,7 +953,7 @@ export function AppShell({ canLogout }: AppShellProps) {
<Button
variant={currentNavigation === "pi" ? "navigationActive" : "outline"}
size="sm"
className="w-full"
className="w-full min-w-0 max-w-full gap-[0.25rem] px-[0.75rem]"
aria-current={currentNavigation === "pi" ? "page" : undefined}
aria-expanded={activeManagementPanel === "pi"}
data-navigation-state={currentNavigation === "pi" ? "current" : canManagePi ? "available" : "unavailable"}
@@ -57,8 +57,8 @@ function StatusIcon({ state }: { state?: WorkspacePreprocessingState }) {
function PhaseProgress({ progress }: { progress: PreprocessingProgress }) {
const step = Math.max(1, Math.min(progress.step, progress.totalSteps));
return (
<div className="col-span-2 mt-1 grid gap-1">
<div className="flex items-center justify-between gap-2 text-[9px] leading-none">
<div className="col-span-2 mt-1 grid min-w-0 max-w-full gap-1">
<div className="flex min-w-0 max-w-full items-center justify-between gap-[0.5rem] text-[9px] leading-none">
<span className="min-w-0 truncate font-medium text-foreground">
{PROGRESS_LABELS[progress.stage]}
</span>
@@ -240,7 +240,7 @@ export function WorkspacePreprocessingControl({
<section
aria-label="Workspace preprocessing"
aria-busy={state === "running" || loading || clearMutation.isPending}
className="mt-0.5 border-t border-border/90 px-0.5 pt-2"
className="mt-0.5 min-w-0 max-w-full border-t border-border/90 px-0.5 pt-2"
>
<p className="mb-2 px-0.5 font-mono text-[9px] font-semibold uppercase tracking-[0.08em] text-primary">
Preprocessing
@@ -272,11 +272,11 @@ export function WorkspacePreprocessingControl({
<span><strong className="block text-foreground">Keep</strong><small className="text-muted-foreground">Memory and solved questions</small></span>
</div>
</div>
<div className="grid grid-cols-[0.78fr_1.22fr] gap-1.5">
<Button type="button" variant="outline" size="xs" className="h-7 text-[9px]" disabled={clearMutation.isPending} onClick={() => setConfirmingClear(false)}>
<div className="grid min-w-0 max-w-full grid-cols-[minmax(0,0.78fr)_minmax(0,1.22fr)] gap-1.5">
<Button type="button" variant="outline" size="xs" className="h-7 min-w-0 max-w-full px-[0.625rem] text-[9px]" disabled={clearMutation.isPending} onClick={() => setConfirmingClear(false)}>
Cancel
</Button>
<Button type="button" variant="destructive" size="xs" className="h-7 text-[9px]" disabled={clearMutation.isPending} onClick={() => clearMutation.mutate()}>
<Button type="button" variant="destructive" size="xs" className="h-7 min-w-0 max-w-full px-[0.625rem] text-[9px]" disabled={clearMutation.isPending} onClick={() => clearMutation.mutate()}>
{clearMutation.isPending ? <LoaderCircle aria-hidden="true" className="animate-spin motion-reduce:animate-none" /> : <Trash2 aria-hidden="true" />}
{clearMutation.isPending ? "Clearing" : "Clear derived data"}
</Button>
@@ -284,7 +284,7 @@ export function WorkspacePreprocessingControl({
</div>
) : (
<>
<div className="grid grid-cols-[1.25rem_minmax(0,1fr)] items-center gap-1.5">
<div className="grid min-w-0 max-w-full grid-cols-[1.25rem_minmax(0,1fr)] items-center gap-1.5">
<span className={`grid size-5 place-items-center rounded-full bg-muted ${stateClasses(state)}`}>
<StatusIcon state={state} />
</span>
@@ -293,12 +293,12 @@ export function WorkspacePreprocessingControl({
{state !== "running" && <span className="text-[9px] leading-tight text-muted-foreground" title={detail}>{detail}</span>}
</div>
{progress && <PhaseProgress progress={progress} />}
<div className="col-span-2 mt-0.5 grid grid-cols-[0.78fr_1.22fr] gap-1.5">
<div className="col-span-2 mt-0.5 grid min-w-0 max-w-full grid-cols-[minmax(0,0.78fr)_minmax(0,1.22fr)] gap-1.5">
<Button
type="button"
variant="outline"
size="xs"
className="h-7 px-2 text-[10px] hover:border-destructive/35 hover:bg-destructive/5 hover:text-destructive"
className="h-7 min-w-0 max-w-full px-[0.5rem] text-[10px] hover:border-destructive/35 hover:bg-destructive/5 hover:text-destructive"
disabled={!clearable}
title={!canManage ? "Database management permission is required" : undefined}
onClick={() => setConfirmingClear(true)}
@@ -309,7 +309,7 @@ export function WorkspacePreprocessingControl({
type="button"
variant="outline"
size="xs"
className="h-7 px-2 text-[10px]"
className="h-7 min-w-0 max-w-full px-[0.5rem] text-[10px]"
disabled={!actionable}
title={!canManage ? "Database management permission is required" : undefined}
onClick={() => mutation.mutate()}
+6
View File
@@ -10,6 +10,12 @@ test("workspace module exposes validation and in-memory coordination but no draf
expect(workspaceModule).not.toHaveProperty("workspaceDeletionDrafts");
});
test("canonical sanitizer accepts schema-v4 workspaces without an authored dwh block", () => {
const { dwh: _catalogOwnedDwh, ...workspace } = canonicalWorkspaceFixture("psd-clinical");
expect(workspaceModule.sanitizeCanonicalWorkspace(workspace)).toEqual(workspace);
});
test("canonical sanitizer rejects unknown fields rather than persisting them", () => {
expect(workspaceModule.sanitizeCanonicalWorkspace({
...canonicalWorkspaceFixture("psd-clinical"),
+33 -16
View File
@@ -375,26 +375,48 @@ function copyDiagnostics(value: unknown): CanonicalDiagnostics | undefined {
export function sanitizeCanonicalWorkspace(value: unknown): CanonicalWorkspace | undefined {
const source = exactRecord(value, ["workspace", "dwh", "diagnostics", "evidence"]);
const metadata = exactRecord(source?.workspace, ["schema_version", "id", "name", "description", "language"]);
const dwh = exactRecord(source?.dwh, ["engine", "database", "schema", "port", "timeout_ms", "supported_transports"]);
const diagnostics = source?.diagnostics === undefined ? undefined : copyDiagnostics(source.diagnostics);
if (!metadata || !dwh) return undefined;
if (!metadata) return undefined;
const id = workspaceId(metadata.id);
const evidence = id && source?.evidence !== undefined ? copyEvidence(source.evidence, id) : undefined;
const name = text(metadata.name);
const language = oneOf(metadata.language, ["en", "it"] as const);
const description = metadata.description === undefined ? undefined : text(metadata.description);
const database = identifier(dwh.database);
const schema = identifier(dwh.schema);
const dwhPort = dwh.port === undefined ? undefined : positiveInteger(dwh.port, 65_535);
const dwhTimeout = dwh.timeout_ms === undefined ? undefined : positiveInteger(dwh.timeout_ms);
const dwhTransports = uniqueChoices(dwh.supported_transports, ["postgres_direct", "rest_api", "ssh_tunnel"] as const);
if (
metadata.schema_version !== 4 || !id || !name || !language || (metadata.description !== undefined && !description)
|| dwh.engine !== "postgres" || !database || !schema || (dwh.port !== undefined && !dwhPort) || (dwh.timeout_ms !== undefined && !dwhTimeout) || !dwhTransports
metadata.schema_version !== 4 || !id || !name || !language
|| (metadata.description !== undefined && !description)
) return undefined;
if (source?.diagnostics !== undefined && !diagnostics) return undefined;
if (source?.evidence !== undefined && !evidence) return undefined;
if (diagnostics?.dwh_rest && !dwhTransports.includes("rest_api")) return undefined;
let dwh: CanonicalWorkspace["dwh"];
if (source?.dwh !== undefined) {
const rawDwh = exactRecord(
source.dwh,
["engine", "database", "schema", "port", "timeout_ms", "supported_transports"],
);
if (!rawDwh) return undefined;
const database = identifier(rawDwh.database);
const schema = identifier(rawDwh.schema);
const port = rawDwh.port === undefined ? undefined : positiveInteger(rawDwh.port, 65_535);
const timeout = rawDwh.timeout_ms === undefined ? undefined : positiveInteger(rawDwh.timeout_ms);
const transports = uniqueChoices(
rawDwh.supported_transports,
["postgres_direct", "rest_api", "ssh_tunnel"] as const,
);
if (
rawDwh.engine !== "postgres" || !database || !schema || !transports
|| (rawDwh.port !== undefined && !port)
|| (rawDwh.timeout_ms !== undefined && !timeout)
) return undefined;
dwh = {
engine: "postgres", database, schema,
...(port ? { port } : {}),
...(timeout ? { timeout_ms: timeout } : {}),
supported_transports: transports,
};
}
if (diagnostics?.dwh_rest && !dwh?.supported_transports.includes("rest_api")) return undefined;
return {
workspace: {
schema_version: 4,
@@ -403,12 +425,7 @@ export function sanitizeCanonicalWorkspace(value: unknown): CanonicalWorkspace |
...(description ? { description } : {}),
language,
},
dwh: {
engine: "postgres", database, schema,
...(dwhPort ? { port: dwhPort } : {}),
...(dwhTimeout ? { timeout_ms: dwhTimeout } : {}),
supported_transports: dwhTransports,
},
...(dwh ? { dwh } : {}),
...(diagnostics ? { diagnostics } : {}),
...(evidence ? { evidence } : {}),
};
-39
View File
@@ -1,39 +0,0 @@
/* Artificial-brain controls and clearly separated explanatory callouts. */
.arit.flow-slide .fcol.ai-hit { flex-basis: 62px; }
.arit.flow-slide .brain-btn {
width: 56px; height: 56px; border-radius: 9px;
border: 1.5px solid var(--bordeaux); background: var(--surface);
box-shadow: 0 3px 8px oklch(26% .02 15 / .1);
}
.arit.flow-slide .fcol.ai > .brain-btn { top: -54px; right: 6px; }
.arit.flow-slide .brain-btn:hover, .arit.flow-slide .brain-btn:focus-visible {
transform: none; background: var(--bordeaux-tint);
box-shadow: 0 0 0 4px var(--bordeaux-tint);
}
.arit.flow-slide .brain-btn[aria-pressed="true"] { outline: 3px solid var(--bordeaux); outline-offset: 4px; }
.artificial-brain { display: block; width: 46px; height: 46px; }
.arit.flow-slide .brain-btn .ai-label {
position: absolute; left: 50%; top: -24px; transform: translateX(-50%);
display: grid; place-items: center; width: 42px; height: 25px;
border: 1.5px solid var(--bordeaux); border-radius: 5px 5px 0 0;
background: var(--bordeaux); color: var(--surface);
font: 800 18px/1 var(--sans); letter-spacing: .04em;
}
.arit.flow-slide .brain-btn .ai-number {
display: none;
}
/* The first AI control is in normal flow, but still anchors its AI label. */
.arit.flow-slide .fcol.ai-hit .brain-btn { position: relative; top: auto; right: auto; }
.ai-pop.is-ai .ai-pop-card {
box-sizing: border-box;
width: min(540px, calc(100vw - 48px)); max-height: calc(100vh - 48px);
overflow-y: auto; border: 2px solid var(--bordeaux); background: var(--surface);
transform: none; transition: none;
}
.ai-pop.is-ai .ai-line line { stroke: var(--bordeaux); stroke-width: 4; }
.ai-pop.is-ai .ai-line circle { fill: var(--bordeaux); }
.ai-pop-title .artificial-brain { width: 40px; height: 40px; }
.ai-pop-title #aiPopBrain { flex: 0 0 44px; width: 44px; height: 44px; border: 0; background: none; }
@media (prefers-reduced-motion: reduce) {
.arit.flow-slide .brain-btn { transition: none; }
}
-9
View File
@@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none" stroke="#8f1204" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M29 9h-9l-8 8v8l-5 5v12l8 8h6l5 5h6V15zm6 0h9l8 8v8l5 5v12l-8 8h-6l-5 5h-6" fill="#f4dfe1"/>
<path d="M20 17v9h12m-19 9h10v10m-7-1h7m21-27v9H32m19 9H41v10m7-1h-7M26 8V4m12 4V4M7 30H3m54 0h4M26 55v5m12-5v5"/>
<rect x="25" y="27" width="14" height="14" rx="2" fill="#fdfcfc"/>
<path d="M29 23v4m6-4v4m-6 14v4m6-4v4m-14-14h4m-4 6h4m14-6h4m-4 6h4"/>
<circle cx="20" cy="17" r="2.5" fill="#fdfcfc"/><circle cx="44" cy="17" r="2.5" fill="#fdfcfc"/>
<circle cx="23" cy="46" r="2.5" fill="#fdfcfc"/><circle cx="41" cy="46" r="2.5" fill="#fdfcfc"/>
<path d="M30 32h4v4h-4z" fill="#8f1204" stroke="none"/>
</svg>

Before

Width:  |  Height:  |  Size: 782 B

-386
View File
@@ -1,386 +0,0 @@
/* AritmoLab deck theme — consolidated light layout (variant 1) */
:root {
--bordeaux: #cb333b; --bordeaux-hover: #b7252d; --bordeaux-deep: #8f1204;
--bordeaux-tint: #f4dfe1;
--surface: #fdfcfc; --surface-alt: #f6f5f5; --surface-sunken: #ecebeb;
--ink: #2a2426; --ink-muted: #6b6568;
--line: #e3e0e1; --line-strong: #c9c5c6;
--sans: 'Source Sans 3', system-ui, sans-serif;
--display: 'Source Serif 4', Georgia, serif;
--mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}
.reveal { font-family: var(--sans); }
.reveal .slides { text-align: left; }
.reveal .slides section.arit {
width: 100%; height: 100%; box-sizing: border-box;
display: flex; flex-direction: column;
background: var(--surface); color: var(--ink);
text-align: left; padding: 0; font-family: var(--sans); font-size: 16px;
}
.reveal .arit *, .reveal .arit *::before, .reveal .arit *::after { box-sizing: border-box; }
/* ---------- chrome ---------- */
.arit .head {
flex: 0 0 104px; height: 104px; display: flex; align-items: center; justify-content: space-between;
padding: 0 40px; background: var(--surface); border-bottom: 1px solid var(--line);
}
.arit .head img { height: 80px; display: block; }
.arit .head-org { font: 700 11.5px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-muted); }
.arit .band {
height: 46px; display: flex; align-items: center; justify-content: space-between;
padding: 0 40px; background: var(--bordeaux); color: var(--surface); flex: 0 0 46px;
}
.arit .band-section { font: 700 13px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; }
.arit .band select.jump {
background: transparent; color: #fff; border: none;
padding: 6px 12px; font: 700 11.5px/1.2 var(--sans);
letter-spacing: .04em; cursor: pointer;
}
.arit .band select.jump option { color: var(--ink); background: #fff; }
.arit .foot {
flex: 0 0 34px; height: 34px; display: flex; align-items: center; justify-content: space-between; gap: 24px;
padding: 0 40px; border-top: 1px solid var(--line);
font: 600 10px/1.4 var(--sans); letter-spacing: .03em; color: var(--ink-muted);
}
.arit .foot span { white-space: nowrap; flex-shrink: 0; }
.presenter-preview .arit .foot { display: none; }
.arit .foot span:first-child { overflow: hidden; text-overflow: ellipsis; flex-shrink: 1; min-width: 0; }
.arit .foot span:first-child { overflow: hidden; text-overflow: ellipsis; flex-shrink: 1; }
.arit .sbody { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 30px 48px 22px; text-align: left; }
.arit.title-slide .sbody { justify-content: center; }
.arit.center-v .sbody { justify-content: center; }
/* ---------- typography ---------- */
.arit .kicker { font: 700 12px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--bordeaux); margin-bottom: 14px; }
.arit h1 { font: 700 46px/1.15 var(--sans); letter-spacing: -.01em; color: var(--ink); margin: 0; }
.arit h2 { font: 700 30px/1.15 var(--sans); letter-spacing: -.01em; color: var(--ink); margin: 0 0 8px; }
.arit .lead { font: 400 16px/1.5 var(--sans); color: var(--ink-muted); margin: 8px 0 0; }
.arit.title-slide .lead { font-size: 19px; text-align: center; }
.arit .hgap { height: 16px; flex: 0 0 16px; }
/* title slide */
.arit .title-meta { display: flex; align-items: center; gap: 14px; margin-top: 28px; }
.arit .title-meta .pill {
display: inline-flex; align-items: center; height: 34px; padding: 0 18px;
border-radius: 9999px; background: var(--bordeaux); color: #fdfcfc;
font: 700 12.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
}
.arit .title-meta .what { font: 400 14.5px/1.5 var(--sans); color: var(--ink-muted); }
.arit .speakers { margin-top: 22px; display: flex; flex-direction: column; gap: 8px; }
.arit .speakers span { font: 600 15.5px/1.4 var(--sans); color: var(--ink); }
.arit .event { margin: 16px 0 0; font: italic 400 15px/1.5 var(--display); color: var(--ink-muted); }
.arit .event-where { margin: 8px 0 0; font: 600 14px/1.4 var(--sans); color: var(--ink-muted); }
/* quote */
.arit .quote {
position: relative; margin: 14px 0 20px; padding: 20px 26px 18px 68px; border: 1px solid var(--line);
background: var(--surface-alt); border-radius: 8px;
font: italic 400 19px/1.55 var(--display); color: var(--ink);
}
.arit .quote::before { content: '\201C'; position: absolute; left: 22px; top: 10px;
font: 700 52px/1 var(--display); color: var(--bordeaux); }
/* EN translations alongside Italian clinical text */
.arit .tr-grid { display: grid; grid-template-columns: 1.12fr 1fr; gap: 24px; align-items: center; }
.arit .tr-grid .it, .arit .tr-grid .en { margin: 0; }
.arit .tr-grid .en { padding-left: 20px; border-left: 1px solid var(--line-strong);
font: 400 19px/1.5 var(--sans); color: var(--bordeaux-deep); }
.arit .en-tag { display: inline-block; margin-right: 8px; padding: 2.5px 8px; border-radius: 4px;
background: var(--bordeaux); color: #fdfcfc; font: 700 9.5px/1 var(--sans); letter-spacing: .12em;
vertical-align: 2px; }
.arit .points .g { color: var(--bordeaux-deep); }
.arit .chipc .g { font-weight: 400; opacity: .78; }
.arit .code .en { font: 400 13px/1.5 var(--sans); color: var(--bordeaux-deep); }
.arit .code .en::before { content: 'EN'; display: inline-block; margin-right: 8px; padding: 2px 6px;
border-radius: 3px; background: var(--bordeaux); color: #fdfcfc;
font: 700 8.5px/1 var(--sans); letter-spacing: .1em; }
/* ---------- slide "The problem": challenges + outputs rail + ThothII right ---------- */
.arit.problem .sbody { padding-top: 20px; padding-bottom: 14px; }
.arit.problem .kicker { margin-bottom: 10px; }
.arit.problem .quote { margin: 0 0 10px; padding: 12px 22px 10px 64px; font-size: 16.5px; }
.arit.problem .tr-grid .en { font-size: 16.5px; }
.arit.problem .stage { padding: 11px 10px; }
.arit.problem .stage b { font-size: 13px; text-transform: uppercase; }
.arit.problem .stage span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .02em; }
.arit.problem .stage.hot { background: #fdf1f2; border-color: var(--bordeaux); }
.arit .brain-ai { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
border-radius: 9999px; background: #fff; border: 1.5px solid var(--bordeaux); }
.arit .brain-ai svg { width: 24px; height: 24px; color: var(--bordeaux); }
.arit.problem .stage span.brain-ai { display: inline-flex; margin: 3px auto 0; }
.arit.problem .midrow { display: flex; gap: 0; margin-top: 8px; align-items: stretch; }
.arit.problem .concepts { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.arit.problem .concepts .citem { flex: 1; }
.arit .concepts .lbl, .arit .rail .lbl { display: block; font: 700 10px/1 var(--mono); letter-spacing: .14em;
text-transform: uppercase; color: var(--bordeaux); margin: 0 0 5px; }
.arit .rail .lbl { padding-left: 16px; }
.arit .citem { display: flex; gap: 12px; align-items: baseline; padding: 5px 0; border-bottom: 1px solid var(--line); }
.arit .citem:last-child { border-bottom: none; }
.arit .citem .n { font: 700 11px/1 var(--mono); color: var(--bordeaux); }
.arit .citem b { font: 700 12.5px/1.3 var(--sans); color: var(--ink); text-transform: uppercase; letter-spacing: .03em; }
.arit .citem span.d { font: 400 11px/1.4 var(--sans); color: var(--ink-muted); margin-left: 8px; }
.arit .railwrap { position: relative; display: flex; justify-content: flex-end; }
.arit .conn-drop, .arit .t-conn { position: absolute; width: 2px; background: var(--bordeaux); }
.arit .conn-elbow { position: absolute; height: 2px; background: var(--bordeaux); }
.arit .t-head { position: absolute; width: 0; height: 0; border: 5px solid transparent;
border-bottom: 7px solid var(--bordeaux); transform: translateX(-50%); }
.arit .rail { width: 540px; border-left: 2px solid var(--bordeaux); padding-top: 12px; }
.arit .rail .row { display: flex; align-items: center; gap: 12px; padding: 5px 14px 5px 16px; position: relative; }
.arit .rail .row::before { content: ''; position: absolute; left: -2px; top: 50%; width: 14px; height: 2px; background: var(--bordeaux); }
.arit .rail .row .oicon { flex: 0 0 26px; width: 26px; height: 26px; color: var(--bordeaux); display: block; }
.arit .rail .row b { font: 700 13px/1.2 var(--sans); color: var(--ink); text-transform: uppercase; letter-spacing: .03em; }
.arit .rail .row span.d { font: 400 11px/1.3 var(--sans); color: var(--ink-muted); }
.arit.problem .thoth-wrap { position: relative; justify-content: flex-end; margin-top: 10px; }
.arit.problem .thoth-box { padding: 8px 14px; font-size: 11px; text-transform: uppercase; letter-spacing: .02em; }
.arit.problem .thoth-box .brain-ai { margin-right: 9px; vertical-align: middle; }
.arit .quote small { display: block; margin-top: 6px; font: 600 11px/1.4 var(--sans); font-style: normal;
letter-spacing: .06em; text-transform: uppercase; color: var(--ink-muted); }
/* mini pipeline (problem / thoth slides) */
.arit .pipeline { display: flex; align-items: stretch; gap: 12px; }
.arit .stage { flex: 1; padding: 15px 12px; text-align: center; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-alt); }
.arit .stage b { display: block; font: 700 14px/1.2 var(--sans); margin-bottom: 4px; }
.arit .stage span { display: block; font: 400 11.5px/1.35 var(--sans); color: var(--ink-muted); }
.arit .stage .tag { display: inline-block; margin-top: 6px; padding: 3px 10px; border-radius: 9999px;
background: var(--bordeaux); color: #fdfcfc; font: 700 9.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; }
.arit .stage.ai { background: var(--bordeaux-tint); border-color: var(--bordeaux); }
.arit .arrow { align-self: center; color: var(--line-strong); font: 700 20px/1 var(--sans); }
.arit .thoth-wrap { display: flex; justify-content: flex-end; margin-top: 18px; }
.arit .thoth-col { width: 540px; text-align: center; }
.arit .thoth-arrow { color: var(--line-strong); font: 700 18px/1 var(--sans); margin: 2px 0; }
.arit .thoth-box { border: 1px solid var(--bordeaux); border-radius: 8px; padding: 12px 16px;
background: var(--surface-alt); font: 600 13px/1.4 var(--sans); }
.arit .thoth-box .tag { margin-right: 8px; }
/* points */
.arit .points { list-style: none; margin: 0; padding: 0; }
.arit .points li { position: relative; padding: 11px 0 11px 26px; border-bottom: 1px solid var(--line);
font: 400 15px/1.45 var(--sans); color: var(--ink); }
.arit .points li::before { content: ''; position: absolute; left: 0; top: 18px;
width: 10px; height: 10px; border-radius: 9999px; background: var(--bordeaux); }
.arit .points code, .arit .stat-note code, .arit .ai-pop-list code {
font: 600 0.92em var(--mono); color: var(--bordeaux-deep); background: var(--surface-alt);
padding: 1px 5px; border-radius: 4px; }
/* split + code panel */
.arit .split { display: flex; gap: 40px; flex: 1; min-height: 0; }
.arit .split .left { flex: 0 0 430px; display: flex; flex-direction: column; }
.arit .split .right { flex: 1; min-width: 0; display: flex; }
.arit.nlp .split .right { align-items: center; }
.arit.nlp .code { flex: 0 0 auto; }
.arit .code { width: 100%; display: flex; flex-direction: column; overflow: hidden;
border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface-sunken); }
.arit .code-head { flex: 0 0 38px; display: flex; align-items: center; justify-content: space-between;
padding: 0 16px; border-bottom: 1px solid var(--line); font: 600 11px/1 var(--mono); color: var(--ink-muted); }
.arit .code pre { flex: 1; padding: 16px 18px; overflow: hidden; margin: 0;
font: 400 13px/1.6 var(--mono); color: var(--ink); text-align: left; box-shadow: none; }
.arit .code b { font-weight: 700; color: var(--bordeaux-deep); }
.arit .code i { font-style: normal; color: #2f6f4f; }
/* stats — editorial numeral band */
.arit .stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); }
.arit .stat { padding: 8px 24px; display: flex; flex-direction: column; gap: 10px; }
.arit .stat:first-child { padding-left: 0; }
.arit .stat + .stat { border-left: 1px solid var(--line); }
.arit .stat .num { font: 700 62px/1 var(--sans); color: var(--bordeaux); letter-spacing: -.02em; }
.arit .stat .lbl { font: 600 14.5px/1.35 var(--sans); color: var(--ink); }
.arit .stat .sub { font: 400 12px/1.45 var(--sans); color: var(--ink-muted); }
.arit .stat-note { margin-top: 26px; font: 400 13px/1.5 var(--sans); color: var(--ink-muted); }
/* slide "What the text miner reads": slim numbers strip + elliptical component cycle */
.arit.stats .sbody { padding-top: 22px; }
.arit.stats .strip { display: flex; justify-content: space-between; align-items: baseline;
border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 9px 2px; }
.arit.stats .sstat { display: flex; align-items: baseline; gap: 9px; }
.arit.stats .sstat .n { font: 700 25px/1 var(--sans); color: var(--bordeaux); letter-spacing: -.02em; }
.arit.stats .sstat .l { font: 600 11.5px/1.2 var(--sans); color: var(--ink); }
.arit.stats .cycle { position: relative; width: 1184px; height: 270px; margin: 4px auto 0; }
.arit.stats .cycle-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.arit.stats .vcomp { position: absolute; transform: translate(-50%, -50%); width: 250px;
text-align: center; background: var(--surface); padding: 4px 6px; }
.arit.stats .vcomp .cicon { width: 46px; height: 46px; color: var(--bordeaux); display: block; margin: 0 auto 7px; }
.arit.stats .vcomp b { display: block; font: 700 14.5px/1.25 var(--sans); text-transform: uppercase;
letter-spacing: .04em; color: var(--ink); }
.arit.stats .vcomp span.d { display: block; margin-top: 4px; font: 400 11.5px/1.4 var(--sans); color: var(--ink-muted); }
.arit.stats .note-row { display: flex; gap: 30px; margin-top: 6px; }
.arit.stats .nitem { flex: 1; position: relative; padding-left: 16px; font: 400 14px/1.45 var(--sans); color: var(--ink); }
.arit.stats .nitem::before { content: ''; position: absolute; left: 0; top: 7px; width: 8px; height: 8px;
border-radius: 9999px; background: var(--bordeaux); }
.arit.stats .nitem b { color: var(--bordeaux-deep); }
/* divider */
.arit.divider .sbody { justify-content: center; }
.arit .numeral { font: 700 110px/1 var(--sans); color: var(--bordeaux); }
.arit .divider-h { font: 700 40px/1.15 var(--sans); margin-top: 10px; }
.arit .cue { margin-top: 22px; font: 600 12px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-muted); }
/* ontology slide: EN-first category pills + output panel */
.arit .onto-split { flex: 0 0 auto; display: grid; grid-template-columns: 1.25fr 1fr;
gap: 26px; align-items: stretch; margin-top: 14px; }
.arit .tier-h { display: flex; align-items: center; font: 700 10px/1 var(--mono); letter-spacing: .14em;
text-transform: uppercase; color: var(--bordeaux-deep); margin: 22px 0 9px; }
.arit .onto-left .tier-h:first-child { margin-top: 0; }
.arit .tier-h .cnt { margin-left: auto; font: 700 9px/1 var(--mono); color: var(--bordeaux);
border: 1px solid var(--bordeaux); border-radius: 9999px; padding: 2px 7px; }
.arit .cats { display: flex; flex-wrap: wrap; gap: 8px; }
.arit .cat { display: inline-flex; align-items: baseline; gap: 7px; border: 1px solid var(--bordeaux);
border-radius: 9999px; padding: 6px 13px; background: #fff; white-space: nowrap; }
.arit .cat b { font: 700 13px/1 var(--sans); color: var(--ink); }
.arit .cat .it { font: 400 11px/1 var(--sans); color: var(--ink-muted); }
.arit .cat.fill { background: var(--bordeaux-tint); }
.arit .onto-points { margin-top: 18px; }
.arit .onto-left .onto-points:first-child { margin-top: 0; }
.arit .onto-left { display: flex; flex-direction: column; }
.arit .onto-left .roi { margin-top: auto; }
.arit .onto-left .onto-points { margin-bottom: 14px; }
.arit .oitem { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.arit .oitem:last-child { border-bottom: none; }
.arit .oitem .n { flex: 0 0 22px; font: 700 11px/1.6 var(--mono); color: var(--bordeaux); }
.arit .oitem b { font: 700 13px/1.35 var(--sans); color: var(--ink); }
.arit .oitem .d { font: 400 12.5px/1.45 var(--sans); color: var(--ink-muted); }
.arit .out-panel { border: 1px solid var(--bordeaux); background: var(--bordeaux-tint); border-radius: 10px;
padding: 15px 18px 8px; align-self: stretch; display: flex; flex-direction: column; }
.arit .out-h { display: block; font: 700 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
color: var(--bordeaux-deep); margin-bottom: 10px; }
.arit .out-item { display: flex; gap: 10px; padding: 13px 0; border-bottom: 1px solid rgba(143,18,4,.18); flex: 1; }
.arit .out-item:last-child { border-bottom: none; }
.arit .out-item .n { flex: 0 0 22px; font: 700 11px/1.6 var(--mono); color: var(--bordeaux-deep); }
.arit .out-item b { font: 700 13px/1.35 var(--sans); color: var(--bordeaux-deep); }
.arit .out-item .d { display: block; margin-top: 2px; font: 400 12.5px/1.45 var(--sans); color: var(--ink); }
/* flow */
.arit .flow { margin-top: 16px; display: flex; align-items: stretch; gap: 14px; }
.arit .zone { border-radius: 8px; padding: 30px 14px 14px; position: relative; }
.arit .zone > .zlabel { position: absolute; top: 8px; left: 14px;
font: 700 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; }
.arit .zone.existed { flex: 0 0 168px; background: var(--surface-alt); border: 1px dashed var(--line-strong); }
.arit .zone.existed > .zlabel { color: var(--ink-muted); }
.arit .zone.built { flex: 1; background: #faf4f5; border: 1px solid #e7c3c6; }
.arit .zone.built > .zlabel { color: var(--bordeaux); }
.arit .fcol { flex: 1; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.arit .fbox { background: #fff; border: 1px solid var(--line-strong); border-radius: 6px; padding: 10px; text-align: center; }
.arit .fbox b { display: block; font: 700 13.5px/1.25 var(--sans); }
.arit .fbox span { display: block; margin-top: 3px; font: 400 11px/1.3 var(--sans); color: var(--ink-muted); }
.arit .fbox.src { background: var(--surface-alt); border-color: var(--line); }
.arit .fbox.src.future { background: transparent; border: 1.5px dashed var(--line-strong); }
.arit .fbox.src.future b { color: var(--ink-muted); font-weight: 700; }
.arit .fbox.src.future .plus { display: inline-flex; width: 16px; height: 16px; margin-right: 5px; vertical-align: -3px;
align-items: center; justify-content: center; border-radius: 9999px; border: 1.5px solid var(--bordeaux);
color: var(--bordeaux); font: 800 11px/1 var(--sans); }
.arit .fbox.end { background: var(--bordeaux); border-color: var(--bordeaux); color: #fff; padding: 14px 10px; }
.arit .fbox.end span { color: rgba(255,255,255,.85); }
.arit .farrow { align-self: center; color: var(--bordeaux); font: 700 15px/1 var(--sans); }
.arit .fcol.ai { position: relative; padding-top: 12px; }
.arit .brain {
position: absolute; top: -6px; right: 6px; z-index: 5;
width: 30px; height: 30px; border-radius: 9999px;
background: #fff; border: 1.5px solid var(--bordeaux);
display: flex; align-items: center; justify-content: center; font-size: 15px;
}
.arit .fcap { font: italic 400 11px/1.4 var(--sans); color: var(--ink-muted); text-align: center; }
.arit .fcol.ai-hit { flex: 0 0 44px; align-items: center; justify-content: center; gap: 8px; }
.arit .fcol.ai-hit .brain-btn { position: static; }
/* clickable brains */
button.brain-btn { cursor: pointer; padding: 0; transition: transform .15s ease, box-shadow .15s ease; }
button.brain-btn:hover, button.brain-btn:focus-visible { transform: scale(1.18); box-shadow: 0 0 0 5px rgba(203,51,59,.14); outline: none; }
/* popup */
.ai-pop { position: fixed; inset: 0; z-index: 100; background: rgba(42,36,38,.12);
display: block; opacity: 0; pointer-events: none; transition: opacity .2s ease; }
.ai-pop.open { opacity: 1; pointer-events: auto; }
.ai-line { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; }
.ai-line line { stroke: var(--bordeaux-deep); stroke-width: 5; stroke-linecap: round; filter: drop-shadow(0 0 2px #fff); }
.ai-line circle { fill: var(--bordeaux-deep); stroke: #fff; stroke-width: 1.5; }
.ai-pop-card { position: absolute; width: min(580px, 92vw); background: #fff; border: 1px solid var(--line);
border-radius: 12px; box-shadow: 0 18px 50px rgba(42,36,38,.28); padding: 24px 28px 22px;
transform: translateY(14px) scale(.95); transition: transform .24s cubic-bezier(.2,.9,.3,1.15); text-align: left; }
.ai-pop.open .ai-pop-card { transform: none; }
.ai-pop-kicker { font: 700 10.5px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--bordeaux); margin-bottom: 10px; }
.ai-pop-title { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.ai-pop-title .brain { position: static; }
.ai-pop-title .brain-btn { cursor: default; pointer-events: none; }
.ai-pop-title b { font: 700 18px/1.3 var(--sans); color: var(--ink); font-family: var(--sans); }
.ai-pop-card p { font: 400 14px/1.65 var(--sans); color: var(--ink); margin: 0; text-align: left; }
.ai-pop-card p.lead { margin-bottom: 14px; }
.ai-pop-list { list-style: none; display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; }
.ai-pop-list li { position: relative; padding-left: 20px; font: 400 13.5px/1.5 var(--sans); color: var(--ink); }
.ai-pop-list li::before { content: ''; position: absolute; left: 0; top: 7px; width: 8px; height: 8px; border-radius: 9999px; background: var(--bordeaux); }
.ai-pop-list b { font-weight: 800; }
.ai-pop-list .n { color: var(--bordeaux-deep); font-weight: 800; }
.roi { margin-top: 14px; border: 1.5px solid var(--bordeaux); background: #faf4f5; border-radius: 8px;
padding: 10px 14px; font: 400 13.5px/1.55 var(--sans); color: var(--ink); }
.roi-quiet { border-color: var(--line-strong); border-width: 1px; background: var(--surface-alt); }
.roi .k { display: block; margin-bottom: 4px; font: 800 10.5px/1 var(--mono); letter-spacing: .14em;
text-transform: uppercase; color: var(--bordeaux-deep); }
.ai-pop-x { position: absolute; top: 12px; right: 14px; width: 30px; height: 30px; border: none;
border-radius: 9999px; background: var(--surface-alt); font: 700 15px/1 var(--sans); color: var(--ink-muted); cursor: pointer; }
.ai-pop-x:hover { background: var(--bordeaux-tint); color: var(--bordeaux-deep); }
/* chips on slides (wording TBD) */
.arit .chip.tbd { color: var(--bordeaux-deep); border: 1px solid var(--bordeaux); background: #fff;
border-radius: 9999px; padding: 6px 12px; font: 700 10.5px/1 var(--sans); letter-spacing: .06em; }
/* where we started — scattered orbit map */
.arit .scatter { position: relative; flex: 1; min-height: 0; }
.arit .todo-stack { position: absolute; z-index: 2; }
.arit .todo { display: flex; align-items: center; gap: 12px; border: 2px dashed var(--bordeaux);
border-radius: 8px; background: #fff; padding: 8px 12px; margin-bottom: 8px;
box-shadow: 0 2px 8px rgba(42,36,38,.06); cursor: pointer; }
.arit .todo .q { font: 800 22px/1 var(--sans); color: var(--bordeaux-deep); }
.arit .todo .tx { display: flex; flex-direction: column; }
.arit .todo b { font: 700 13.5px/1.3 var(--sans); color: var(--bordeaux-deep); }
.arit .todo .tx span { font: 400 12px/1.4 var(--sans); color: var(--ink-muted); margin-top: 2px; }
.arit .missing-title { position: absolute; font: 700 30px/1.2 var(--sans); color: var(--bordeaux-deep); }
.arit .isle { position: absolute; display: flex; flex-direction: column; align-items: center; gap: 2px;
cursor: pointer; transform: rotate(var(--rot, 0deg)); transition: transform .18s ease;
border: none; background: none; font-family: var(--sans); width: 230px; }
.arit .isle:hover, .arit .isle:focus-visible { transform: rotate(var(--rot, 0deg)) scale(1.05); outline: none; }
.arit .isle .ico { width: var(--size, 120px); height: var(--size, 120px); color: var(--bordeaux); display: block; }
.arit .isle .nm { font: 700 16px/1.3 var(--sans); color: var(--ink); margin-top: 4px; }
.arit .isle .sc { font: 400 13.5px/1.4 var(--sans); color: var(--ink-muted); max-width: 240px; }
.arit .hint { margin-top: 12px; font: italic 400 12px/1.4 var(--sans); color: var(--ink-muted); }
/* snapshot tours + chart placeholders */
.arit .shots { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: 1fr 1fr;
gap: 14px; flex: 1; min-height: 0; align-content: center; }
.arit .shot { border: 1.5px dashed var(--line-strong); border-radius: 8px;
background: var(--surface-alt); display: flex; align-items: center; justify-content: center;
font: italic 400 12px/1.4 var(--sans); color: var(--ink-muted); min-height: 0; overflow: hidden; }
.arit .charts { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; flex: 1; min-height: 0; align-content: center; }
.arit .chart { border: 1.5px solid var(--line); border-radius: 8px; background: #fff; min-height: 0;
display: flex; flex-direction: column; overflow: hidden; }
.arit .chart b { display: block; padding: 12px 16px; font: 700 14px/1.3 var(--sans); color: var(--ink);
border-bottom: 1px solid var(--line); }
.arit .chart span { flex: 1; display: flex; align-items: center; justify-content: center;
font: italic 400 12px/1.4 var(--sans); color: var(--ink-muted); text-align: center; padding: 0 20px; }
/* pillars strip (vision slide) */
.arit .pillars { margin-top: auto; padding-top: 14px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.arit .pillars .agents { font: italic 600 12px/1.4 var(--sans); color: var(--bordeaux-deep);
border: 1.5px dashed var(--bordeaux); border-radius: 8px; padding: 7px 12px; background: #faf4f5; }
.arit .pillars .pillar { border: 1px solid var(--line-strong); border-radius: 9999px;
padding: 6px 12px; font: 600 11.5px/1 var(--sans); color: var(--ink-muted); }
.arit .pillars .pillar b { color: var(--ink); font-weight: 700; }
/* Reveal sets inline "display: block" on the presented section — beat it
(author !important wins over inline) so our flex column layout applies */
.reveal .slides section.arit.present { display: flex !important; }
/* hide reveal default noise on our chrome */
.reveal .slides section.arit aside.notes { display: none; }
/* vision slide: tighter vertical rhythm to keep pillars clear of the footer */
.arit.flow-slide .kicker { margin-bottom: 10px; }
.arit.flow-slide h2 { margin-bottom: 6px; }
.arit.flow-slide .lead { margin-top: 6px; font-size: 15px; }
.arit.flow-slide .flow { margin-top: 10px; }
.arit.flow-slide .zone { padding: 26px 14px 12px; }
.arit.flow-slide .fbox { padding: 8px 10px; }
.arit.flow-slide .fbox.end { padding: 12px 10px; }
.arit.flow-slide .fcol { gap: 6px; }
.arit.flow-slide .pillars { padding-top: 8px; }
/* popup: lead + list (missing-pieces popups) */
.ai-pop-card p.lead { font-style: italic; color: var(--ink-muted); }
-11
View File
@@ -1,11 +0,0 @@
/* Embedded fonts — Source Sans 3 & Source Serif 4 (SIL Open Font License) */
@font-face { font-family: 'Source Sans 3'; font-style: normal; font-weight: 400; font-display: swap;
src: url('fonts/ss3-400.woff2') format('woff2'); }
@font-face { font-family: 'Source Sans 3'; font-style: normal; font-weight: 600; font-display: swap;
src: url('fonts/ss3-600.woff2') format('woff2'); }
@font-face { font-family: 'Source Sans 3'; font-style: normal; font-weight: 700; font-display: swap;
src: url('fonts/ss3-700.woff2') format('woff2'); }
@font-face { font-family: 'Source Serif 4'; font-style: normal; font-weight: 400; font-display: swap;
src: url('fonts/ss4-400.woff2') format('woff2'); }
@font-face { font-family: 'Source Serif 4'; font-style: italic; font-weight: 400; font-display: swap;
src: url('fonts/ss4-italic-400.woff2') format('woff2'); }
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

-76
View File
@@ -1,76 +0,0 @@
/* Opt-in, same-browser synchronization. The regular deck has no channel or session. */
(() => {
const params = new URLSearchParams(location.search);
const session = params.get('session');
const role = params.get('view');
if (!session || !['preview', 'audience'].includes(role)) return;
const channel = new BroadcastChannel(`aritmolab-presenter:${session}`);
const sender = crypto.randomUUID();
const storageKey = `aritmolab-state:${session}`;
let applying = false;
let pending = false;
const send = (type, extra = {}) => channel.postMessage({ type, role, sender, ...extra });
const api = window.PresentationControls;
const valid = state => state && Number.isInteger(state.index) && state.index >= 0 && state.index < Reveal.getTotalSlides();
function save(state) { try { localStorage.setItem(storageKey, JSON.stringify(state)); } catch {} }
function publish() {
if (applying || pending) return;
pending = true;
queueMicrotask(() => {
pending = false;
const state = api.snapshot();
save(state);
send('state', { state });
});
}
function apply(state) {
if (!valid(state)) return;
applying = true;
Reveal.slide(state.index);
api.closePopup();
if (state.popup) api.openPopup(state.popup);
applying = false;
save(api.snapshot());
}
function command(message) {
if (message.action === 'next') Reveal.next();
if (message.action === 'previous') Reveal.prev();
if (message.action === 'slide' && valid({ index: message.index })) Reveal.slide(message.index);
if (message.action === 'popup' && message.popup) api.openPopup(message.popup);
if (message.action === 'close') api.closePopup();
publish();
}
function ready() {
Reveal.configure({ overview: false, pause: false });
if (role === 'preview') {
// Remove only the presenter's footer and its 34px, preserving the slide body geometry.
document.documentElement.classList.add('presenter-preview');
Reveal.configure({ height: 686 });
}
try { apply(JSON.parse(localStorage.getItem(storageKey))); } catch {}
addEventListener('presentationchange', publish);
Reveal.on('slidechanged', publish);
channel.onmessage = ({ data }) => {
if (!data || data.sender === sender) return;
if (data.type === 'state') apply(data.state);
if (data.type === 'command' && role === 'preview') command(data);
if (data.type === 'request' && role === 'preview') publish();
};
if (role === 'preview') publish();
else send('request');
send('presence');
setInterval(() => send('presence'), 1000);
addEventListener('pagehide', () => send('departed'));
if (role === 'audience') {
document.title = 'AritmoLab | Audience';
const button = document.createElement('button');
button.textContent = 'Full screen';
button.setAttribute('aria-label', 'Enter audience full screen');
Object.assign(button.style, { position: 'fixed', right: '16px', top: '16px', zIndex: '200', padding: '10px 18px', borderRadius: '6px', border: '1px solid #b9afb1', background: '#faf7f7', color: '#482d34', cursor: 'pointer', font: '15px system-ui' });
button.onclick = () => document.documentElement.requestFullscreen().catch(() => { button.textContent = 'Use the browser full-screen command'; });
document.addEventListener('fullscreenchange', () => { button.hidden = Boolean(document.fullscreenElement); });
document.body.append(button);
}
}
if (Reveal.isReady()) ready(); else Reveal.on('ready', ready);
})();
-49
View File
@@ -1,49 +0,0 @@
/* Ordered tour stops; screenshot originals keep their full aspect ratio. */
.arit .screenshot-tour {
display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(2, minmax(0, 1fr));
gap: 16px; flex: 1; min-height: 0; margin-top: 10px;
}
.arit .screenshot-tour-four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.arit .screenshot-tour button {
display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 0;
overflow: hidden; border: 1px solid var(--line-strong); border-radius: 8px;
background: var(--surface-alt); color: var(--ink); cursor: pointer; text-align: left;
}
.arit .screenshot-tour button:hover { border-color: var(--bordeaux); background: var(--bordeaux-tint); }
.arit .screenshot-tour button:focus-visible { outline: 3px solid var(--bordeaux); outline-offset: 3px; }
.arit .screenshot-tour img {
display: block; width: 100%; height: 0; flex: 1; min-height: 0; max-width: none; max-height: none;
margin: 0; object-fit: contain; border: 0; box-shadow: none; background: #fff;
}
.arit .screenshot-tour span {
display: flex; align-items: center; gap: 10px; padding: 9px 12px;
border-top: 1px solid var(--line); font: 600 16px/1.2 var(--sans);
}
.arit .screenshot-tour b { color: var(--bordeaux); font: 700 22px/1 var(--sans); }
.arit .screenshot-tour-compact {
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 10px;
}
.arit .screenshot-tour-compact span { gap: 8px; padding: 6px 10px; font-size: 14px; }
.arit .screenshot-tour-compact b { font-size: 18px; }
.screenshot-dialog {
box-sizing: border-box; width: calc(100vw - 24px); height: calc(100vh - 24px);
max-width: none; max-height: none; padding: 8px; margin: auto;
border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface);
color: var(--ink); font-family: var(--sans); overflow: hidden;
}
.screenshot-dialog[open] { display: flex; flex-direction: column; gap: 6px; }
.screenshot-dialog::backdrop { background: rgb(42 36 38 / 70%); }
.screenshot-dialog header { display: flex; align-items: center; gap: 12px; min-height: 32px; flex: 0 0 auto; }
.screenshot-dialog h2 { margin: 0 auto 0 4px; font: 600 16px/1.2 var(--sans); }
.screenshot-dialog button {
border: 1px solid var(--line-strong); border-radius: 4px; background: var(--surface);
color: var(--ink); padding: 5px 12px; font: 600 14px/1.2 var(--sans); cursor: pointer;
}
.screenshot-dialog button:hover { background: var(--bordeaux-tint); }
.screenshot-dialog button:focus-visible { outline: 3px solid var(--bordeaux); outline-offset: 1px; }
.screenshot-stage { position: relative; flex: 1; min-height: 0; }
.screenshot-stage img { position: absolute; inset: 0; width: 100%; height: 100%; }
.screenshot-stage img { object-fit: contain; }
.screenshot-dialog .screenshot-error { margin: auto; text-align: center; }
@media print { .screenshot-dialog { display: none !important; } }
-44
View File
@@ -1,44 +0,0 @@
/* Uses the deck's shared popup state, so preview and audience stay synchronized. */
(() => {
const dialog = document.createElement('dialog');
dialog.className = 'screenshot-dialog';
dialog.setAttribute('aria-labelledby', 'screenshot-title');
dialog.innerHTML = `<header><h2 id="screenshot-title"></h2><button type="button" aria-label="Close screenshot">Close · Esc</button></header>
<div class="screenshot-stage">
<img alt="">
</div>
<p class="screenshot-error" hidden>Screenshot unavailable. Close and reopen to retry.</p>`;
document.body.append(dialog);
const title = dialog.querySelector('h2');
const image = dialog.querySelector('img');
const error = dialog.querySelector('.screenshot-error');
let active = null;
let trigger = null;
const close = () => {
active = null;
if (dialog.open) dialog.close();
if (trigger?.closest('section.present')) trigger.focus({ preventScroll: true });
trigger = null;
};
const requestClose = () => window.PresentationControls.closePopup();
dialog.querySelector('button').addEventListener('click', requestClose);
dialog.addEventListener('cancel', event => { event.preventDefault(); requestClose(); });
dialog.addEventListener('click', event => { if (event.target === dialog) requestClose(); });
image.addEventListener('error', () => { image.hidden = true; error.hidden = false; });
window.ScreenshotTour = {
get active() { return active; },
open(button) {
trigger = button;
active = { kind: 'screenshot', key: button.dataset.screenshot };
const total = button.closest('.screenshot-tour').querySelectorAll('[data-screenshot]').length;
title.textContent = `${button.dataset.screenshotNumber} / ${total} · ${button.dataset.screenshotTitle}`;
image.hidden = false;
error.hidden = true;
image.alt = button.dataset.screenshotTitle;
image.src = button.querySelector('img').src;
if (!dialog.open) dialog.showModal();
window.dispatchEvent(new Event('presentationchange'));
},
close,
};
})();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 551 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 959 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 707 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 KiB

-127
View File
@@ -1,127 +0,0 @@
/* A rectangular optical enlargement, anchored to the original diagram element. */
.arit .flow .lens-target {
display: block; width: 100%; color: inherit; font: inherit; cursor: pointer;
appearance: none;
transition: transform 180ms cubic-bezier(.16, 1, .3, 1), box-shadow 180ms ease,
border-color 180ms ease, opacity 220ms ease;
}
.arit .flow .lens-target:hover {
transform: translateY(-2px); border-color: var(--bordeaux);
box-shadow: 0 5px 12px oklch(26% .02 15 / .13);
}
.arit .flow .lens-target:focus-visible, .arit .slide-lens-close:focus-visible {
outline: 3px solid var(--bordeaux); outline-offset: 4px;
}
.arit .flow .zone.built, .arit .flow > .ai-hit, .arit .flow .fbox:not(.lens-target) {
transition: opacity 220ms ease;
}
.arit.lens-active .flow .zone.built:not(:has(.lens-source)), .arit.lens-active .flow > .ai-hit,
.arit.lens-active .flow .zone.built:has(.lens-source) :is(.fbox:not(.lens-source), .farrow, .brain-btn, .fcap),
.arit.lens-active .flow .zone.existed:not(.lens-source) { opacity: .18; }
.arit .flow .lens-source {
border-color: var(--bordeaux); box-shadow: 0 0 0 3px var(--bordeaux-tint);
}
.arit .oitem.lens-target {
width: 100%; color: inherit; font: inherit; text-align: left;
background: transparent; border: 0; border-bottom: 1px solid var(--line);
appearance: none; cursor: pointer;
transition: background 180ms ease, opacity 220ms ease;
}
.arit .oitem.lens-target:last-child { border-bottom: 0; }
.arit .oitem.lens-target:hover, .arit .oitem.lens-source { background: var(--bordeaux-tint); }
.arit .oitem.lens-target:focus-visible { outline: 3px solid var(--bordeaux); outline-offset: 3px; }
.arit.crisis .crisis-points { margin-bottom: 4px; }
.arit.crisis .oitem { padding: 12px 10px; gap: 14px; }
.arit.crisis .oitem .n { flex-basis: 28px; font-size: 15px; }
.arit.crisis .oitem b { display: block; font-size: 18px; }
.arit.crisis .oitem .d { display: block; margin-top: 3px; font-size: 16px; }
.arit.crisis .sbody > .roi { padding: 12px 18px; font-size: 22px; line-height: 1.3; font-weight: 600; }
.arit.crisis .sbody > .roi .k { margin-bottom: 8px; font-size: 14px; line-height: 1.2; }
.arit.crisis.lens-active .crisis-points .oitem:not(.lens-source),
.arit.crisis.lens-active .sbody > .roi { opacity: .18; }
.arit.crisis.lens-active .sbody > :is(h2, .kicker) { opacity: 0; }
.arit.validation .onto-split :is(.oitem, .roi, .out-panel) { transition: opacity 220ms ease; }
.arit.validation.lens-active .onto-split :is(.oitem:not(.lens-source), .roi, .out-panel:not(.lens-source)) { opacity: .18; }
.arit.validation .out-panel.lens-target {
appearance: none; width: 100%; color: inherit; font: inherit; text-align: left;
cursor: pointer;
transition: transform 180ms cubic-bezier(.16, 1, .3, 1), box-shadow 180ms ease,
background 180ms ease, opacity 220ms ease;
}
.arit.validation .out-panel.lens-target:hover {
transform: translateY(-2px); background: var(--surface-alt);
box-shadow: 0 0 0 3px var(--bordeaux-tint), 0 6px 16px oklch(26% .02 15 / .14);
}
.arit.validation .out-panel.lens-target:focus-visible {
outline: 3px solid var(--bordeaux); outline-offset: 4px;
}
.arit.validation .out-panel.lens-source { box-shadow: 0 0 0 3px var(--bordeaux-tint); }
.arit.validation .out-panel.lens-target .out-item:last-of-type { border-bottom: none; }
.arit .slide-lens-guides {
position: absolute; inset: 0; width: 100%; height: 100%;
pointer-events: none; z-index: 8; overflow: visible;
}
.arit .slide-lens-guides path {
fill: none; stroke: var(--bordeaux); stroke-width: 1; opacity: .45;
}
.arit .slide-lens {
position: absolute; z-index: 9; transform-origin: 0 0;
border: 3px solid var(--bordeaux); border-radius: 9px;
background: var(--surface-alt); padding: 9px;
box-shadow: 0 22px 48px oklch(26% .02 15 / .2),
0 4px 10px oklch(26% .02 15 / .12),
inset 0 0 0 2px var(--surface), inset 0 0 0 3px var(--line-strong);
}
/* A beveled rim and a restrained reflection suggest a lens without an icon. */
.arit .slide-lens::after {
content: ''; position: absolute; inset: 5px; pointer-events: none;
border-radius: 4px; border: 1px solid oklch(99% .004 20 / .85);
background: linear-gradient(125deg, oklch(99% .004 20 / .45), transparent 26%,
transparent 78%, oklch(99% .004 20 / .25));
}
.arit .slide-lens-content { overflow: hidden; width: 100%; height: 100%; border-radius: 2px; }
.arit .slide-lens .slide-lens-copy {
margin: 0; transform-origin: 0 0; border-radius: 1px;
border-color: transparent; position: static;
}
.arit .slide-lens .slide-lens-copy.zone { position: relative; }
.arit .slide-lens.has-details .slide-lens-content { overflow-y: auto; }
.arit .slide-lens-detail { padding: 16px 18px; text-align: left; color: var(--ink); }
.arit .slide-lens-detail h3 {
margin: 0 0 12px; font: 700 30px/1.15 var(--sans); color: var(--bordeaux-deep);
}
.arit .slide-lens-detail p { margin: 0 0 10px; font: 400 17px/1.35 var(--sans); }
.arit .slide-lens-detail p:last-child { margin-bottom: 0; }
.arit .slide-lens-detail p b {
display: block; margin-bottom: 4px; font-weight: 700; color: var(--bordeaux-deep);
}
.arit .slide-lens-detail .detail-intro { font-size: 19px; line-height: 1.3; }
.arit .slide-lens-detail .detail-example { padding-top: 12px; border-top: 1px solid var(--line-strong); }
.arit .slide-lens-caption {
position: absolute; left: 0; top: -28px; color: var(--bordeaux-deep);
font: 700 11px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase;
}
.arit .slide-lens-close {
position: absolute; right: -15px; top: -15px; z-index: 1;
display: grid; place-items: center; width: 30px; height: 30px;
border: 1px solid var(--bordeaux); border-radius: 5px;
padding: 0; background: var(--surface); color: var(--bordeaux-deep);
font: 400 22px/1 var(--sans); cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
.arit.validation .out-panel.lens-target { transition: none; }
.arit.validation .out-panel.lens-target:hover { transform: none; }
.arit.validation .onto-split :is(.oitem, .roi, .out-panel) { transition: none; }
.arit .flow .zone, .arit .flow > .ai-hit, .arit .flow .fbox { transition: none; }
.arit .flow .lens-target:hover { transform: none; }
}
@media print {
.arit.crisis.lens-active .sbody > :is(h2, .kicker) { opacity: 1; }
.arit.crisis.lens-active .crisis-points .oitem:not(.lens-source),
.arit.crisis.lens-active .sbody > .roi { opacity: 1; }
.arit.validation.lens-active .onto-split :is(.oitem, .roi, .out-panel) { opacity: 1; }
.arit .slide-lens, .arit .slide-lens-guides { display: none !important; }
.arit.lens-active .flow .zone, .arit.lens-active .flow > .ai-hit,
.arit.lens-active .flow .fbox,
.arit.lens-active .flow .zone.built:has(.lens-source) :is(.fbox, .farrow, .brain-btn, .fcap) { opacity: 1; }
}
-121
View File
@@ -1,121 +0,0 @@
/* Reuse with a source button carrying its id and data-lens="source-id".
Content is cloned from the source, with optional explanatory content in a template. */
(() => {
let current = null;
const changed = () => window.dispatchEvent(new Event('presentationchange'));
const reducedMotion = () => matchMedia('(prefers-reduced-motion: reduce)').matches;
function layout() {
if (!current) return;
const { source, slide, frame, copy, guides, caption, detailed } = current;
const sr = slide.getBoundingClientRect();
const rect = source.getBoundingClientRect();
const scale = sr.width / slide.offsetWidth;
const area = (slide.querySelector('.flow') || slide.querySelector('.sbody')).getBoundingClientRect();
const centered = source.dataset.lensPlacement === 'center';
const x = (rect.left - sr.left) / scale, y = (rect.top - sr.top) / scale;
const w = rect.width / scale, h = rect.height / scale;
const isGroup = source.classList.contains('zone');
const areaTop = isGroup || detailed ? 160 : (area.top - sr.top) / scale;
const areaHeight = isGroup || detailed ? slide.offsetHeight - areaTop - 50 : area.height / scale;
// Choose the roomier side so the original stays visible, including middle/right nodes.
const margin = 65, gap = 38;
const roomLeft = x - gap - margin;
const roomRight = slide.offsetWidth - margin - (x + w + gap);
const onRight = roomRight >= roomLeft;
const maxWidth = centered ? Math.min(760, slide.offsetWidth - 2 * margin)
: Math.min(slide.offsetWidth * .58, Math.max(roomLeft, roomRight));
const zoom = Math.min(4, (maxWidth - 24) / w, (areaHeight - 40) / h);
let width = w * zoom + 24, height = h * zoom + 24;
if (detailed) {
width = maxWidth;
Object.assign(copy.style, { width: `${width - 24}px`, height: 'auto', transform: 'none' });
height = Math.min(copy.scrollHeight + 24, areaHeight - 16);
}
const left = centered ? (slide.offsetWidth - width) / 2 : onRight
? Math.min(slide.offsetWidth - width - margin, Math.max(slide.offsetWidth * .36, x + w + gap))
: Math.max(margin, Math.min(slide.offsetWidth * .36, x - gap - width));
const top = areaTop + (areaHeight - height) / 2 + 10;
Object.assign(frame.style, { left: `${left}px`, top: `${top}px`, width: `${width}px`, height: `${height}px` });
if (!detailed) Object.assign(copy.style, { width: `${w}px`, height: `${h}px`, transform: `scale(${zoom})` });
const zoneTitle = source.dataset.lensCaption || source.closest('.zone')?.querySelector('.zlabel')?.textContent || 'Detail';
caption.textContent = detailed ? zoneTitle : `${zoneTitle} · ${zoom.toFixed(1)}×`;
guides.setAttribute('viewBox', `0 0 ${slide.offsetWidth} ${slide.offsetHeight}`);
const sourceEdge = onRight ? x + w : x;
const lensEdge = onRight ? left : left + width;
guides.querySelector('path').setAttribute('d', `M ${sourceEdge} ${y} L ${lensEdge} ${top} M ${sourceEdge} ${y + h} L ${lensEdge} ${top + height}`);
current.origin = `translate(${x - left}px, ${y - top}px) scale(${w / width}, ${h / height})`;
}
function close() {
if (!current) return;
const { slide, source, trigger, frame, guides, animation } = current;
animation?.cancel();
const restoreFocus = frame.contains(document.activeElement);
frame.remove(); guides.remove();
slide.classList.remove('lens-active'); source.classList.remove('lens-source');
trigger.setAttribute('aria-expanded', 'false');
current = null;
if (restoreFocus && slide.classList.contains('present')) trigger.focus({ preventScroll: true });
changed();
}
function open(trigger) {
const source = document.getElementById(trigger.dataset.lens);
const slide = source?.closest('section');
if (!source || !slide?.classList.contains('present')) return;
close();
const details = source.querySelector('template.lens-details');
const title = source.dataset.lensTitle || source.querySelector('b').textContent;
const copy = document.createElement('div');
if (details) {
copy.className = 'slide-lens-detail';
const heading = document.createElement('h3');
heading.textContent = title;
copy.append(heading, details.content.cloneNode(true));
} else {
copy.className = source.className;
copy.classList.remove('lens-target', 'lens-source');
copy.innerHTML = source.innerHTML;
}
copy.querySelectorAll('[id]').forEach(el => el.removeAttribute('id'));
copy.querySelectorAll('button').forEach(el => el.remove());
copy.classList.add('slide-lens-copy');
const frame = document.createElement('div');
frame.id = 'slide-lens'; frame.className = 'slide-lens';
frame.classList.toggle('has-details', Boolean(details));
frame.setAttribute('role', 'region');
frame.setAttribute('aria-label', details ? `${title} explained` : `${title} enlarged`);
const caption = document.createElement('div'); caption.className = 'slide-lens-caption';
const content = document.createElement('div'); content.className = 'slide-lens-content';
content.append(copy);
const closeButton = document.createElement('button');
closeButton.className = 'slide-lens-close'; closeButton.textContent = '×';
closeButton.setAttribute('aria-label', 'Close detail');
frame.append(caption, content, closeButton);
const guides = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
guides.classList.add('slide-lens-guides'); guides.setAttribute('aria-hidden', 'true');
guides.append(document.createElementNS(guides.namespaceURI, 'path'));
slide.append(guides, frame);
current = { source, slide, trigger, frame, copy, guides, caption, detailed: Boolean(details) };
layout();
source.classList.add('lens-source'); slide.classList.add('lens-active');
trigger.setAttribute('aria-expanded', 'true');
if (!reducedMotion()) {
current.animation = frame.animate([
{ transform: current.origin, opacity: .5 },
{ transform: 'none', opacity: 1 },
], { duration: 480, easing: 'cubic-bezier(.16, 1, .3, 1)' });
guides.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 480 });
}
changed();
}
window.SlideLens = {
open, close, layout,
get active() { return current ? { kind: 'lens', key: current.source.id } : null; },
};
addEventListener('resize', layout);
document.addEventListener('transitionend', event => {
if (event.target === current?.source && event.propertyName === 'transform') layout();
});
})();
-21
View File
@@ -1,21 +0,0 @@
## Contributing
Please keep the [issue tracker](https://github.com/hakimel/reveal.js/issues) limited to **bug reports**.
### General Questions and Support
If you have questions about how to use reveal.js the best place to ask is in the [Discussions](https://github.com/hakimel/reveal.js/discussions). Anything that isn't a bug report should be posted as a dicussion instead.
### Bug Reports
When reporting a bug make sure to include information about which browser and operating system you are on as well as the necessary steps to reproduce the issue. If possible please include a link to a sample presentation where the bug can be tested.
### Pull Requests
- Should be submitted from a feature/topic branch (not your master)
- Should follow the coding style of the file you work in, most importantly:
- Tabs to indent
- Single-quoted strings
### Plugins
Please do not submit plugins as pull requests. They should be maintained in their own separate repository. More information here: https://github.com/hakimel/reveal.js/wiki/Plugin-Guidelines
-1
View File
@@ -1 +0,0 @@
github: [hakimel]
@@ -1,31 +0,0 @@
name: tests
on:
- push
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version:
- 18
- 20
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build --if-present
- run: npm test
env:
CI: true
@@ -1,11 +0,0 @@
.idea/
*.iml
*.iws
*.eml
out/
.DS_Store
.svn
log/*.log
tmp/**
node_modules/
.sass-cache
-5
View File
@@ -1,5 +0,0 @@
/test
/examples
.github
.sass-cache
gulpfile.js
-19
View File
@@ -1,19 +0,0 @@
Copyright (C) 2011-2024 Hakim El Hattab, http://hakim.se, and reveal.js contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-50
View File
@@ -1,50 +0,0 @@
<p align="center">
<a href="https://revealjs.com">
<img src="https://hakim-static.s3.amazonaws.com/reveal-js/logo/v1/reveal-black-text-sticker.png" alt="reveal.js" width="500">
</a>
<br><br>
<a href="https://github.com/hakimel/reveal.js/actions"><img src="https://github.com/hakimel/reveal.js/workflows/tests/badge.svg"></a>
<a href="https://slides.com/"><img src="https://s3.amazonaws.com/static.slid.es/images/slides-github-banner-320x40.png?1" alt="Slides" width="160" height="20"></a>
</p>
reveal.js is an open source HTML presentation framework. It enables anyone with a web browser to create beautiful presentations for free. Check out the live demo at [revealjs.com](https://revealjs.com/).
The framework comes with a powerful feature set including [nested slides](https://revealjs.com/vertical-slides/), [Markdown support](https://revealjs.com/markdown/), [Auto-Animate](https://revealjs.com/auto-animate/), [PDF export](https://revealjs.com/pdf-export/), [speaker notes](https://revealjs.com/speaker-view/), [LaTeX typesetting](https://revealjs.com/math/), [syntax highlighted code](https://revealjs.com/code/) and an [extensive API](https://revealjs.com/api/).
---
Want to create reveal.js presentation in a graphical editor? Try <https://slides.com>. It's made by the same people behind reveal.js.
---
### Sponsors
Hakim's open source work is supported by <a href="https://github.com/sponsors/hakimel">GitHub sponsors</a>. Special thanks to:
<div align="center">
<table>
<td align="center">
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=revealjs&utm_source=github">
<div>
<img src="https://user-images.githubusercontent.com/629429/151508669-efb4c3b3-8fe3-45eb-8e47-e9510b5f0af1.svg" width="290" alt="WorkOS">
</div>
<b>Your app, enterprise-ready.</b>
<div>
<sub>Start selling to enterprise customers with just a few lines of code. Add Single Sign-On (and more) in minutes instead of months.</sup>
</div>
</a>
</td>
</table>
</div>
---
### Getting started
- 🚀 [Install reveal.js](https://revealjs.com/installation)
- 👀 [View the demo presentation](https://revealjs.com/demo)
- 📖 [Read the documentation](https://revealjs.com/markup/)
- 🖌 [Try the visual editor for reveal.js at Slides.com](https://slides.com/)
- 🎬 [Watch the reveal.js video course (paid)](https://revealjs.com/course)
---
<div align="center">
MIT licensed | Copyright © 2011-2024 Hakim El Hattab, https://hakim.se
</div>
-70
View File
@@ -1,70 +0,0 @@
/**
* Layout helpers.
*/
// Stretch an element vertically based on available space
.reveal .stretch,
.reveal .r-stretch {
max-width: none;
max-height: none;
}
.reveal pre.stretch code,
.reveal pre.r-stretch code {
height: 100%;
max-height: 100%;
box-sizing: border-box;
}
// Text that auto-fits its container
.reveal .r-fit-text {
display: inline-block; // https://github.com/rikschennink/fitty#performance
white-space: nowrap;
}
// Stack multiple elements on top of each other
.reveal .r-stack {
display: grid;
grid-template-rows: 100%;
}
.reveal .r-stack > * {
grid-area: 1/1;
margin: auto;
}
// Horizontal and vertical stacks
.reveal .r-vstack,
.reveal .r-hstack {
display: flex;
img, video {
min-width: 0;
min-height: 0;
object-fit: contain;
}
}
.reveal .r-vstack {
flex-direction: column;
align-items: center;
justify-content: center;
}
.reveal .r-hstack {
flex-direction: row;
align-items: center;
justify-content: center;
}
// Naming based on tailwindcss
.reveal .items-stretch { align-items: stretch; }
.reveal .items-start { align-items: flex-start; }
.reveal .items-center { align-items: center; }
.reveal .items-end { align-items: flex-end; }
.reveal .justify-between { justify-content: space-between; }
.reveal .justify-around { justify-content: space-around; }
.reveal .justify-start { justify-content: flex-start; }
.reveal .justify-center { justify-content: center; }
.reveal .justify-end { justify-content: flex-end; }
-166
View File
@@ -1,166 +0,0 @@
@media print {
html:not(.print-pdf) {
overflow: visible;
width: auto;
height: auto;
body {
margin: 0;
padding: 0;
overflow: visible;
}
}
html:not(.print-pdf) .reveal {
background: #fff;
font-size: 20pt;
.controls,
.state-background,
.progress,
.backgrounds,
.slide-number {
display: none !important;
}
p, td, li {
font-size: 20pt!important;
color: #000;
}
h1,h2,h3,h4,h5,h6 {
color: #000!important;
height: auto;
line-height: normal;
text-align: left;
letter-spacing: normal;
}
h1 { font-size: 28pt !important; }
h2 { font-size: 24pt !important; }
h3 { font-size: 22pt !important; }
h4 { font-size: 22pt !important; font-variant: small-caps; }
h5 { font-size: 21pt !important; }
h6 { font-size: 20pt !important; font-style: italic; }
a:link,
a:visited {
color: #000 !important;
font-weight: bold;
text-decoration: underline;
}
ul, ol, div, p {
visibility: visible;
position: static;
width: auto;
height: auto;
display: block;
overflow: visible;
margin: 0;
text-align: left !important;
}
pre,
table {
margin-left: 0;
margin-right: 0;
}
pre code {
padding: 20px;
}
blockquote {
margin: 20px 0;
}
.slides {
position: static !important;
width: auto !important;
height: auto !important;
left: 0 !important;
top: 0 !important;
margin-left: 0 !important;
margin-top: 0 !important;
padding: 0 !important;
zoom: 1 !important;
transform: none !important;
overflow: visible !important;
display: block !important;
text-align: left !important;
perspective: none;
perspective-origin: 50% 50%;
}
.slides section {
visibility: visible !important;
position: static !important;
width: auto !important;
height: auto !important;
display: block !important;
overflow: visible !important;
left: 0 !important;
top: 0 !important;
margin-left: 0 !important;
margin-top: 0 !important;
padding: 60px 20px !important;
z-index: auto !important;
opacity: 1 !important;
page-break-after: always !important;
transform-style: flat !important;
transform: none !important;
transition: none !important;
}
.slides section.stack {
padding: 0 !important;
}
.slides section:last-of-type {
page-break-after: avoid !important;
}
.slides section .fragment {
opacity: 1 !important;
visibility: visible !important;
transform: none !important;
}
.r-fit-text {
white-space: normal !important;
}
section img {
display: block;
margin: 15px 0px;
background: rgba(255,255,255,1);
border: 1px solid #666;
box-shadow: none;
}
section small {
font-size: 0.8em;
}
.hljs {
max-height: 100%;
white-space: pre-wrap;
word-wrap: break-word;
word-break: break-word;
font-size: 15pt;
}
.hljs .hljs-ln-numbers {
white-space: nowrap;
}
.hljs td {
font-size: inherit !important;
color: inherit !important;
}
}
}
-159
View File
@@ -1,159 +0,0 @@
/**
* This stylesheet is used to print reveal.js
* presentations to PDF.
*
* https://revealjs.com/pdf-export/
*/
html.reveal-print {
* {
-webkit-print-color-adjust: exact;
}
& {
width: 100%;
height: 100%;
overflow: visible;
}
body {
margin: 0 auto !important;
border: 0;
padding: 0;
float: none !important;
overflow: visible;
}
/* Remove any elements not needed in print. */
.nestedarrow,
.reveal .controls,
.reveal .progress,
.reveal .playback,
.reveal.overview,
.state-background {
display: none !important;
}
.reveal pre code {
overflow: hidden !important;
}
.reveal {
width: auto !important;
height: auto !important;
overflow: hidden !important;
}
.reveal .slides {
position: static;
width: 100% !important;
height: auto !important;
zoom: 1 !important;
pointer-events: initial;
left: auto;
top: auto;
margin: 0 !important;
padding: 0 !important;
overflow: visible;
display: block;
perspective: none;
perspective-origin: 50% 50%;
}
.reveal .slides .pdf-page {
position: relative;
overflow: hidden;
z-index: 1;
page-break-after: always;
}
.reveal .slides .pdf-page:last-of-type {
page-break-after: avoid;
}
.reveal .slides section {
visibility: visible !important;
display: block !important;
position: absolute !important;
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
min-height: 1px;
opacity: 1 !important;
transform-style: flat !important;
transform: none !important;
}
.reveal section.stack {
position: relative !important;
margin: 0 !important;
padding: 0 !important;
page-break-after: avoid !important;
height: auto !important;
min-height: auto !important;
}
.reveal img {
box-shadow: none;
}
/* Slide backgrounds are placed inside of their slide when exporting to PDF */
.reveal .backgrounds {
display: none;
}
.reveal .slide-background {
display: block !important;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: auto !important;
}
/* Display slide speaker notes when 'showNotes' is enabled */
.reveal.show-notes {
max-width: none;
max-height: none;
}
.reveal .speaker-notes-pdf {
display: block;
width: 100%;
height: auto;
max-height: none;
top: auto;
right: auto;
bottom: auto;
left: auto;
z-index: 100;
}
/* Layout option which makes notes appear on a separate page */
.reveal .speaker-notes-pdf[data-layout="separate-page"] {
position: relative;
color: inherit;
background-color: transparent;
padding: 20px;
page-break-after: always;
border: 0;
}
/* Display slide numbers when 'slideNumber' is enabled */
.reveal .slide-number-pdf {
display: block;
position: absolute;
font-size: 14px;
visibility: visible;
}
/* This accessibility tool is not useful in PDF and breaks it visually */
.aria-status {
display: none;
}
}
File diff suppressed because it is too large Load Diff
-21
View File
@@ -1,21 +0,0 @@
## Dependencies
Themes are written using Sass to keep things modular and reduce the need for repeated selectors across files. Make sure that you have the reveal.js development environment installed before proceeding: https://revealjs.com/installation/#full-setup
## Creating a Theme
To create your own theme, start by duplicating a ```.scss``` file in [/css/theme/source](https://github.com/hakimel/reveal.js/blob/master/css/theme/source). It will be automatically compiled from Sass to CSS (see the [gulpfile](https://github.com/hakimel/reveal.js/blob/master/gulpfile.js)) when you run `npm run build -- css-themes`.
Each theme file does four things in the following order:
1. **Include [/css/theme/template/mixins.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/mixins.scss)**
Shared utility functions.
2. **Include [/css/theme/template/settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss)**
Declares a set of custom variables that the template file (step 4) expects. Can be overridden in step 3.
3. **Override**
This is where you override the default theme. Either by specifying variables (see [settings.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/settings.scss) for reference) or by adding any selectors and styles you please.
4. **Include [/css/theme/template/theme.scss](https://github.com/hakimel/reveal.js/blob/master/css/theme/template/theme.scss)**
The template theme file which will generate final CSS output based on the currently defined variables.
@@ -1,44 +0,0 @@
/**
* Beige theme for reveal.js.
*
* Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
// Override theme settings (see ../template/settings.scss)
$mainColor: #333;
$headingColor: #333;
$headingTextShadow: none;
$backgroundColor: #f7f3de;
$linkColor: #8b743d;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: rgba(79, 64, 28, 0.99);
$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Background generator
@mixin bodyBackground() {
@include radial-gradient( rgba(247,242,211,1), rgba(255,255,255,1) );
}
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,49 +0,0 @@
/**
* Black compact & high contrast reveal.js theme, with headers not in capitals.
*
* By Peter Kehl. Based on black.(s)css by Hakim El Hattab, http://hakim.se
*
* - Keep the source similar to black.css - for easy comparison.
* - $mainFontSize controls code blocks, too (although under some ratio).
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/source-sans-pro/source-sans-pro.css);
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #000000;
$mainColor: #fff;
$headingColor: #fff;
$mainFontSize: 42px;
$mainFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingFontWeight: 600;
$linkColor: #42affa;
$linkColorHover: lighten( $linkColor, 15% );
$selectionBackgroundColor: lighten( $linkColor, 25% );
$heading1Size: 2.5em;
$heading2Size: 1.6em;
$heading3Size: 1.3em;
$heading4Size: 1.0em;
// Change text colors against light slide backgrounds
@include light-bg-text-color(#000);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,46 +0,0 @@
/**
* Black theme for reveal.js. This is the opposite of the 'white' theme.
*
* By Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/source-sans-pro/source-sans-pro.css);
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #191919;
$mainColor: #fff;
$headingColor: #fff;
$mainFontSize: 42px;
$mainFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingFontWeight: 600;
$linkColor: #42affa;
$linkColorHover: lighten( $linkColor, 15% );
$selectionBackgroundColor: rgba( $linkColor, 0.75 );
$heading1Size: 2.5em;
$heading2Size: 1.6em;
$heading3Size: 1.3em;
$heading4Size: 1.0em;
// Change text colors against light slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,87 +0,0 @@
/**
* Blood theme for reveal.js
* Author: Walther http://github.com/Walther
*
* Designed to be used with highlight.js theme
* "monokai_sublime.css" available from
* https://github.com/isagalaev/highlight.js/
*
* For other themes, change $codeBackground accordingly.
*
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,700,300italic,700italic);
// Colors used in the theme
$blood: #a23;
$coal: #222;
$codeBackground: #23241f;
$backgroundColor: $coal;
// Main text
$mainFont: Ubuntu, 'sans-serif';
$mainColor: #eee;
// Headings
$headingFont: Ubuntu, 'sans-serif';
$headingTextShadow: 2px 2px 2px $coal;
// h1 shadow, borrowed humbly from
// (c) Default theme by Hakim El Hattab
$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
// Links
$linkColor: $blood;
$linkColorHover: lighten( $linkColor, 20% );
// Text selection
$selectionBackgroundColor: $blood;
$selectionColor: #fff;
// Change text colors against dark slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
// some overrides after theme template import
.reveal p {
font-weight: 300;
text-shadow: 1px 1px $coal;
}
section.has-light-background {
p, h1, h2, h3, h4 {
text-shadow: none;
}
}
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
font-weight: 700;
}
.reveal p code {
background-color: $codeBackground;
display: inline-block;
border-radius: 7px;
}
.reveal small code {
vertical-align: baseline;
}
@@ -1,106 +0,0 @@
/**
* Dracula Dark theme for reveal.js.
* Based on https://draculatheme.com
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
$systemFontsSansSerif: -apple-system,
BlinkMacSystemFont,
avenir next,
avenir,
segoe ui,
helvetica neue,
helvetica,
Cantarell,
Ubuntu,
roboto,
noto,
arial,
sans-serif;
$systemFontsMono: Menlo,
Consolas,
Monaco,
Liberation Mono,
Lucida Console,
monospace;
/**
* Dracula colors by Zeno Rocha
* https://draculatheme.com/contribute
*/
html * {
color-profile: sRGB;
rendering-intent: auto;
}
$background: #282A36;
$foreground: #F8F8F2;
$selection: #44475A;
$comment: #6272A4;
$red: #FF5555;
$orange: #FFB86C;
$yellow: #F1FA8C;
$green: #50FA7B;
$purple: #BD93F9;
$cyan: #8BE9FD;
$pink: #FF79C6;
// Override theme settings (see ../template/settings.scss)
$mainColor: $foreground;
$headingColor: $purple;
$headingTextShadow: none;
$headingTextTransform: none;
$backgroundColor: $background;
$linkColor: $pink;
$linkColorHover: $cyan;
$selectionBackgroundColor: $selection;
$inlineCodeColor: $green;
$listBulletColor: $cyan;
$mainFont: $systemFontsSansSerif;
$codeFont: "Fira Code", $systemFontsMono;
// Change text colors against light slide backgrounds
@include light-bg-text-color($background);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
// Define additional color effects based on Dracula spec
// https://spec.draculatheme.com/
:root {
--r-bold-color: #{$orange};
--r-italic-color: #{$yellow};
--r-inline-code-color: #{$inlineCodeColor};
--r-list-bullet-color: #{$listBulletColor};
}
.reveal {
strong, b {
color: var(--r-bold-color);
}
em, i, blockquote {
color: var(--r-italic-color);
}
code {
color: var(--r-inline-code-color);
}
// Dracula colored list bullets and numbers
ul, ol {
li::marker {
color: var(--r-list-bullet-color);
}
}
}
@@ -1,36 +0,0 @@
/**
* League theme for reveal.js.
*
* This was the default theme pre-3.0.0.
*
* Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
// Override theme settings (see ../template/settings.scss)
$headingTextShadow: 0px 0px 6px rgba(0,0,0,0.2);
$heading1TextShadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 20px 20px rgba(0,0,0,.15);
// Background generator
@mixin bodyBackground() {
@include radial-gradient( rgba(28,30,32,1), rgba(85,90,95,1) );
}
// Change text colors against light slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,54 +0,0 @@
/**
* Solarized Dark theme for reveal.js.
* Author: Achim Staebler
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
/**
* Solarized colors by Ethan Schoonover
*/
// Solarized colors
$base03: #002b36;
$base02: #073642;
$base01: #586e75;
$base00: #657b83;
$base0: #839496;
$base1: #93a1a1;
$base2: #eee8d5;
$base3: #fdf6e3;
$yellow: #b58900;
$orange: #cb4b16;
$red: #dc322f;
$magenta: #d33682;
$violet: #6c71c4;
$blue: #268bd2;
$cyan: #2aa198;
$green: #859900;
// Override theme settings (see ../template/settings.scss)
$mainColor: $base1;
$headingColor: $base2;
$headingTextShadow: none;
$backgroundColor: $base03;
$linkColor: $blue;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: $magenta;
// Change text colors against light slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,37 +0,0 @@
/**
* Black theme for reveal.js.
*
* Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(https://fonts.googleapis.com/css?family=Montserrat:700);
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic,700italic);
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #111;
$mainFont: 'Open Sans', sans-serif;
$linkColor: #e7ad52;
$linkColorHover: lighten( $linkColor, 20% );
$headingFont: 'Montserrat', Impact, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: -0.03em;
$headingTextTransform: none;
$selectionBackgroundColor: #e7ad52;
// Change text colors against light slide backgrounds
@include light-bg-text-color(#222);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,41 +0,0 @@
/**
* A simple theme for reveal.js presentations, similar
* to the default theme. The accent color is brown.
*
* This theme is Copyright (C) 2012-2013 Owen Versteeg, http://owenversteeg.com - it is MIT licensed.
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Override theme settings (see ../template/settings.scss)
$mainFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
$mainColor: #000;
$headingFont: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
$headingColor: #383D3D;
$headingTextShadow: none;
$headingTextTransform: none;
$backgroundColor: #F0F1EB;
$linkColor: #51483D;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: #26351C;
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
.reveal a {
line-height: 1.3em;
}
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,43 +0,0 @@
/**
* A simple theme for reveal.js presentations, similar
* to the default theme. The accent color is darkblue.
*
* This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed.
* reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
// Override theme settings (see ../template/settings.scss)
$mainFont: 'Lato', sans-serif;
$mainColor: #000;
$headingFont: 'News Cycle', Impact, sans-serif;
$headingColor: #000;
$headingTextShadow: none;
$headingTextTransform: none;
$backgroundColor: #fff;
$linkColor: #00008B;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: rgba(0, 0, 0, 0.99);
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,52 +0,0 @@
/**
* Sky theme for reveal.js.
*
* Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(https://fonts.googleapis.com/css?family=Quicksand:400,700,400italic,700italic);
@import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
// Override theme settings (see ../template/settings.scss)
$mainFont: 'Open Sans', sans-serif;
$mainColor: #333;
$headingFont: 'Quicksand', sans-serif;
$headingColor: #333;
$headingLetterSpacing: -0.08em;
$headingTextShadow: none;
$backgroundColor: #f7fbfc;
$linkColor: #3b759e;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: #134674;
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Fix links so they are not cut off
.reveal a {
line-height: 1.3em;
}
// Background generator
@mixin bodyBackground() {
@include radial-gradient( #add9e4, #f7fbfc );
}
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,66 +0,0 @@
/**
* Solarized Light theme for reveal.js.
* Author: Achim Staebler
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/league-gothic/league-gothic.css);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
/**
* Solarized colors by Ethan Schoonover
*/
html * {
color-profile: sRGB;
rendering-intent: auto;
}
// Solarized colors
$base03: #002b36;
$base02: #073642;
$base01: #586e75;
$base00: #657b83;
$base0: #839496;
$base1: #93a1a1;
$base2: #eee8d5;
$base3: #fdf6e3;
$yellow: #b58900;
$orange: #cb4b16;
$red: #dc322f;
$magenta: #d33682;
$violet: #6c71c4;
$blue: #268bd2;
$cyan: #2aa198;
$green: #859900;
// Override theme settings (see ../template/settings.scss)
$mainColor: $base00;
$headingColor: $base01;
$headingTextShadow: none;
$backgroundColor: $base3;
$linkColor: $blue;
$linkColorHover: lighten( $linkColor, 20% );
$selectionBackgroundColor: $magenta;
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Background generator
// @mixin bodyBackground() {
// @include radial-gradient( rgba($base3,1), rgba(lighten($base3, 20%),1) );
// }
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,52 +0,0 @@
/**
* White compact & high contrast reveal.js theme, with headers not in capitals.
*
* By Peter Kehl. Based on white.(s)css by Hakim El Hattab, http://hakim.se
*
* - Keep the source similar to black.css - for easy comparison.
* - $mainFontSize controls code blocks, too (although under some ratio).
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/source-sans-pro/source-sans-pro.css);
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #fff;
$mainColor: #000;
$headingColor: #000;
$mainFontSize: 42px;
$mainFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingFontWeight: 600;
$linkColor: #2a76dd;
$linkColorHover: lighten( $linkColor, 15% );
$selectionBackgroundColor: lighten( $linkColor, 25% );
$heading1Size: 2.5em;
$heading2Size: 1.6em;
$heading3Size: 1.3em;
$heading4Size: 1.0em;
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,49 +0,0 @@
/**
* White theme for reveal.js. This is the opposite of the 'black' theme.
*
* By Hakim El Hattab, http://hakim.se
*/
// Default mixins and settings -----------------
@import "../template/mixins";
@import "../template/settings";
// ---------------------------------------------
// Include theme-specific fonts
@import url(./fonts/source-sans-pro/source-sans-pro.css);
// Override theme settings (see ../template/settings.scss)
$backgroundColor: #fff;
$mainColor: #222;
$headingColor: #222;
$mainFontSize: 42px;
$mainFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingFont: 'Source Sans Pro', Helvetica, sans-serif;
$headingTextShadow: none;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingFontWeight: 600;
$linkColor: #2a76dd;
$linkColorHover: lighten( $linkColor, 15% );
$selectionBackgroundColor: lighten( $linkColor, 25% );
$heading1Size: 2.5em;
$heading2Size: 1.6em;
$heading3Size: 1.3em;
$heading4Size: 1.0em;
$overlayElementBgColor: 0, 0, 0;
$overlayElementFgColor: 240, 240, 240;
// Change text colors against dark slide backgrounds
@include dark-bg-text-color(#fff);
// Theme template ------------------------------
@import "../template/theme";
// ---------------------------------------------
@@ -1,30 +0,0 @@
// Exposes theme's variables for easy re-use in CSS for plugin authors
:root {
--r-background-color: #{$backgroundColor};
--r-main-font: #{$mainFont};
--r-main-font-size: #{$mainFontSize};
--r-main-color: #{$mainColor};
--r-block-margin: #{$blockMargin};
--r-heading-margin: #{$headingMargin};
--r-heading-font: #{$headingFont};
--r-heading-color: #{$headingColor};
--r-heading-line-height: #{$headingLineHeight};
--r-heading-letter-spacing: #{$headingLetterSpacing};
--r-heading-text-transform: #{$headingTextTransform};
--r-heading-text-shadow: #{$headingTextShadow};
--r-heading-font-weight: #{$headingFontWeight};
--r-heading1-text-shadow: #{$heading1TextShadow};
--r-heading1-size: #{$heading1Size};
--r-heading2-size: #{$heading2Size};
--r-heading3-size: #{$heading3Size};
--r-heading4-size: #{$heading4Size};
--r-code-font: #{$codeFont};
--r-link-color: #{$linkColor};
--r-link-color-dark: #{darken($linkColor , 15% )};
--r-link-color-hover: #{$linkColorHover};
--r-selection-background-color: #{$selectionBackgroundColor};
--r-selection-color: #{$selectionColor};
--r-overlay-element-bg-color: #{$overlayElementBgColor};
--r-overlay-element-fg-color: #{$overlayElementFgColor};
}
@@ -1,45 +0,0 @@
@mixin vertical-gradient( $top, $bottom ) {
background: $top;
background: -moz-linear-gradient( top, $top 0%, $bottom 100% );
background: -webkit-gradient( linear, left top, left bottom, color-stop(0%,$top), color-stop(100%,$bottom) );
background: -webkit-linear-gradient( top, $top 0%, $bottom 100% );
background: -o-linear-gradient( top, $top 0%, $bottom 100% );
background: -ms-linear-gradient( top, $top 0%, $bottom 100% );
background: linear-gradient( top, $top 0%, $bottom 100% );
}
@mixin horizontal-gradient( $top, $bottom ) {
background: $top;
background: -moz-linear-gradient( left, $top 0%, $bottom 100% );
background: -webkit-gradient( linear, left top, right top, color-stop(0%,$top), color-stop(100%,$bottom) );
background: -webkit-linear-gradient( left, $top 0%, $bottom 100% );
background: -o-linear-gradient( left, $top 0%, $bottom 100% );
background: -ms-linear-gradient( left, $top 0%, $bottom 100% );
background: linear-gradient( left, $top 0%, $bottom 100% );
}
@mixin radial-gradient( $outer, $inner, $type: circle ) {
background: $outer;
background: -moz-radial-gradient( center, $type cover, $inner 0%, $outer 100% );
background: -webkit-gradient( radial, center center, 0px, center center, 100%, color-stop(0%,$inner), color-stop(100%,$outer) );
background: -webkit-radial-gradient( center, $type cover, $inner 0%, $outer 100% );
background: -o-radial-gradient( center, $type cover, $inner 0%, $outer 100% );
background: -ms-radial-gradient( center, $type cover, $inner 0%, $outer 100% );
background: radial-gradient( center, $type cover, $inner 0%, $outer 100% );
}
@mixin light-bg-text-color( $color ) {
section.has-light-background {
&, h1, h2, h3, h4, h5, h6 {
color: $color;
}
}
}
@mixin dark-bg-text-color( $color ) {
section.has-dark-background {
&, h1, h2, h3, h4, h5, h6 {
color: $color;
}
}
}
@@ -1,50 +0,0 @@
// Base settings for all themes that can optionally be
// overridden by the super-theme
// Background of the presentation
$backgroundColor: #2b2b2b;
// Primary/body text
$mainFont: 'Lato', sans-serif;
$mainFontSize: 40px;
$mainColor: #eee;
// Vertical spacing between blocks of text
$blockMargin: 20px;
// Headings
$headingMargin: 0 0 $blockMargin 0;
$headingFont: 'League Gothic', Impact, sans-serif;
$headingColor: #eee;
$headingLineHeight: 1.2;
$headingLetterSpacing: normal;
$headingTextTransform: uppercase;
$headingTextShadow: none;
$headingFontWeight: normal;
$heading1TextShadow: $headingTextShadow;
$heading1Size: 3.77em;
$heading2Size: 2.11em;
$heading3Size: 1.55em;
$heading4Size: 1.00em;
$codeFont: monospace;
// Links and actions
$linkColor: #13DAEC;
$linkColorHover: lighten( $linkColor, 20% );
// Text selection
$selectionBackgroundColor: #FF5E99;
$selectionColor: #fff;
// Colors used for UI elements that are overlaid on top of
// the presentation
$overlayElementBgColor: 240, 240, 240;
$overlayElementFgColor: 0, 0, 0;
// Generates the presentation background, can be overridden
// to return a background image or gradient
@mixin bodyBackground() {
background: $backgroundColor;
}
@@ -1,331 +0,0 @@
// Base theme template for reveal.js
/*********************************************
* GLOBAL STYLES
*********************************************/
@import "./exposer";
.reveal-viewport {
@include bodyBackground();
background-color: var(--r-background-color);
}
.reveal {
font-family: var(--r-main-font);
font-size: var(--r-main-font-size);
font-weight: normal;
color: var(--r-main-color);
}
.reveal ::selection {
color: var(--r-selection-color);
background: var(--r-selection-background-color);
text-shadow: none;
}
.reveal ::-moz-selection {
color: var(--r-selection-color);
background: var(--r-selection-background-color);
text-shadow: none;
}
.reveal .slides section,
.reveal .slides section>section {
line-height: 1.3;
font-weight: inherit;
}
/*********************************************
* HEADERS
*********************************************/
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: var(--r-heading-margin);
color: var(--r-heading-color);
font-family: var(--r-heading-font);
font-weight: var(--r-heading-font-weight);
line-height: var(--r-heading-line-height);
letter-spacing: var(--r-heading-letter-spacing);
text-transform: var(--r-heading-text-transform);
text-shadow: var(--r-heading-text-shadow);
word-wrap: break-word;
}
.reveal h1 {font-size: var(--r-heading1-size); }
.reveal h2 {font-size: var(--r-heading2-size); }
.reveal h3 {font-size: var(--r-heading3-size); }
.reveal h4 {font-size: var(--r-heading4-size); }
.reveal h1 {
text-shadow: var(--r-heading1-text-shadow);
}
/*********************************************
* OTHER
*********************************************/
.reveal p {
margin: var(--r-block-margin) 0;
line-height: 1.3;
}
/* Remove trailing margins after titles */
.reveal h1:last-child,
.reveal h2:last-child,
.reveal h3:last-child,
.reveal h4:last-child,
.reveal h5:last-child,
.reveal h6:last-child {
margin-bottom: 0;
}
/* Ensure certain elements are never larger than the slide itself */
.reveal img,
.reveal video,
.reveal iframe {
max-width: 95%;
max-height: 95%;
}
.reveal strong,
.reveal b {
font-weight: bold;
}
.reveal em {
font-style: italic;
}
.reveal ol,
.reveal dl,
.reveal ul {
display: inline-block;
text-align: left;
margin: 0 0 0 1em;
}
.reveal ol {
list-style-type: decimal;
}
.reveal ul {
list-style-type: disc;
}
.reveal ul ul {
list-style-type: square;
}
.reveal ul ul ul {
list-style-type: circle;
}
.reveal ul ul,
.reveal ul ol,
.reveal ol ol,
.reveal ol ul {
display: block;
margin-left: 40px;
}
.reveal dt {
font-weight: bold;
}
.reveal dd {
margin-left: 40px;
}
.reveal blockquote {
display: block;
position: relative;
width: 70%;
margin: var(--r-block-margin) auto;
padding: 5px;
font-style: italic;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0px 0px 2px rgba(0,0,0,0.2);
}
.reveal blockquote p:first-child,
.reveal blockquote p:last-child {
display: inline-block;
}
.reveal q {
font-style: italic;
}
.reveal pre {
display: block;
position: relative;
width: 90%;
margin: var(--r-block-margin) auto;
text-align: left;
font-size: 0.55em;
font-family: var(--r-code-font);
line-height: 1.2em;
word-wrap: break-word;
box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.15);
}
.reveal code {
font-family: var(--r-code-font);
text-transform: none;
tab-size: 2;
}
.reveal pre code {
display: block;
padding: 5px;
overflow: auto;
max-height: 400px;
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 {
text-align: left;
padding: 0.2em 0.5em 0.2em 0.5em;
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 img {
margin: var(--r-block-margin) 0;
}
/*********************************************
* LINKS
*********************************************/
.reveal a {
color: var(--r-link-color);
text-decoration: none;
transition: color .15s ease;
}
.reveal a:hover {
color: var(--r-link-color-hover);
text-shadow: none;
border: none;
}
.reveal .roll span:after {
color: #fff;
// background: darken( var(--r-link-color), 15% );
background: var(--r-link-color-dark);
}
/*********************************************
* Frame helper
*********************************************/
.reveal .r-frame {
border: 4px solid var(--r-main-color);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);
}
.reveal a .r-frame {
transition: all .15s linear;
}
.reveal a:hover .r-frame {
border-color: var(--r-link-color);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55);
}
/*********************************************
* NAVIGATION CONTROLS
*********************************************/
.reveal .controls {
color: var(--r-link-color);
}
/*********************************************
* PROGRESS BAR
*********************************************/
.reveal .progress {
background: rgba(0,0,0,0.2);
color: var(--r-link-color);
}
/*********************************************
* PRINT BACKGROUND
*********************************************/
@media print {
.backgrounds {
background-color: var(--r-background-color);
}
}
-481
View File
@@ -1,481 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js – The HTML Presentation Framework</title>
<meta name="description" content="A framework for easily creating beautiful presentations using HTML">
<meta name="author" content="Hakim El Hattab">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="dist/reset.css">
<link rel="stylesheet" href="dist/reveal.css">
<link rel="stylesheet" href="dist/theme/black.css" id="theme">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<a href="https://revealjs.com">
<img src="https://static.slid.es/reveal/logo-v1/reveal-white-text.svg" alt="reveal.js logo" style="height: 180px; margin: 0 auto 4rem auto; background: transparent;" class="demo-logo">
</a>
<h3>The HTML Presentation Framework</h3>
<p>
<small>Created by <a href="http://hakim.se">Hakim El Hattab</a> and <a href="https://github.com/hakimel/reveal.js/graphs/contributors">contributors</a></small>
</p>
</section>
<section>
<h2>Hello There</h2>
<p>
reveal.js enables you to create beautiful interactive slide decks using HTML. This presentation will show you examples of what it can do.
</p>
</section>
<!-- Example of nested vertical slides -->
<section>
<section>
<h2>Vertical Slides</h2>
<p>Slides can be nested inside of each other.</p>
<p>Use the <em>Space</em> key to navigate through all slides.</p>
<br>
<a href="#/2/1" class="navigate-down">
<img class="r-frame" style="background: rgba(255,255,255,0.1);" width="178" height="238" data-src="https://static.slid.es/reveal/arrow.png" alt="Down arrow">
</a>
</section>
<section>
<h2>Basement Level 1</h2>
<p>Nested slides are useful for adding additional detail underneath a high level horizontal slide.</p>
</section>
<section>
<h2>Basement Level 2</h2>
<p>That's it, time to go back up.</p>
<br>
<a href="#/2">
<img class="r-frame" style="background: rgba(255,255,255,0.1); transform: rotate(180deg);" width="178" height="238" data-src="https://static.slid.es/reveal/arrow.png" alt="Up arrow">
</a>
</section>
</section>
<section>
<h2>Slides</h2>
<p>
Not a coder? Not a problem. There's a fully-featured visual editor for authoring these, try it out at <a href="https://slides.com" target="_blank">https://slides.com</a>.
</p>
</section>
<section data-visibility="hidden">
<h2>Hidden Slides</h2>
<p>
This slide is visible in the source, but hidden when the presentation is viewed. You can show all hidden slides by setting the `showHiddenSlides` config option to `true`.
</p>
</section>
<section data-auto-animate>
<h2 data-id="code-title">Pretty Code</h2>
<pre data-id="code-animation"><code class="hljs javascript" data-trim data-line-numbers>
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
...
);
}
</code></pre>
<p>Code syntax highlighting courtesy of <a href="https://highlightjs.org/usage/">highlight.js</a>.</p>
</section>
<section data-auto-animate>
<h2 data-id="code-title">With Animations</h2>
<pre data-id="code-animation"><code class="hljs javascript" data-trim data-line-numbers="|4,8-11|17|22-24"><script type="text/template">
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
function SecondExample() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
</script></code></pre>
</section>
<section>
<h2>Point of View</h2>
<p>
Press <strong>ESC</strong> to enter the slide overview.
</p>
<p>
Hold down the <strong>alt</strong> key (<strong>ctrl</strong> in Linux) and click on any element to zoom towards it using <a href="http://lab.hakim.se/zoom-js">zoom.js</a>. Click again to zoom back out.
</p>
<p>
(NOTE: Use ctrl + click in Linux.)
</p>
</section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<h2>Auto-Animate</h2>
<p>Automatically animate matching elements across slides with <a href="https://revealjs.com/auto-animate/">Auto-Animate</a>.</p>
<div class="r-hstack justify-center">
<div data-id="box1" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
<div data-id="box2" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
<div data-id="box3" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
</div>
</section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<div class="r-hstack justify-center">
<div data-id="box1" data-auto-animate-delay="0" style="background: cyan; width: 150px; height: 100px; margin: 10px;"></div>
<div data-id="box2" data-auto-animate-delay="0.1" style="background: magenta; width: 150px; height: 100px; margin: 10px;"></div>
<div data-id="box3" data-auto-animate-delay="0.2" style="background: yellow; width: 150px; height: 100px; margin: 10px;"></div>
</div>
<h2 style="margin-top: 20px;">Auto-Animate</h2>
</section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<div class="r-stack">
<div data-id="box1" style="background: cyan; width: 300px; height: 300px;"></div>
<div data-id="box2" style="background: magenta; width: 200px; height: 200px;"></div>
<div data-id="box3" style="background: yellow; width: 100px; height: 100px;"></div>
</div>
<h2 style="margin-top: 20px;">Auto-Animate</h2>
</section>
<section>
<h2>Touch Optimized</h2>
<p>
Presentations look great on touch devices, like mobile phones and tablets. Simply swipe through your slides.
</p>
</section>
<section data-markdown>
<script type="text/template">
## Markdown Support
Write content using inline or external Markdown.
Instructions and more info available in the [docs](https://revealjs.com/markdown/).
```html []
<section data-markdown>
## Markdown Support
Write content using inline or external Markdown.
Instructions and more info available in the [docs](https://revealjs.com/markdown/).
</section>
```
</script>
</section>
<section>
<p>Add the <code>r-fit-text</code> class to auto-size text</p>
<h2 class="r-fit-text">FIT TEXT</h2>
</section>
<section>
<section id="fragments">
<h2>Fragments</h2>
<p>Hit the next arrow...</p>
<p class="fragment">... to step through ...</p>
<p><span class="fragment">... a</span> <span class="fragment">fragmented</span> <span class="fragment">slide.</span></p>
<aside class="notes">
This slide has fragments which are also stepped through in the notes window.
</aside>
</section>
<section>
<h2>Fragment Styles</h2>
<p>There's different types of fragments, like:</p>
<p class="fragment grow">grow</p>
<p class="fragment shrink">shrink</p>
<p class="fragment fade-out">fade-out</p>
<p>
<span style="display: inline-block;" class="fragment fade-right">fade-right, </span>
<span style="display: inline-block;" class="fragment fade-up">up, </span>
<span style="display: inline-block;" class="fragment fade-down">down, </span>
<span style="display: inline-block;" class="fragment fade-left">left</span>
</p>
<p class="fragment fade-in-then-out">fade-in-then-out</p>
<p class="fragment fade-in-then-semi-out">fade-in-then-semi-out</p>
<p>Highlight <span class="fragment highlight-red">red</span> <span class="fragment highlight-blue">blue</span> <span class="fragment highlight-green">green</span></p>
</section>
</section>
<section id="transitions">
<h2>Transition Styles</h2>
<p>
You can select from different transitions, like: <br>
<a href="?transition=none#/transitions">None</a> -
<a href="?transition=fade#/transitions">Fade</a> -
<a href="?transition=slide#/transitions">Slide</a> -
<a href="?transition=convex#/transitions">Convex</a> -
<a href="?transition=concave#/transitions">Concave</a> -
<a href="?transition=zoom#/transitions">Zoom</a>
</p>
</section>
<section id="themes">
<h2>Themes</h2>
<p>
reveal.js comes with a few themes built in: <br>
<!-- Hacks to swap themes after the page has loaded. Not flexible and only intended for the reveal.js demo deck. -->
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/black.css'); return false;">Black (default)</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/white.css'); return false;">White</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/league.css'); return false;">League</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/sky.css'); return false;">Sky</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/beige.css'); return false;">Beige</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/simple.css'); return false;">Simple</a> <br>
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/serif.css'); return false;">Serif</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/blood.css'); return false;">Blood</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/night.css'); return false;">Night</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/moon.css'); return false;">Moon</a> -
<a href="#/themes" onclick="document.getElementById('theme').setAttribute('href','dist/theme/solarized.css'); return false;">Solarized</a>
</p>
</section>
<section>
<section data-background="#dddddd">
<h2>Slide Backgrounds</h2>
<p>
Set <code>data-background="#dddddd"</code> on a slide to change the background color. All CSS color formats are supported.
</p>
<a href="#" class="navigate-down">
<img class="r-frame" style="background: rgba(255,255,255,0.1);" width="178" height="238" data-src="https://static.slid.es/reveal/arrow.png" alt="Down arrow">
</a>
</section>
<section data-background-gradient="linear-gradient(to bottom, #283b95, #17b2c3)">
<h2>Gradient Backgrounds</h2>
<pre><code class="hljs html wrap">&lt;section data-background-gradient=
"linear-gradient(to bottom, #ddd, #191919)"&gt;</code></pre>
</section>
<section data-background="https://static.slid.es/reveal/image-placeholder.png">
<h2>Image Backgrounds</h2>
<pre><code class="hljs html">&lt;section data-background="image.png"&gt;</code></pre>
</section>
<section data-background="https://static.slid.es/reveal/image-placeholder.png" data-background-repeat="repeat" data-background-size="100px">
<h2>Tiled Backgrounds</h2>
<pre><code class="hljs html" style="word-wrap: break-word;">&lt;section data-background="image.png" data-background-repeat="repeat" data-background-size="100px"&gt;</code></pre>
</section>
<section data-background-video="https://static.slid.es/site/homepage/v1/homepage-video-editor.mp4" data-background-color="#000000">
<div style="background-color: rgba(0, 0, 0, 0.9); color: #fff; padding: 20px;">
<h2>Video Backgrounds</h2>
<pre><code class="hljs html" style="word-wrap: break-word;">&lt;section data-background-video="video.mp4,video.webm"&gt;</code></pre>
</div>
</section>
<section data-background="http://i.giphy.com/90F8aUepslB84.gif">
<h2>... and GIFs!</h2>
</section>
</section>
<section data-transition="slide" data-background="#4d7e65" data-background-transition="zoom">
<h2>Background Transitions</h2>
<p>
Different background transitions are available via the backgroundTransition option. This one's called "zoom".
</p>
<pre><code class="hljs javascript">Reveal.configure({ backgroundTransition: 'zoom' })</code></pre>
</section>
<section data-transition="slide" data-background="#b5533c" data-background-transition="zoom">
<h2>Background Transitions</h2>
<p>
You can override background transitions per-slide.
</p>
<pre><code class="hljs html" style="word-wrap: break-word;">&lt;section data-background-transition="zoom"&gt;</code></pre>
</section>
<section data-background-iframe="https://hakim.se" data-background-interactive>
<div style="position: absolute; width: 40%; right: 0; box-shadow: 0 1px 4px rgba(0,0,0,0.5), 0 5px 25px rgba(0,0,0,0.2); background-color: rgba(0, 0, 0, 0.9); color: #fff; padding: 20px; font-size: 20px; text-align: left;">
<h2>Iframe Backgrounds</h2>
<p>Since reveal.js runs on the web, you can easily embed other web content. Try interacting with the page in the background.</p>
</div>
</section>
<section>
<h2>Marvelous List</h2>
<ul>
<li>No order here</li>
<li>Or here</li>
<li>Or here</li>
<li>Or here</li>
</ul>
</section>
<section>
<h2>Fantastic Ordered List</h2>
<ol>
<li>One is smaller than...</li>
<li>Two is smaller than...</li>
<li>Three!</li>
</ol>
</section>
<section>
<h2>Tabular Tables</h2>
<table>
<thead>
<tr>
<th>Item</th>
<th>Value</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apples</td>
<td>$1</td>
<td>7</td>
</tr>
<tr>
<td>Lemonade</td>
<td>$2</td>
<td>18</td>
</tr>
<tr>
<td>Bread</td>
<td>$3</td>
<td>2</td>
</tr>
</tbody>
</table>
</section>
<section>
<h2>Clever Quotes</h2>
<p>
These guys come in two forms, inline: <q cite="http://searchservervirtualization.techtarget.com/definition/Our-Favorite-Technology-Quotations">The nice thing about standards is that there are so many to choose from</q> and block:
</p>
<blockquote cite="http://searchservervirtualization.techtarget.com/definition/Our-Favorite-Technology-Quotations">
&ldquo;For years there has been a theory that millions of monkeys typing at random on millions of typewriters would
reproduce the entire works of Shakespeare. The Internet has proven this theory to be untrue.&rdquo;
</blockquote>
</section>
<section>
<h2>Intergalactic Interconnections</h2>
<p>
You can link between slides internally,
<a href="#/2/3">like this</a>.
</p>
</section>
<section>
<h2>Speaker View</h2>
<p>There's a <a href="https://revealjs.com/speaker-view/">speaker view</a>. It includes a timer, preview of the upcoming slide as well as your speaker notes.</p>
<p>Press the <em>S</em> key to try it out.</p>
<aside class="notes">
Oh hey, these are some notes. They'll be hidden in your presentation, but you can see them if you open the speaker notes window (hit 's' on your keyboard).
</aside>
</section>
<section>
<h2>Export to PDF</h2>
<p>Presentations can be <a href="https://revealjs.com/pdf-export/">exported to PDF</a>, here's an example:</p>
<iframe data-src="https://www.slideshare.net/slideshow/embed_code/42840540" width="445" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:3px solid #666; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe>
</section>
<section>
<h2>Global State</h2>
<p>
Set <code>data-state="something"</code> on a slide and <code>"something"</code>
will be added as a class to the document element when the slide is open. This lets you
apply broader style changes, like switching the page background.
</p>
</section>
<section data-state="customevent">
<h2>State Events</h2>
<p>
Additionally custom events can be triggered on a per slide basis by binding to the <code>data-state</code> name.
</p>
<pre><code class="javascript" data-trim contenteditable style="font-size: 18px;">
Reveal.on( 'customevent', function() {
console.log( '"customevent" has fired' );
} );
</code></pre>
</section>
<section>
<h2>Take a Moment</h2>
<p>
Press B or . on your keyboard to pause the presentation. This is helpful when you're on stage and want to take distracting slides off the screen.
</p>
</section>
<section>
<h2>Much more</h2>
<ul>
<li>Right-to-left support</li>
<li><a href="https://revealjs.com/api/">Extensive JavaScript API</a></li>
<li><a href="https://revealjs.com/auto-slide/">Auto-progression</a></li>
<li><a href="https://revealjs.com/backgrounds/#parallax-background">Parallax backgrounds</a></li>
<li><a href="https://revealjs.com/keyboard/">Custom keyboard bindings</a></li>
</ul>
</section>
<section style="text-align: left;">
<h1>THE END</h1>
<p>
- <a href="https://slides.com">Try the online editor</a> <br>
- <a href="https://github.com/hakimel/reveal.js">Source code &amp; documentation</a>
</p>
</section>
</div>
</div>
<script src="dist/reveal.js"></script>
<script src="plugin/zoom/zoom.js"></script>
<script src="plugin/notes/notes.js"></script>
<script src="plugin/search/search.js"></script>
<script src="plugin/markdown/markdown.js"></script>
<script src="plugin/highlight/highlight.js"></script>
<script>
// Also available as an ES module, see:
// https://revealjs.com/initialization/
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [ RevealZoom, RevealNotes, RevealSearch, RevealMarkdown, RevealHighlight ]
});
</script>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-526
View File
@@ -1,526 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - 500 slides</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/black.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section><h1>1</h1></section>
<section><h1>2</h1></section>
<section><h1>3</h1></section>
<section><h1>4</h1></section>
<section><h1>5</h1></section>
<section><h1>6</h1></section>
<section><h1>7</h1></section>
<section><h1>8</h1></section>
<section><h1>9</h1></section>
<section><h1>10</h1></section>
<section><h1>11</h1></section>
<section><h1>12</h1></section>
<section><h1>13</h1></section>
<section><h1>14</h1></section>
<section><h1>15</h1></section>
<section><h1>16</h1></section>
<section><h1>17</h1></section>
<section><h1>18</h1></section>
<section><h1>19</h1></section>
<section><h1>20</h1></section>
<section><h1>21</h1></section>
<section><h1>22</h1></section>
<section><h1>23</h1></section>
<section><h1>24</h1></section>
<section><h1>25</h1></section>
<section><h1>26</h1></section>
<section><h1>27</h1></section>
<section><h1>28</h1></section>
<section><h1>29</h1></section>
<section><h1>30</h1></section>
<section><h1>31</h1></section>
<section><h1>32</h1></section>
<section><h1>33</h1></section>
<section><h1>34</h1></section>
<section><h1>35</h1></section>
<section><h1>36</h1></section>
<section><h1>37</h1></section>
<section><h1>38</h1></section>
<section><h1>39</h1></section>
<section><h1>40</h1></section>
<section><h1>41</h1></section>
<section><h1>42</h1></section>
<section><h1>43</h1></section>
<section><h1>44</h1></section>
<section><h1>45</h1></section>
<section><h1>46</h1></section>
<section><h1>47</h1></section>
<section><h1>48</h1></section>
<section><h1>49</h1></section>
<section><h1>50</h1></section>
<section><h1>51</h1></section>
<section><h1>52</h1></section>
<section><h1>53</h1></section>
<section><h1>54</h1></section>
<section><h1>55</h1></section>
<section><h1>56</h1></section>
<section><h1>57</h1></section>
<section><h1>58</h1></section>
<section><h1>59</h1></section>
<section><h1>60</h1></section>
<section><h1>61</h1></section>
<section><h1>62</h1></section>
<section><h1>63</h1></section>
<section><h1>64</h1></section>
<section><h1>65</h1></section>
<section><h1>66</h1></section>
<section><h1>67</h1></section>
<section><h1>68</h1></section>
<section><h1>69</h1></section>
<section><h1>70</h1></section>
<section><h1>71</h1></section>
<section><h1>72</h1></section>
<section><h1>73</h1></section>
<section><h1>74</h1></section>
<section><h1>75</h1></section>
<section><h1>76</h1></section>
<section><h1>77</h1></section>
<section><h1>78</h1></section>
<section><h1>79</h1></section>
<section><h1>80</h1></section>
<section><h1>81</h1></section>
<section><h1>82</h1></section>
<section><h1>83</h1></section>
<section><h1>84</h1></section>
<section><h1>85</h1></section>
<section><h1>86</h1></section>
<section><h1>87</h1></section>
<section><h1>88</h1></section>
<section><h1>89</h1></section>
<section><h1>90</h1></section>
<section><h1>91</h1></section>
<section><h1>92</h1></section>
<section><h1>93</h1></section>
<section><h1>94</h1></section>
<section><h1>95</h1></section>
<section><h1>96</h1></section>
<section><h1>97</h1></section>
<section><h1>98</h1></section>
<section><h1>99</h1></section>
<section><h1>100</h1></section>
<section><h1>101</h1></section>
<section><h1>102</h1></section>
<section><h1>103</h1></section>
<section><h1>104</h1></section>
<section><h1>105</h1></section>
<section><h1>106</h1></section>
<section><h1>107</h1></section>
<section><h1>108</h1></section>
<section><h1>109</h1></section>
<section><h1>110</h1></section>
<section><h1>111</h1></section>
<section><h1>112</h1></section>
<section><h1>113</h1></section>
<section><h1>114</h1></section>
<section><h1>115</h1></section>
<section><h1>116</h1></section>
<section><h1>117</h1></section>
<section><h1>118</h1></section>
<section><h1>119</h1></section>
<section><h1>120</h1></section>
<section><h1>121</h1></section>
<section><h1>122</h1></section>
<section><h1>123</h1></section>
<section><h1>124</h1></section>
<section><h1>125</h1></section>
<section><h1>126</h1></section>
<section><h1>127</h1></section>
<section><h1>128</h1></section>
<section><h1>129</h1></section>
<section><h1>130</h1></section>
<section><h1>131</h1></section>
<section><h1>132</h1></section>
<section><h1>133</h1></section>
<section><h1>134</h1></section>
<section><h1>135</h1></section>
<section><h1>136</h1></section>
<section><h1>137</h1></section>
<section><h1>138</h1></section>
<section><h1>139</h1></section>
<section><h1>140</h1></section>
<section><h1>141</h1></section>
<section><h1>142</h1></section>
<section><h1>143</h1></section>
<section><h1>144</h1></section>
<section><h1>145</h1></section>
<section><h1>146</h1></section>
<section><h1>147</h1></section>
<section><h1>148</h1></section>
<section><h1>149</h1></section>
<section><h1>150</h1></section>
<section><h1>151</h1></section>
<section><h1>152</h1></section>
<section><h1>153</h1></section>
<section><h1>154</h1></section>
<section><h1>155</h1></section>
<section><h1>156</h1></section>
<section><h1>157</h1></section>
<section><h1>158</h1></section>
<section><h1>159</h1></section>
<section><h1>160</h1></section>
<section><h1>161</h1></section>
<section><h1>162</h1></section>
<section><h1>163</h1></section>
<section><h1>164</h1></section>
<section><h1>165</h1></section>
<section><h1>166</h1></section>
<section><h1>167</h1></section>
<section><h1>168</h1></section>
<section><h1>169</h1></section>
<section><h1>170</h1></section>
<section><h1>171</h1></section>
<section><h1>172</h1></section>
<section><h1>173</h1></section>
<section><h1>174</h1></section>
<section><h1>175</h1></section>
<section><h1>176</h1></section>
<section><h1>177</h1></section>
<section><h1>178</h1></section>
<section><h1>179</h1></section>
<section><h1>180</h1></section>
<section><h1>181</h1></section>
<section><h1>182</h1></section>
<section><h1>183</h1></section>
<section><h1>184</h1></section>
<section><h1>185</h1></section>
<section><h1>186</h1></section>
<section><h1>187</h1></section>
<section><h1>188</h1></section>
<section><h1>189</h1></section>
<section><h1>190</h1></section>
<section><h1>191</h1></section>
<section><h1>192</h1></section>
<section><h1>193</h1></section>
<section><h1>194</h1></section>
<section><h1>195</h1></section>
<section><h1>196</h1></section>
<section><h1>197</h1></section>
<section><h1>198</h1></section>
<section><h1>199</h1></section>
<section><h1>200</h1></section>
<section><h1>201</h1></section>
<section><h1>202</h1></section>
<section><h1>203</h1></section>
<section><h1>204</h1></section>
<section><h1>205</h1></section>
<section><h1>206</h1></section>
<section><h1>207</h1></section>
<section><h1>208</h1></section>
<section><h1>209</h1></section>
<section><h1>210</h1></section>
<section><h1>211</h1></section>
<section><h1>212</h1></section>
<section><h1>213</h1></section>
<section><h1>214</h1></section>
<section><h1>215</h1></section>
<section><h1>216</h1></section>
<section><h1>217</h1></section>
<section><h1>218</h1></section>
<section><h1>219</h1></section>
<section><h1>220</h1></section>
<section><h1>221</h1></section>
<section><h1>222</h1></section>
<section><h1>223</h1></section>
<section><h1>224</h1></section>
<section><h1>225</h1></section>
<section><h1>226</h1></section>
<section><h1>227</h1></section>
<section><h1>228</h1></section>
<section><h1>229</h1></section>
<section><h1>230</h1></section>
<section><h1>231</h1></section>
<section><h1>232</h1></section>
<section><h1>233</h1></section>
<section><h1>234</h1></section>
<section><h1>235</h1></section>
<section><h1>236</h1></section>
<section><h1>237</h1></section>
<section><h1>238</h1></section>
<section><h1>239</h1></section>
<section><h1>240</h1></section>
<section><h1>241</h1></section>
<section><h1>242</h1></section>
<section><h1>243</h1></section>
<section><h1>244</h1></section>
<section><h1>245</h1></section>
<section><h1>246</h1></section>
<section><h1>247</h1></section>
<section><h1>248</h1></section>
<section><h1>249</h1></section>
<section><h1>250</h1></section>
<section><h1>251</h1></section>
<section><h1>252</h1></section>
<section><h1>253</h1></section>
<section><h1>254</h1></section>
<section><h1>255</h1></section>
<section><h1>256</h1></section>
<section><h1>257</h1></section>
<section><h1>258</h1></section>
<section><h1>259</h1></section>
<section><h1>260</h1></section>
<section><h1>261</h1></section>
<section><h1>262</h1></section>
<section><h1>263</h1></section>
<section><h1>264</h1></section>
<section><h1>265</h1></section>
<section><h1>266</h1></section>
<section><h1>267</h1></section>
<section><h1>268</h1></section>
<section><h1>269</h1></section>
<section><h1>270</h1></section>
<section><h1>271</h1></section>
<section><h1>272</h1></section>
<section><h1>273</h1></section>
<section><h1>274</h1></section>
<section><h1>275</h1></section>
<section><h1>276</h1></section>
<section><h1>277</h1></section>
<section><h1>278</h1></section>
<section><h1>279</h1></section>
<section><h1>280</h1></section>
<section><h1>281</h1></section>
<section><h1>282</h1></section>
<section><h1>283</h1></section>
<section><h1>284</h1></section>
<section><h1>285</h1></section>
<section><h1>286</h1></section>
<section><h1>287</h1></section>
<section><h1>288</h1></section>
<section><h1>289</h1></section>
<section><h1>290</h1></section>
<section><h1>291</h1></section>
<section><h1>292</h1></section>
<section><h1>293</h1></section>
<section><h1>294</h1></section>
<section><h1>295</h1></section>
<section><h1>296</h1></section>
<section><h1>297</h1></section>
<section><h1>298</h1></section>
<section><h1>299</h1></section>
<section><h1>300</h1></section>
<section><h1>301</h1></section>
<section><h1>302</h1></section>
<section><h1>303</h1></section>
<section><h1>304</h1></section>
<section><h1>305</h1></section>
<section><h1>306</h1></section>
<section><h1>307</h1></section>
<section><h1>308</h1></section>
<section><h1>309</h1></section>
<section><h1>310</h1></section>
<section><h1>311</h1></section>
<section><h1>312</h1></section>
<section><h1>313</h1></section>
<section><h1>314</h1></section>
<section><h1>315</h1></section>
<section><h1>316</h1></section>
<section><h1>317</h1></section>
<section><h1>318</h1></section>
<section><h1>319</h1></section>
<section><h1>320</h1></section>
<section><h1>321</h1></section>
<section><h1>322</h1></section>
<section><h1>323</h1></section>
<section><h1>324</h1></section>
<section><h1>325</h1></section>
<section><h1>326</h1></section>
<section><h1>327</h1></section>
<section><h1>328</h1></section>
<section><h1>329</h1></section>
<section><h1>330</h1></section>
<section><h1>331</h1></section>
<section><h1>332</h1></section>
<section><h1>333</h1></section>
<section><h1>334</h1></section>
<section><h1>335</h1></section>
<section><h1>336</h1></section>
<section><h1>337</h1></section>
<section><h1>338</h1></section>
<section><h1>339</h1></section>
<section><h1>340</h1></section>
<section><h1>341</h1></section>
<section><h1>342</h1></section>
<section><h1>343</h1></section>
<section><h1>344</h1></section>
<section><h1>345</h1></section>
<section><h1>346</h1></section>
<section><h1>347</h1></section>
<section><h1>348</h1></section>
<section><h1>349</h1></section>
<section><h1>350</h1></section>
<section><h1>351</h1></section>
<section><h1>352</h1></section>
<section><h1>353</h1></section>
<section><h1>354</h1></section>
<section><h1>355</h1></section>
<section><h1>356</h1></section>
<section><h1>357</h1></section>
<section><h1>358</h1></section>
<section><h1>359</h1></section>
<section><h1>360</h1></section>
<section><h1>361</h1></section>
<section><h1>362</h1></section>
<section><h1>363</h1></section>
<section><h1>364</h1></section>
<section><h1>365</h1></section>
<section><h1>366</h1></section>
<section><h1>367</h1></section>
<section><h1>368</h1></section>
<section><h1>369</h1></section>
<section><h1>370</h1></section>
<section><h1>371</h1></section>
<section><h1>372</h1></section>
<section><h1>373</h1></section>
<section><h1>374</h1></section>
<section><h1>375</h1></section>
<section><h1>376</h1></section>
<section><h1>377</h1></section>
<section><h1>378</h1></section>
<section><h1>379</h1></section>
<section><h1>380</h1></section>
<section><h1>381</h1></section>
<section><h1>382</h1></section>
<section><h1>383</h1></section>
<section><h1>384</h1></section>
<section><h1>385</h1></section>
<section><h1>386</h1></section>
<section><h1>387</h1></section>
<section><h1>388</h1></section>
<section><h1>389</h1></section>
<section><h1>390</h1></section>
<section><h1>391</h1></section>
<section><h1>392</h1></section>
<section><h1>393</h1></section>
<section><h1>394</h1></section>
<section><h1>395</h1></section>
<section><h1>396</h1></section>
<section><h1>397</h1></section>
<section><h1>398</h1></section>
<section><h1>399</h1></section>
<section><h1>400</h1></section>
<section><h1>401</h1></section>
<section><h1>402</h1></section>
<section><h1>403</h1></section>
<section><h1>404</h1></section>
<section><h1>405</h1></section>
<section><h1>406</h1></section>
<section><h1>407</h1></section>
<section><h1>408</h1></section>
<section><h1>409</h1></section>
<section><h1>410</h1></section>
<section><h1>411</h1></section>
<section><h1>412</h1></section>
<section><h1>413</h1></section>
<section><h1>414</h1></section>
<section><h1>415</h1></section>
<section><h1>416</h1></section>
<section><h1>417</h1></section>
<section><h1>418</h1></section>
<section><h1>419</h1></section>
<section><h1>420</h1></section>
<section><h1>421</h1></section>
<section><h1>422</h1></section>
<section><h1>423</h1></section>
<section><h1>424</h1></section>
<section><h1>425</h1></section>
<section><h1>426</h1></section>
<section><h1>427</h1></section>
<section><h1>428</h1></section>
<section><h1>429</h1></section>
<section><h1>430</h1></section>
<section><h1>431</h1></section>
<section><h1>432</h1></section>
<section><h1>433</h1></section>
<section><h1>434</h1></section>
<section><h1>435</h1></section>
<section><h1>436</h1></section>
<section><h1>437</h1></section>
<section><h1>438</h1></section>
<section><h1>439</h1></section>
<section><h1>440</h1></section>
<section><h1>441</h1></section>
<section><h1>442</h1></section>
<section><h1>443</h1></section>
<section><h1>444</h1></section>
<section><h1>445</h1></section>
<section><h1>446</h1></section>
<section><h1>447</h1></section>
<section><h1>448</h1></section>
<section><h1>449</h1></section>
<section><h1>450</h1></section>
<section><h1>451</h1></section>
<section><h1>452</h1></section>
<section><h1>453</h1></section>
<section><h1>454</h1></section>
<section><h1>455</h1></section>
<section><h1>456</h1></section>
<section><h1>457</h1></section>
<section><h1>458</h1></section>
<section><h1>459</h1></section>
<section><h1>460</h1></section>
<section><h1>461</h1></section>
<section><h1>462</h1></section>
<section><h1>463</h1></section>
<section><h1>464</h1></section>
<section><h1>465</h1></section>
<section><h1>466</h1></section>
<section><h1>467</h1></section>
<section><h1>468</h1></section>
<section><h1>469</h1></section>
<section><h1>470</h1></section>
<section><h1>471</h1></section>
<section><h1>472</h1></section>
<section><h1>473</h1></section>
<section><h1>474</h1></section>
<section><h1>475</h1></section>
<section><h1>476</h1></section>
<section><h1>477</h1></section>
<section><h1>478</h1></section>
<section><h1>479</h1></section>
<section><h1>480</h1></section>
<section><h1>481</h1></section>
<section><h1>482</h1></section>
<section><h1>483</h1></section>
<section><h1>484</h1></section>
<section><h1>485</h1></section>
<section><h1>486</h1></section>
<section><h1>487</h1></section>
<section><h1>488</h1></section>
<section><h1>489</h1></section>
<section><h1>490</h1></section>
<section><h1>491</h1></section>
<section><h1>492</h1></section>
<section><h1>493</h1></section>
<section><h1>494</h1></section>
<section><h1>495</h1></section>
<section><h1>496</h1></section>
<section><h1>497</h1></section>
<section><h1>498</h1></section>
<section><h1>499</h1></section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script>
Reveal.initialize({
transition: 'linear'
});
</script>
</body>
</html>
@@ -1,2 +0,0 @@
Source: https://freesound.org/people/fennelliott/sounds/379419/
License: CC0 (public domain)
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

@@ -1,225 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Auto Animate</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/black.css" id="theme">
<link rel="stylesheet" href="../plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-auto-animate data-auto-animate-unmatched="fade">
<h3>Auto-Animate Example</h3>
<p>This will fade out</p>
<img src="assets/image1.png" style="height: 100px;">
<pre data-id="code"><code data-line-numbers class="hljs" data-trim>
function Example() {
const [count, setCount] = useState(0);
}
</code></pre>
</section>
<section data-auto-animate data-auto-animate-unmatched="fade">
<h3>Auto-Animate Example</h3>
<p style="opacity: 0.2; margin-top: 100px;">This will fade out</p>
<p>This element is unmatched</p>
<img src="assets/image1.png" style="height: 150px;">
<pre data-id="code"><code data-line-numbers class="hljs" data-trim>
function Example() {
New line!
const [count, setCount] = useState(0);
}
</code></pre>
</section>
<section data-auto-animate>
<p data-id="text-props" style="background: #555; line-height: 1em; letter-spacing: 0em;">Line Height & Letter Spacing</p>
</section>
<section data-auto-animate>
<p data-id="text-props" style="background: #555; line-height: 3em; letter-spacing: 0.2em;">Line Height & Letter Spacing</p>
</section>
<section>
<section data-auto-animate>
<pre data-id="code"><code data-line-numbers class="hljs" data-trim>
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
...
);
}
</code></pre>
</section>
<section data-auto-animate>
<pre data-id="code"><code data-line-numbers class="hljs" data-trim>
function Example() {
const [count, setCount] = useState(0);
return (
&lt;div&gt;
&lt;p&gt;You clicked {count} times&lt;/p&gt;
&lt;button onClick={() =&gt; setCount(count + 1)}&gt;
Click me
&lt;/button&gt;
&lt;/div&gt;
);
}
</code></pre>
</section>
<section data-auto-animate>
<pre data-id="code"><code data-line-numbers class="hljs" data-trim>
function Example() {
// A comment!
const [count, setCount] = useState(0);
return (
&lt;div&gt;
&lt;p&gt;You clicked {count} times&lt;/p&gt;
&lt;button onClick={() =&gt; setCount(count + 1)}&gt;
Click me
&lt;/button&gt;
&lt;/div&gt;
);
}
</code></pre>
</section>
</section>
<section>
<section data-auto-animate>
<h3>Swapping list items</h3>
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
</section>
<section data-auto-animate>
<h3>Swapping list items</h3>
<ul>
<li>Two</li>
<li>One</li>
<li>Three</li>
</ul>
</section>
<section data-auto-animate>
<h3>Swapping list items</h3>
<ul>
<li>Two</li>
<li>Three</li>
<li>One</li>
</ul>
</section>
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 1</h3>
<h2 data-id="title" style="margin-top: 260px;">Animate Anything</h2>
<div data-id="1" style="background: white; position: absolute; top: 150px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: white; position: absolute; top: 150px; left: 36%; width: 60px; height: 60px;"></div>
<div data-id="3" style="background: white; position: absolute; top: 150px; left: 56%; width: 60px; height: 60px;"></div>
<div data-id="4" style="background: white; position: absolute; top: 150px; left: 76%; width: 60px; height: 60px;"></div>
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 2</h3>
<h2 data-id="title" style="margin-top: 500px">With Auto Animate</h2>
<div data-id="1" style="background: cyan; position: absolute; bottom: 190px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: magenta; position: absolute; bottom: 190px; left: 36%; width: 60px; height: 160px;"></div>
<div data-id="3" style="background: yellow; position: absolute; bottom: 190px; left: 56%; width: 60px; height: 260px;"></div>
<div data-id="4" style="background: red; position: absolute; bottom: 190px; left: 76%; width: 60px; height: 360px;"></div>
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 3</h3>
<h2 data-id="title" style="margin-top: 500px; opacity: 0;">With Auto Animate</h2>
<div data-id="1" style="background: cyan; position: absolute; top: 50%; left: 50%; width: 400px; height: 400px; margin: -200px 0 0 -200px; border-radius: 400px;"></div>
<div data-id="2" style="background: magenta; position: absolute; top: 50%; left: 50%; width: 300px; height: 300px; margin: -150px 0 0 -150px; border-radius: 400px;"></div>
<div data-id="3" style="background: yellow; position: absolute; top: 50%; left: 50%; width: 200px; height: 200px; margin: -100px 0 0 -100px; border-radius: 400px;"></div>
<div data-id="4" style="background: red; position: absolute; top: 50%; left: 50%; width: 100px; height: 100px; margin: -50px 0 0 -50px; border-radius: 400px;"></div>
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 3</h3>
<h2 data-id="title" style="margin-top: 500px; opacity: 0;">With Auto Animate</h2>
<div data-id="1" style="background: red; position: absolute; top: 250px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: yellow; position: absolute; top: 250px; left: 36%; width: 60px; height: 60px;"></div>
<div data-id="3" style="background: magenta; position: absolute; top: 250px; left: 56%; width: 60px; height: 60px;"></div>
<div data-id="4" style="background: cyan; position: absolute; top: 250px; left: 76%; width: 60px; height: 60px;"></div>
</section>
<section data-auto-animate data-auto-animate-id="a">
<h2>data-auto-animate-id="a"</h2>
<h3>A1</h3>
</section>
<section data-auto-animate data-auto-animate-id="a">
<h2>data-auto-animate-id="a"</h2>
<h3>A1</h3>
<h3>A2</h3>
</section>
<section data-auto-animate data-auto-animate-id="b">
<h2>data-auto-animate-id="b"</h2>
<h3>B1</h3>
</section>
<section data-auto-animate data-auto-animate-id="b">
<h2>data-auto-animate-id="b"</h2>
<h3>B1</h3>
<h3>B2</h3>
</section>
<section>
<section id="stacked-slide-1" data-auto-animate>
<a href="#/stacked-slide-1">Slide 1</a><br>
<a href="#/stacked-slide-2">Slide 2</a><br>
<a href="#/stacked-slide-3">Slide 3</a><br>
<a href="#/stacked-slide-4">Slide 4</a><br>
<div data-id="anim" style="background: indigo; padding: 8px; width: 50px; height: 50px; position: absolute; left: 0px;">A</div>
</section>
<section id="stacked-slide-2" data-auto-animate>
<a href="#/stacked-slide-1">Slide 1</a><br>
<a href="#/stacked-slide-2">Slide 2</a><br>
<a href="#/stacked-slide-3">Slide 3</a><br>
<a href="#/stacked-slide-4">Slide 4</a><br>
<div data-id="anim" style="background: indigo; padding: 8px; width: 50px; height: 50px; position: absolute; left: 25%;">A</div>
</section>
<section id="stacked-slide-3" data-auto-animate>
<a href="#/stacked-slide-1">Slide 1</a><br>
<a href="#/stacked-slide-2">Slide 2</a><br>
<a href="#/stacked-slide-3">Slide 3</a><br>
<a href="#/stacked-slide-4">Slide 4</a><br>
<div data-id="anim" style="background: indigo; padding: 8px; width: 50px; height: 50px; position: absolute; left: 50%;">A</div>
</section>
<section id="stacked-slide-4" data-auto-animate>
<a href="#/stacked-slide-1">Slide 1</a><br>
<a href="#/stacked-slide-2">Slide 2</a><br>
<a href="#/stacked-slide-3">Slide 3</a><br>
<a href="#/stacked-slide-4">Slide 4</a><br>
<div data-id="anim" style="background: indigo; padding: 8px; width: 50px; height: 50px; position: absolute; left: 75%;">A</div>
</section>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script src="../plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
center: true,
hash: true,
plugins: [ RevealHighlight ]
});
</script>
</body>
</html>
@@ -1,141 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Slide Backgrounds</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/serif.css" id="theme">
<style type="text/css" media="screen">
.slides section.has-dark-background,
.slides section.has-dark-background h2 {
color: #fff;
}
.slides section.has-light-background,
.slides section.has-light-background h2 {
color: #222;
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-background="#00ffff">
<h2>data-background: #00ffff</h2>
</section>
<section data-background="#bb00bb">
<h2>data-background: #bb00bb</h2>
</section>
<section data-background-color="lightblue">
<h2>data-background: lightblue</h2>
</section>
<section>
<section data-background="#ff0000">
<h2>data-background: #ff0000</h2>
</section>
<section data-background="rgba(0, 0, 0, 0.2)">
<h2>data-background: rgba(0, 0, 0, 0.2)</h2>
</section>
<section data-background="salmon">
<h2>data-background: salmon</h2>
</section>
</section>
<section data-background="rgba(0, 100, 100, 0.2)">
<section>
<h2>Background applied to stack</h2>
</section>
<section>
<h2>Background applied to stack</h2>
</section>
<section data-background="rgb(66, 66, 66)">
<h2>Background applied to slide inside of stack</h2>
</section>
</section>
<section data-background-transition="slide" data-background="assets/image1.png">
<h2>Background image</h2>
</section>
<section>
<section data-background-transition="slide" data-background="assets/image1.png">
<h2>Background image</h2>
</section>
<section data-background-transition="slide" data-background="assets/image1.png">
<h2>Background image</h2>
</section>
</section>
<section data-background="assets/image2.png" data-background-size="100px" data-background-repeat="repeat" data-background-color="#111">
<h2>Background image</h2>
<pre>data-background-size="100px" data-background-repeat="repeat" data-background-color="#111"</pre>
</section>
<section data-background="#888888">
<h2>Same background twice (1/2)</h2>
</section>
<section data-background="#888888">
<h2>Same background twice (2/2)</h2>
</section>
<section data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<h2>Video background</h2>
</section>
<section data-background-iframe="https://slides.com/news/make-better-presentations/embed?style=hidden&autoSlide=4000">
<h2>Iframe background</h2>
</section>
<section>
<section data-background="#417203">
<h2>Same background twice vertical (1/2)</h2>
</section>
<section data-background="#417203">
<h2>Same background twice vertical (2/2)</h2>
</section>
</section>
<section data-background="#934f4d">
<h2>Same background from horizontal to vertical (1/3)</h2>
</section>
<section>
<section data-background="#934f4d">
<h2>Same background from horizontal to vertical (2/3)</h2>
</section>
<section data-background="#934f4d">
<h2>Same background from horizontal to vertical (3/3)</h2>
</section>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script>
// Full list of configuration options:
// https://revealjs.revealjs.com/config/
Reveal.initialize({
center: true,
transition: 'linear',
// transitionSpeed: 'slow',
// backgroundTransition: 'slide'
});
</script>
</body>
</html>
-32
View File
@@ -1,32 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Barebones</title>
<link rel="stylesheet" href="../dist/reveal.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h2>Barebones Presentation</h2>
<p>This example contains the bare minimum includes and markup required to run a reveal.js presentation.</p>
</section>
<section>
<h2>No Theme</h2>
<p>There's no theme included, so it will fall back on browser defaults.</p>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script>
Reveal.initialize();
</script>
</body>
</html>
@@ -1,160 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Layout Helpers</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h2>Layout Helper Examples</h2>
<ul>
<li><a href="#/fit-text">Big Text</a></li>
<li><a href="#/stretch">Stretch</a></li>
<li><a href="#/stack">Stack</a></li>
<li><a href="#/hstack">HStack</a></li>
<li><a href="#/vstack">VStack</a></li>
</ul>
</section>
<section id="fit-text">
<h2>Fit Text</h2>
<p>Resizes text to be as large as possible within its container.</p>
<pre><code class="html" data-trim data-line-numbers>
<h2 class="r-fit-text">FIT</h2>
</code></pre>
</section>
<section>
<h2 class="r-fit-text">FIT</h2>
</section>
<section>
<h2 class="r-fit-text">HELLO WORLD</h2>
<h2 class="r-fit-text">BOTH THESE TITLES USE FIT-TEXT</h2>
</section>
<section id="stretch">
<h2>Stretch</h2>
<p>Makes an element as tall as possible while remaining within the slide bounds.</p>
<pre><code class="html" data-trim data-line-numbers>
<h2>Stretch Example</h2>
<img src="assets/image2.png" class="r-stretch">
<p>Image byline</p>
</code></pre>
</section>
<section>
<h2>Stretch Example</h2>
<img src="assets/image2.png" class="r-stretch">
<p>Image byline</p>
</section>
<section id="stack">
<h2>Stack</h2>
<p>Stacks multiple elements on top of each other, for use with fragments.</p>
<pre><code class="html" data-trim data-line-numbers>
<div class="r-stack">
&lt;img class="fragment" width="450" height="300" src="..."&gt;
&lt;img class="fragment" width="300" height="450" src="..."&gt;
&lt;img class="fragment" width="400" height="400" src="..."&gt;
</div>
</code></pre>
</section>
<section>
<h2>Stack Example</h2>
<div class="r-stack">
<p class="fragment fade-in-then-out">One</p>
<p class="fragment fade-in-then-out">Two</p>
<p class="fragment fade-in-then-out">Three</p>
<p class="fragment fade-in-then-out">Four</p>
</div>
<div class="r-stack">
<img src="https://placekitten.com/450/300" width="450" height="300" class="fragment">
<img src="https://placekitten.com/300/450" width="300" height="450" class="fragment">
<img src="https://placekitten.com/400/400" width="400" height="400" class="fragment">
</div>
</section>
<section>
<h2>Stack Example</h2>
<p>fade-in-then-out fragments</p>
<div class="r-stack">
<img src="https://placekitten.com/450/300" width="450" height="300" class="fragment fade-in-then-out">
<img src="https://placekitten.com/300/450" width="300" height="450" class="fragment fade-in-then-out">
<img src="https://placekitten.com/400/400" width="400" height="400" class="fragment fade-in-then-out">
</div>
</section>
<section id="hstack">
<h2>HStack</h2>
<p>Stacks multiple elements horizontally.</p>
<pre><code class="html" data-trim data-line-numbers>
<div class="r-hstack">
&lt;img width="450" height="300" src="..."&gt;
&lt;img width="300" height="450" src="..."&gt;
&lt;img width="400" height="400" src="..."&gt;
</div>
</code></pre>
</section>
<section data-auto-animate>
<h2>HStack Example</h2>
<div class="r-hstack">
<p style="padding: 0.50em; background: #eee; margin: 0.25em">One</p>
<p style="padding: 0.75em; background: #eee; margin: 0.25em">Two</p>
<p style="padding: 1.00em; background: #eee; margin: 0.25em">Three</p>
</div>
</section>
<section id="vstack">
<h2>VStack</h2>
<p>Stacks multiple elements vertically.</p>
<pre><code class="html" data-trim data-line-numbers>
<div class="r-vstack">
&lt;img width="450" height="300" src="..."&gt;
&lt;img width="300" height="450" src="..."&gt;
&lt;img width="400" height="400" src="..."&gt;
</div>
</code></pre>
</section>
<section data-auto-animate>
<h2>VStack Example</h2>
<div class="r-vstack">
<p style="padding: 0.50em; background: #eee; margin: 0.25em">One</p>
<p style="padding: 0.75em; background: #eee; margin: 0.25em">Two</p>
<p style="padding: 1.00em; background: #eee; margin: 0.25em">Three</p>
</div>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script src="../plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
center: true,
hash: true,
plugins: [ RevealHighlight ]
});
</script>
</body>
</html>
-161
View File
@@ -1,161 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Markdown Example</title>
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<!-- Use external markdown resource, separate slides by three newlines; vertical slides by two newlines -->
<section data-markdown="markdown.md" data-separator="^\n\n\n" data-separator-vertical="^\n\n"></section>
<!-- Slides are separated by three dashes (the default) -->
<section data-markdown>
<script type="text/template">
## Demo 1
Slide 1
---
## Demo 1
Slide 2
---
## Demo 1
Slide 3
</script>
</section>
<!-- Slides are separated by regexp matching newline + three dashes + newline, vertical slides identical but two dashes -->
<section data-markdown data-separator="^\n---\n$" data-separator-vertical="^\n--\n$">
<script type="text/template">
## Demo 2
Slide 1.1
--
## Demo 2
Slide 1.2
---
## Demo 2
Slide 2
</script>
</section>
<!-- No "extra" slides, since the separator can't be matched ("---" will become horizontal rulers) -->
<section data-markdown data-separator="$x">
<script type="text/template">
A
---
B
---
C
</script>
</section>
<!-- Slide attributes -->
<section data-markdown>
<script type="text/template">
<!-- .slide: data-background="#000000" -->
## Slide attributes
</script>
</section>
<!-- Element attributes -->
<section data-markdown>
<script type="text/template">
## Element attributes
- Item 1 <!-- .element: class="fragment" data-fragment-index="2" -->
- Item 2 <!-- .element: class="fragment" data-fragment-index="1" -->
</script>
</section>
<!-- Code -->
<section data-markdown>
<script type="text/template">
```php [1|3-5]
public function foo()
{
$foo = array(
'bar' => 'bar'
)
}
```
</script>
</section>
<!-- add optional line count offset, in this case 287 -->
<section data-markdown>
<script type="text/template">
## echo.c
```c [287: 2|4,6]
/* All of the options in this arg are valid, so handle them. */
p = arg + 1;
do {
if (*p == 'n')
nflag = 0;
if (*p == 'e')
eflag = '\\';
} while (*++p);
```
[source](https://git.busybox.net/busybox/tree/coreutils/echo.c?h=1_36_stable#n287)
</script>
</section>
<!-- Images -->
<section data-markdown>
<script type="text/template">
![Sample image](https://s3.amazonaws.com/static.slid.es/logo/v2/slides-symbol-512x512.png)
</script>
</section>
<!-- Math -->
<section data-markdown>
## The Lorenz Equations
`\[\begin{aligned}
\dot{x} &amp; = \sigma(y-x) \\
\dot{y} &amp; = \rho x - y - xz \\
\dot{z} &amp; = -\beta z + xy
\end{aligned} \]`
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script src="../plugin/markdown/markdown.js"></script>
<script src="../plugin/highlight/highlight.js"></script>
<script src="../plugin/notes/notes.js"></script>
<script src="../plugin/math/math.js"></script>
<script>
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes, RevealMath.KaTeX ]
});
</script>
</body>
</html>
-41
View File
@@ -1,41 +0,0 @@
# Markdown Demo
## External 1.1
Content 1.1
Note: This will only appear in the speaker notes window.
## External 1.2
Content 1.2
## External 2
Content 2.1
## External 3.1
Content 3.1
## External 3.2
Content 3.2
## External 3.3 (Image)
![External Image](https://s3.amazonaws.com/static.slid.es/logo/v2/slides-symbol-512x512.png)
## External 3.4 (Math)
`\[ J(\theta_0,\theta_1) = \sum_{i=0} \]`
-206
View File
@@ -1,206 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Math Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/night.css" id="theme">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h2>reveal.js Math Plugin</h2>
<p>Render math with KaTeX, MathJax 2 or MathJax 3</p>
</section>
<section>
<h3>The Lorenz Equations</h3>
\[\begin{aligned}
\dot{x} &amp; = \sigma(y-x) \\
\dot{y} &amp; = \rho x - y - xz \\
\dot{z} &amp; = -\beta z + xy
\end{aligned} \]
</section>
<section>
<h3>The Cauchy-Schwarz Inequality</h3>
<script type="math/tex; mode=display">
\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
</script>
</section>
<section>
<h3>A Cross Product Formula</h3>
\[\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} &amp; \mathbf{j} &amp; \mathbf{k} \\
\frac{\partial X}{\partial u} &amp; \frac{\partial Y}{\partial u} &amp; 0 \\
\frac{\partial X}{\partial v} &amp; \frac{\partial Y}{\partial v} &amp; 0
\end{vmatrix} \]
</section>
<section>
<h3>The probability of getting \(k\) heads when flipping \(n\) coins is</h3>
\[P(E) = {n \choose k} p^k (1-p)^{ n-k} \]
</section>
<section>
<h3>An Identity of Ramanujan</h3>
\[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } } \]
</section>
<section>
<h3>A Rogers-Ramanujan Identity</h3>
\[ 1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})}\]
</section>
<section>
<h3>Maxwell&#8217;s Equations</h3>
\[ \begin{aligned}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} &amp; = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} &amp; = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} &amp; = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} &amp; = 0 \end{aligned}
\]
</section>
<section>
<h3>TeX Macros</h3>
Here is a common vector space:
\[L^2(\R) = \set{u : \R \to \R}{\int_\R |u|^2 &lt; +\infty}\]
used in functional analysis.
</section>
<section>
<section>
<h3>The Lorenz Equations</h3>
<div class="fragment">
\[\begin{aligned}
\dot{x} &amp; = \sigma(y-x) \\
\dot{y} &amp; = \rho x - y - xz \\
\dot{z} &amp; = -\beta z + xy
\end{aligned} \]
</div>
</section>
<section>
<h3>The Cauchy-Schwarz Inequality</h3>
<div class="fragment">
\[ \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \]
</div>
</section>
<section>
<h3>A Cross Product Formula</h3>
<div class="fragment">
\[\mathbf{V}_1 \times \mathbf{V}_2 = \begin{vmatrix}
\mathbf{i} &amp; \mathbf{j} &amp; \mathbf{k} \\
\frac{\partial X}{\partial u} &amp; \frac{\partial Y}{\partial u} &amp; 0 \\
\frac{\partial X}{\partial v} &amp; \frac{\partial Y}{\partial v} &amp; 0
\end{vmatrix} \]
</div>
</section>
<section>
<h3>The probability of getting \(k\) heads when flipping \(n\) coins is</h3>
<div class="fragment">
\[P(E) = {n \choose k} p^k (1-p)^{ n-k} \]
</div>
</section>
<section>
<h3>An Identity of Ramanujan</h3>
<div class="fragment">
\[ \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } } \]
</div>
</section>
<section>
<h3>A Rogers-Ramanujan Identity</h3>
<div class="fragment">
\[ 1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})}\]
</div>
</section>
<section>
<h3>Maxwell&#8217;s Equations</h3>
<div class="fragment">
\[ \begin{aligned}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} &amp; = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} &amp; = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} &amp; = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} &amp; = 0 \end{aligned}
\]
</div>
</section>
<section>
<h3>TeX Macros</h3>
Here is a common vector space:
\[L^2(\R) = \set{u : \R \to \R}{\int_\R |u|^2 &lt; +\infty}\]
used in functional analysis.
</section>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script src="../plugin/math/math.js"></script>
<script>
Reveal.initialize({
history: true,
transition: 'linear',
mathjax2: {
config: 'TeX-AMS_HTML-full',
TeX: {
Macros: {
R: '\\mathbb{R}',
set: [ '\\left\\{#1 \\; ; \\; #2\\right\\}', 2 ]
}
}
},
// There are three typesetters available
// RevealMath.MathJax2 (default)
// RevealMath.MathJax3
// RevealMath.KaTeX
//
// More info at https://revealjs.com/math/
plugins: [ RevealMath.MathJax2 ]
});
</script>
</body>
</html>
-75
View File
@@ -1,75 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Video, Audio and Iframes</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/white.css" id="theme">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h2>Examples of embedded Video, Audio and Iframes</h2>
</section>
<section>
<h2>Iframe</h2>
<iframe data-autoplay width="700" height="540" src="https://slides.com/news/auto-animate/embed" frameborder="0"></iframe>
</section>
<section data-background-iframe="https://www.youtube.com/embed/h1_nyI3z8gI" data-background-interactive>
<h2 style="color: #fff;">Iframe Background</h2>
</section>
<section>
<h2>Video</h2>
<video src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4" data-autoplay></video>
</section>
<section data-background-video="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">
<h2>Background Video</h2>
</section>
<section>
<h2>Auto-playing audio</h2>
<audio src="assets/beeping.wav" data-autoplay></audio>
</section>
<section>
<h2>Audio inside slide fragments</h2>
<div class="fragment">
Beep 1
<audio src="assets/beeping.wav" data-autoplay></audio>
</div>
<div class="fragment">
Beep 2
<audio src="assets/beeping.wav" data-autoplay></audio>
</div>
</section>
<section>
<h2>Audio with controls</h2>
<audio src="assets/beeping.wav" controls></audio>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script>
Reveal.initialize({hash: true});
</script>
</body>
</html>
@@ -1,102 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Multiple Presentations</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/white.css" id="theme">
<link rel="stylesheet" href="../plugin/highlight/monokai.css">
</head>
<body style="background: #ddd;">
<div style="display: flex; flex-direction: row;">
<div class="reveal deck1" style="width: 100%; height: 50vh; margin: 10px;">
<div class="slides">
<section>Deck 1, Slide 1</section>
<section>Deck 1, Slide 2</section>
<section>
<pre data-id="code-animation"><code class="hljs" data-trim data-line-numbers>
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
}
</code></pre>
</section>
</div>
</div>
<div class="reveal deck2" style="width: 100%; height: 50vh; margin: 10px;">
<div class="slides">
<section>Deck 2, Slide 1</section>
<section>Deck 2, Slide 2</section>
<section data-markdown>
<script type="text/template">
## Markdown plugin
- 1
- 2
- 3
</script>
</section>
<section>
<h3>The Lorenz Equations</h3>
\[\begin{aligned}
\dot{x} &amp; = \sigma(y-x) \\
\dot{y} &amp; = \rho x - y - xz \\
\dot{z} &amp; = -\beta z + xy
\end{aligned} \]
</section>
</div>
</div>
</div>
<style>
.reveal {
border: 4px solid #ccc;
}
.reveal.focused {
border-color: #94b5ff;
}
</style>
<script src="../dist/reveal.js"></script>
<script src="../plugin/highlight/highlight.js"></script>
<script src="../plugin/markdown/markdown.js"></script>
<script src="../plugin/math/math.js"></script>
<script>
let deck1 = new Reveal( document.querySelector( '.deck1' ), {
embedded: true,
progress: false,
keyboardCondition: 'focused',
plugins: [ RevealHighlight ]
} );
deck1.on( 'slidechanged', () => {
console.log( 'Deck 1 slide changed' );
} );
deck1.initialize();
let deck2 = new Reveal( document.querySelector( '.deck2' ), {
embedded: true,
progress: false,
keyboardCondition: 'focused',
plugins: [ RevealMarkdown, RevealMath ]
} );
deck2.initialize().then( () => {
deck2.slide(1);
} );
deck2.on( 'slidechanged', () => {
console.log( 'Deck 2 slide changed' );
} );
</script>
</body>
</html>
-118
View File
@@ -1,118 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Scroll View</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../dist/reset.css">
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/black.css" id="theme">
<link rel="stylesheet" href="../plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section><h1>Scroll View</h1></section>
<section data-background="indigo">
<h2>Scroll triggered fragments</h2>
<ul>
<li class="fragment fade-left">Step one</li>
<li class="fragment fade-left">Step two</li>
<li class="fragment fade-left">Step three</li>
</ul>
</section>
<section data-background-color="#fff"><h2>Scrollbar inverts<br>based on slide bg</h2></section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<h2>Auto-Animate</h2>
<p>Scroll triggered auto-animations 😍</p>
<div class="r-hstack justify-center">
<div data-id="box1" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
<div data-id="box2" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
<div data-id="box3" style="background: #999; width: 50px; height: 50px; margin: 10px; border-radius: 5px;"></div>
</div>
</section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<div class="r-hstack justify-center">
<div data-id="box1" data-auto-animate-delay="0" style="background: cyan; width: 150px; height: 100px; margin: 10px;"></div>
<div data-id="box2" data-auto-animate-delay="0.1" style="background: magenta; width: 150px; height: 100px; margin: 10px;"></div>
<div data-id="box3" data-auto-animate-delay="0.2" style="background: yellow; width: 150px; height: 100px; margin: 10px;"></div>
</div>
<h2 style="margin-top: 20px;">Auto-Animate</h2>
</section>
<section data-auto-animate data-auto-animate-easing="cubic-bezier(0.770, 0.000, 0.175, 1.000)">
<div class="r-stack">
<div data-id="box1" style="background: cyan; width: 300px; height: 300px; border-radius: 200px;"></div>
<div data-id="box2" style="background: magenta; width: 200px; height: 200px; border-radius: 200px;"></div>
<div data-id="box3" style="background: yellow; width: 100px; height: 100px; border-radius: 200px;"></div>
</div>
<h2 style="margin-top: 20px;">Auto-Animate</h2>
</section>
<section data-background-gradient="linear-gradient(to bottom, #283b95, #17b2c3)" id="gradient-bg">
<h2 data-id="code-title">Code highlights,<br />meet scroll triggers</h2>
<pre data-id="code-animation"><code class="hljs javascript" data-trim data-line-numbers="|4,8-11|17|22-24"><script type="text/template">
import React, { useState } from 'react';
function Example() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
function SecondExample() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
</script></code></pre>
</section>
<section class="stack">
<section data-background="https://static.slid.es/reveal/image-placeholder.png" id="image-bg">
<h2>Image Backgrounds</h2>
</section>
<section data-background-video-muted data-background-video="https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.mp4,https://s3.amazonaws.com/static.slid.es/site/homepage/v1/homepage-video-editor.webm">
<h2>Video background</h2>
</section>
</section>
<section><h2>The end</h2></section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script src="../plugin/notes/notes.js"></script>
<script src="../plugin/markdown/markdown.js"></script>
<script src="../plugin/highlight/highlight.js"></script>
<script>
Reveal.initialize({
view: 'scroll',
hash: true,
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
});
</script>
</body>
</html>
@@ -1,97 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Slide Transitions</title>
<link rel="stylesheet" href="../dist/reveal.css">
<link rel="stylesheet" href="../dist/theme/white.css" id="theme">
<style type="text/css" media="screen">
.slides section.has-dark-background,
.slides section.has-dark-background h3 {
color: #fff;
}
.slides section.has-light-background,
.slides section.has-light-background h3 {
color: #222;
}
</style>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h3>Default</h3>
</section>
<section>
<h3>Default</h3>
</section>
<section data-transition="zoom">
<h3>data-transition: zoom</h3>
</section>
<section data-transition="zoom-in fade-out">
<h3>data-transition: zoom-in fade-out</h3>
</section>
<section>
<h3>Default</h3>
</section>
<section data-transition="convex">
<h3>data-transition: convex</h3>
</section>
<section data-transition="convex-in concave-out">
<h3>data-transition: convex-in concave-out</h3>
</section>
<section>
<section data-transition="zoom">
<h3>Default</h3>
</section>
<section data-transition="concave">
<h3>data-transition: concave</h3>
</section>
<section data-transition="convex-in fade-out">
<h3>data-transition: convex-in fade-out</h3>
</section>
<section>
<h3>Default</h3>
</section>
</section>
<section data-transition="none">
<h3>data-transition: none</h3>
</section>
<section>
<h3>Default</h3>
</section>
</div>
</div>
<script src="../dist/reveal.js"></script>
<script>
Reveal.initialize({
center: true,
history: true,
// transition: 'slide',
// transitionSpeed: 'slow',
// backgroundTransition: 'slide'
});
</script>
</body>
</html>
-321
View File
@@ -1,321 +0,0 @@
const pkg = require('./package.json')
const glob = require('glob')
const yargs = require('yargs')
const through = require('through2');
const qunit = require('node-qunit-puppeteer')
const {rollup} = require('rollup')
const terser = require('@rollup/plugin-terser')
const babel = require('@rollup/plugin-babel').default
const commonjs = require('@rollup/plugin-commonjs')
const resolve = require('@rollup/plugin-node-resolve').default
const sass = require('sass')
const gulp = require('gulp')
const tap = require('gulp-tap')
const zip = require('gulp-zip')
const header = require('gulp-header')
const eslint = require('gulp-eslint')
const minify = require('gulp-clean-css')
const connect = require('gulp-connect')
const autoprefixer = require('gulp-autoprefixer')
const root = yargs.argv.root || '.'
const port = yargs.argv.port || 8000
const host = yargs.argv.host || 'localhost'
const banner = `/*!
* reveal.js ${pkg.version}
* ${pkg.homepage}
* MIT licensed
*
* Copyright (C) 2011-2024 Hakim El Hattab, https://hakim.se
*/\n`
// Prevents warnings from opening too many test pages
process.setMaxListeners(20);
const babelConfig = {
babelHelpers: 'bundled',
ignore: ['node_modules'],
compact: false,
extensions: ['.js', '.html'],
plugins: [
'transform-html-import-to-string'
],
presets: [[
'@babel/preset-env',
{
corejs: 3,
useBuiltIns: 'usage',
modules: false
}
]]
};
// Our ES module bundle only targets newer browsers with
// module support. Browsers are targeted explicitly instead
// of using the "esmodule: true" target since that leads to
// polyfilling older browsers and a larger bundle.
const babelConfigESM = JSON.parse( JSON.stringify( babelConfig ) );
babelConfigESM.presets[0][1].targets = { browsers: [
'last 2 Chrome versions',
'last 2 Safari versions',
'last 2 iOS versions',
'last 2 Firefox versions',
'last 2 Edge versions',
] };
let cache = {};
// Creates a bundle with broad browser support, exposed
// as UMD
gulp.task('js-es5', () => {
return rollup({
cache: cache.umd,
input: 'js/index.js',
plugins: [
resolve(),
commonjs(),
babel( babelConfig ),
terser()
]
}).then( bundle => {
cache.umd = bundle.cache;
return bundle.write({
name: 'Reveal',
file: './dist/reveal.js',
format: 'umd',
banner: banner,
sourcemap: true
});
});
})
// Creates an ES module bundle
gulp.task('js-es6', () => {
return rollup({
cache: cache.esm,
input: 'js/index.js',
plugins: [
resolve(),
commonjs(),
babel( babelConfigESM ),
terser()
]
}).then( bundle => {
cache.esm = bundle.cache;
return bundle.write({
file: './dist/reveal.esm.js',
format: 'es',
banner: banner,
sourcemap: true
});
});
})
gulp.task('js', gulp.parallel('js-es5', 'js-es6'));
// Creates a UMD and ES module bundle for each of our
// built-in plugins
gulp.task('plugins', () => {
return Promise.all([
{ name: 'RevealHighlight', input: './plugin/highlight/plugin.js', output: './plugin/highlight/highlight' },
{ name: 'RevealMarkdown', input: './plugin/markdown/plugin.js', output: './plugin/markdown/markdown' },
{ name: 'RevealSearch', input: './plugin/search/plugin.js', output: './plugin/search/search' },
{ name: 'RevealNotes', input: './plugin/notes/plugin.js', output: './plugin/notes/notes' },
{ name: 'RevealZoom', input: './plugin/zoom/plugin.js', output: './plugin/zoom/zoom' },
{ name: 'RevealMath', input: './plugin/math/plugin.js', output: './plugin/math/math' },
].map( plugin => {
return rollup({
cache: cache[plugin.input],
input: plugin.input,
plugins: [
resolve(),
commonjs(),
babel({
...babelConfig,
ignore: [/node_modules\/(?!(highlight\.js|marked)\/).*/],
}),
terser()
]
}).then( bundle => {
cache[plugin.input] = bundle.cache;
bundle.write({
file: plugin.output + '.esm.js',
name: plugin.name,
format: 'es'
})
bundle.write({
file: plugin.output + '.js',
name: plugin.name,
format: 'umd'
})
});
} ));
})
// a custom pipeable step to transform Sass to CSS
function compileSass() {
return through.obj( ( vinylFile, encoding, callback ) => {
const transformedFile = vinylFile.clone();
sass.render({
data: transformedFile.contents.toString(),
file: transformedFile.path,
}, ( err, result ) => {
if( err ) {
callback(err);
}
else {
transformedFile.extname = '.css';
transformedFile.contents = result.css;
callback( null, transformedFile );
}
});
});
}
gulp.task('css-themes', () => gulp.src(['./css/theme/source/*.{sass,scss}'])
.pipe(compileSass())
.pipe(gulp.dest('./dist/theme')))
gulp.task('css-core', () => gulp.src(['css/reveal.scss'])
.pipe(compileSass())
.pipe(autoprefixer())
.pipe(minify({compatibility: 'ie9'}))
.pipe(header(banner))
.pipe(gulp.dest('./dist')))
gulp.task('css', gulp.parallel('css-themes', 'css-core'))
gulp.task('qunit', () => {
let serverConfig = {
root,
port: 8009,
host: 'localhost',
name: 'test-server'
}
let server = connect.server( serverConfig )
let testFiles = glob.sync('test/*.html' )
let totalTests = 0;
let failingTests = 0;
let tests = Promise.all( testFiles.map( filename => {
return new Promise( ( resolve, reject ) => {
qunit.runQunitPuppeteer({
targetUrl: `http://${serverConfig.host}:${serverConfig.port}/${filename}`,
timeout: 20000,
redirectConsole: false,
puppeteerArgs: ['--allow-file-access-from-files']
})
.then(result => {
if( result.stats.failed > 0 ) {
console.log(`${'!'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.red);
// qunit.printResultSummary(result, console);
qunit.printFailedTests(result, console);
}
else {
console.log(`${'✔'} ${filename} [${result.stats.passed}/${result.stats.total}] in ${result.stats.runtime}ms`.green);
}
totalTests += result.stats.total;
failingTests += result.stats.failed;
resolve();
})
.catch(error => {
console.error(error);
reject();
});
} )
} ) );
return new Promise( ( resolve, reject ) => {
tests.then( () => {
if( failingTests > 0 ) {
reject( new Error(`${failingTests}/${totalTests} tests failed`.red) );
}
else {
console.log(`${'✔'} Passed ${totalTests} tests`.green.bold);
resolve();
}
} )
.catch( () => {
reject();
} )
.finally( () => {
server.close();
} );
} );
} )
gulp.task('eslint', () => gulp.src(['./js/**', 'gulpfile.js'])
.pipe(eslint())
.pipe(eslint.format()))
gulp.task('test', gulp.series( 'eslint', 'qunit' ))
gulp.task('default', gulp.series(gulp.parallel('js', 'css', 'plugins'), 'test'))
gulp.task('build', gulp.parallel('js', 'css', 'plugins'))
gulp.task('package', gulp.series(() =>
gulp.src(
[
'./index.html',
'./dist/**',
'./lib/**',
'./images/**',
'./plugin/**',
'./**/*.md'
],
{ base: './' }
)
.pipe(zip('reveal-js-presentation.zip')).pipe(gulp.dest('./'))
))
gulp.task('reload', () => gulp.src(['index.html'])
.pipe(connect.reload()));
gulp.task('serve', () => {
connect.server({
root: root,
port: port,
host: host,
livereload: true
})
const slidesRoot = root.endsWith('/') ? root : root + '/'
gulp.watch([
slidesRoot + '**/*.html',
slidesRoot + '**/*.md',
`!${slidesRoot}**/node_modules/**`, // ignore node_modules
], gulp.series('reload'))
gulp.watch(['js/**'], gulp.series('js', 'reload', 'eslint'))
gulp.watch(['plugin/**/plugin.js', 'plugin/**/*.html'], gulp.series('plugins', 'reload'))
gulp.watch([
'css/theme/source/**/*.{sass,scss}',
'css/theme/template/*.{sass,scss}',
], gulp.series('css-themes', 'reload'))
gulp.watch([
'css/*.scss',
'css/print/*.{sass,scss,css}'
], gulp.series('css-core', 'reload'))
gulp.watch(['test/*.html'], gulp.series('test'))
})
-40
View File
@@ -1,40 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>reveal.js</title>
<link rel="stylesheet" href="dist/reset.css">
<link rel="stylesheet" href="dist/reveal.css">
<link rel="stylesheet" href="dist/theme/black.css">
<!-- Theme used for syntax highlighted code -->
<link rel="stylesheet" href="plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>Slide 1</section>
<section>Slide 2</section>
</div>
</div>
<script src="dist/reveal.js"></script>
<script src="plugin/notes/notes.js"></script>
<script src="plugin/markdown/markdown.js"></script>
<script src="plugin/highlight/highlight.js"></script>
<script>
// More info about initialization & config:
// - https://revealjs.com/initialization/
// - https://revealjs.com/config/
Reveal.initialize({
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ]
});
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More