Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
818563c408 | ||
|
|
50c546e42d | ||
|
|
651a5c7902 | ||
|
|
28db30bd78 |
@@ -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:
|
||||
|
||||
@@ -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,24 +58,39 @@ 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);
|
||||
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);
|
||||
return await withOperatorRunner(config, async (runner) => {
|
||||
for (const revision of revisions) {
|
||||
const result = await runner.run(["doctor", "--json"], revision.snapshotPath);
|
||||
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);
|
||||
@@ -83,8 +101,12 @@ async function workflowDiagnostics(config: AppConfig): Promise<{ ready: true; wo
|
||||
result.code !== 0 || !payload || typeof payload !== "object"
|
||||
|| (payload as { ok?: unknown }).ok !== true
|
||||
) throw new Error("workflow diagnostics failed");
|
||||
} finally {
|
||||
runtime.release();
|
||||
}
|
||||
}
|
||||
return { ready: true, workspaces: revisions.length };
|
||||
});
|
||||
}
|
||||
|
||||
async function workspaceIntegrity(config: AppConfig): Promise<{
|
||||
|
||||
@@ -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 await d.workspaceRegistry.list();
|
||||
return { revisions: await d.workspaceRegistry.list(), retainedComplete: false };
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -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/ /
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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). */
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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 } : {}),
|
||||
};
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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 |
@@ -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); }
|
||||
@@ -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'); }
|
||||
|
Before Width: | Height: | Size: 76 KiB |
@@ -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);
|
||||
})();
|
||||
@@ -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; } }
|
||||
@@ -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,
|
||||
};
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 630 KiB |
|
Before Width: | Height: | Size: 680 KiB |
|
Before Width: | Height: | Size: 551 KiB |
|
Before Width: | Height: | Size: 721 KiB |
|
Before Width: | Height: | Size: 723 KiB |
|
Before Width: | Height: | Size: 834 KiB |
|
Before Width: | Height: | Size: 596 KiB |
|
Before Width: | Height: | Size: 470 KiB |
|
Before Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 976 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 959 KiB |
|
Before Width: | Height: | Size: 948 KiB |
|
Before Width: | Height: | Size: 704 KiB |
|
Before Width: | Height: | Size: 802 KiB |
|
Before Width: | Height: | Size: 820 KiB |
|
Before Width: | Height: | Size: 925 KiB |
|
Before Width: | Height: | Size: 707 KiB |
|
Before Width: | Height: | Size: 472 KiB |
@@ -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; }
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
})();
|
||||
@@ -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 +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
|
||||
@@ -1,5 +0,0 @@
|
||||
/test
|
||||
/examples
|
||||
.github
|
||||
.sass-cache
|
||||
gulpfile.js
|
||||
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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; }
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"><section data-background-gradient=
|
||||
"linear-gradient(to bottom, #ddd, #191919)"></code></pre>
|
||||
</section>
|
||||
<section data-background="https://static.slid.es/reveal/image-placeholder.png">
|
||||
<h2>Image Backgrounds</h2>
|
||||
<pre><code class="hljs html"><section data-background="image.png"></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;"><section data-background="image.png" data-background-repeat="repeat" data-background-size="100px"></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;"><section data-background-video="video.mp4,video.webm"></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;"><section data-background-transition="zoom"></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">
|
||||
“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.”
|
||||
</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 & 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>
|
||||
@@ -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)
|
||||
|
Before Width: | Height: | Size: 22 KiB |
|
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 (
|
||||
<div>
|
||||
<p>You clicked {count} times</p>
|
||||
<button onClick={() => setCount(count + 1)}>
|
||||
Click me
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</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 (
|
||||
<div>
|
||||
<p>You clicked {count} times</p>
|
||||
<button onClick={() => setCount(count + 1)}>
|
||||
Click me
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</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>
|
||||
@@ -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">
|
||||
<img class="fragment" width="450" height="300" src="...">
|
||||
<img class="fragment" width="300" height="450" src="...">
|
||||
<img class="fragment" width="400" height="400" src="...">
|
||||
</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">
|
||||
<img width="450" height="300" src="...">
|
||||
<img width="300" height="450" src="...">
|
||||
<img width="400" height="400" src="...">
|
||||
</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">
|
||||
<img width="450" height="300" src="...">
|
||||
<img width="300" height="450" src="...">
|
||||
<img width="400" height="400" src="...">
|
||||
</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>
|
||||
@@ -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">
|
||||

|
||||
</script>
|
||||
</section>
|
||||
|
||||
<!-- Math -->
|
||||
<section data-markdown>
|
||||
## The Lorenz Equations
|
||||
`\[\begin{aligned}
|
||||
\dot{x} & = \sigma(y-x) \\
|
||||
\dot{y} & = \rho x - y - xz \\
|
||||
\dot{z} & = -\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>
|
||||
@@ -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 3.4 (Math)
|
||||
|
||||
`\[ J(\theta_0,\theta_1) = \sum_{i=0} \]`
|
||||
@@ -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} & = \sigma(y-x) \\
|
||||
\dot{y} & = \rho x - y - xz \\
|
||||
\dot{z} & = -\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} & \mathbf{j} & \mathbf{k} \\
|
||||
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
|
||||
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 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’s Equations</h3>
|
||||
|
||||
\[ \begin{aligned}
|
||||
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
|
||||
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
|
||||
\nabla \cdot \vec{\mathbf{B}} & = 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 < +\infty}\]
|
||||
used in functional analysis.
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h3>The Lorenz Equations</h3>
|
||||
|
||||
<div class="fragment">
|
||||
\[\begin{aligned}
|
||||
\dot{x} & = \sigma(y-x) \\
|
||||
\dot{y} & = \rho x - y - xz \\
|
||||
\dot{z} & = -\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} & \mathbf{j} & \mathbf{k} \\
|
||||
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
|
||||
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 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’s Equations</h3>
|
||||
|
||||
<div class="fragment">
|
||||
\[ \begin{aligned}
|
||||
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
|
||||
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
|
||||
\nabla \cdot \vec{\mathbf{B}} & = 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 < +\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>
|
||||
@@ -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} & = \sigma(y-x) \\
|
||||
\dot{y} & = \rho x - y - xz \\
|
||||
\dot{z} & = -\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>
|
||||
@@ -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>
|
||||
@@ -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'))
|
||||
|
||||
})
|
||||
@@ -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>
|
||||