enya-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +20 -0
- package/.github/workflows/ci.yml +70 -0
- package/.github/workflows/publish.yml +250 -0
- package/.gitmodules +3 -0
- package/Cargo.lock +3584 -0
- package/Cargo.toml +97 -0
- package/crates/enact/Cargo.toml +27 -0
- package/crates/enact/src/lib.rs +60 -0
- package/crates/enact-a2a/Cargo.toml +25 -0
- package/crates/enact-a2a/src/lib.rs +411 -0
- package/crates/enact-channels/Cargo.toml +64 -0
- package/crates/enact-channels/examples/README.md +80 -0
- package/crates/enact-channels/examples/channel_bot.rs +169 -0
- package/crates/enact-channels/examples/telegram-echo.rs +34 -0
- package/crates/enact-channels/examples/whatsapp-echo.rs +142 -0
- package/crates/enact-channels/src/config.rs +213 -0
- package/crates/enact-channels/src/lib.rs +25 -0
- package/crates/enact-channels/src/runtime.rs +237 -0
- package/crates/enact-channels/src/security/mod.rs +5 -0
- package/crates/enact-channels/src/security/pairing.rs +205 -0
- package/crates/enact-channels/src/teams.rs +601 -0
- package/crates/enact-channels/src/telegram.rs +2833 -0
- package/crates/enact-channels/src/traits.rs +200 -0
- package/crates/enact-channels/src/webhook.rs +262 -0
- package/crates/enact-channels/src/whatsapp.rs +310 -0
- package/crates/enact-cli/Cargo.toml +40 -0
- package/crates/enact-cli/src/commands/doctor.rs +62 -0
- package/crates/enact-cli/src/commands/mod.rs +3 -0
- package/crates/enact-cli/src/commands/run.rs +69 -0
- package/crates/enact-cli/src/commands/serve.rs +81 -0
- package/crates/enact-cli/src/config.rs +2 -0
- package/crates/enact-cli/src/main.rs +79 -0
- package/crates/enact-config/Cargo.toml +36 -0
- package/crates/enact-config/ENV_VAR_MAPPING.md +135 -0
- package/crates/enact-config/QUICK_REFERENCE.md +92 -0
- package/crates/enact-config/README.md +107 -0
- package/crates/enact-config/TESTING.md +161 -0
- package/crates/enact-config/examples/test-env-vars.rs +100 -0
- package/crates/enact-config/src/config.rs +399 -0
- package/crates/enact-config/src/encrypted_store.rs +211 -0
- package/crates/enact-config/src/lib.rs +298 -0
- package/crates/enact-config/src/secrets.rs +149 -0
- package/crates/enact-config/src/sync.rs +260 -0
- package/crates/enact-config/test-env-vars.sh +34 -0
- package/crates/enact-config/tests/README.md +99 -0
- package/crates/enact-config/tests/config_integration_test.rs +202 -0
- package/crates/enact-config/tests/security_test.rs +140 -0
- package/crates/enact-context/Cargo.toml +41 -0
- package/crates/enact-context/src/budget.rs +314 -0
- package/crates/enact-context/src/calibrator.rs +535 -0
- package/crates/enact-context/src/compactor.rs +392 -0
- package/crates/enact-context/src/condenser.rs +826 -0
- package/crates/enact-context/src/lib.rs +94 -0
- package/crates/enact-context/src/segment.rs +238 -0
- package/crates/enact-context/src/step_context.rs +645 -0
- package/crates/enact-context/src/token_counter.rs +148 -0
- package/crates/enact-context/src/window.rs +372 -0
- package/crates/enact-core/Cargo.toml +42 -0
- package/crates/enact-core/README.md +98 -0
- package/crates/enact-core/src/background/executor.rs +524 -0
- package/crates/enact-core/src/background/mod.rs +48 -0
- package/crates/enact-core/src/background/target_binding.rs +390 -0
- package/crates/enact-core/src/background/trigger.rs +511 -0
- package/crates/enact-core/src/callable/callable.rs +152 -0
- package/crates/enact-core/src/callable/composite.rs +817 -0
- package/crates/enact-core/src/callable/graph.rs +104 -0
- package/crates/enact-core/src/callable/llm.rs +211 -0
- package/crates/enact-core/src/callable/mod.rs +64 -0
- package/crates/enact-core/src/callable/registry.rs +206 -0
- package/crates/enact-core/src/context/execution_context.rs +757 -0
- package/crates/enact-core/src/context/invocation.rs +99 -0
- package/crates/enact-core/src/context/mod.rs +50 -0
- package/crates/enact-core/src/context/tenant.rs +175 -0
- package/crates/enact-core/src/context/trace.rs +127 -0
- package/crates/enact-core/src/flow/conditional.rs +293 -0
- package/crates/enact-core/src/flow/mod.rs +43 -0
- package/crates/enact-core/src/flow/parallel.rs +437 -0
- package/crates/enact-core/src/flow/repeat.rs +534 -0
- package/crates/enact-core/src/flow/sequential.rs +248 -0
- package/crates/enact-core/src/graph/checkpoint.rs +79 -0
- package/crates/enact-core/src/graph/checkpoint_store.rs +76 -0
- package/crates/enact-core/src/graph/compiled.rs +189 -0
- package/crates/enact-core/src/graph/edge.rs +59 -0
- package/crates/enact-core/src/graph/graph_schema.rs +218 -0
- package/crates/enact-core/src/graph/loader.rs +155 -0
- package/crates/enact-core/src/graph/mod.rs +18 -0
- package/crates/enact-core/src/graph/node/function.rs +49 -0
- package/crates/enact-core/src/graph/node/mod.rs +48 -0
- package/crates/enact-core/src/graph/schema.rs +62 -0
- package/crates/enact-core/src/inbox/message.rs +405 -0
- package/crates/enact-core/src/inbox/mod.rs +31 -0
- package/crates/enact-core/src/inbox/store.rs +355 -0
- package/crates/enact-core/src/kernel/artifact/filesystem.rs +546 -0
- package/crates/enact-core/src/kernel/artifact/metadata.rs +283 -0
- package/crates/enact-core/src/kernel/artifact/mod.rs +27 -0
- package/crates/enact-core/src/kernel/artifact/store.rs +427 -0
- package/crates/enact-core/src/kernel/enforcement.rs +1315 -0
- package/crates/enact-core/src/kernel/error.rs +1200 -0
- package/crates/enact-core/src/kernel/event.rs +1394 -0
- package/crates/enact-core/src/kernel/execution_model.rs +831 -0
- package/crates/enact-core/src/kernel/execution_state.rs +189 -0
- package/crates/enact-core/src/kernel/execution_strategy.rs +117 -0
- package/crates/enact-core/src/kernel/ids.rs +2086 -0
- package/crates/enact-core/src/kernel/interrupt.rs +125 -0
- package/crates/enact-core/src/kernel/kernel.rs +1283 -0
- package/crates/enact-core/src/kernel/mod.rs +205 -0
- package/crates/enact-core/src/kernel/persistence/event_store.rs +270 -0
- package/crates/enact-core/src/kernel/persistence/message_store.rs +908 -0
- package/crates/enact-core/src/kernel/persistence/mod.rs +102 -0
- package/crates/enact-core/src/kernel/persistence/state_store.rs +228 -0
- package/crates/enact-core/src/kernel/persistence/vector_store.rs +299 -0
- package/crates/enact-core/src/kernel/reducer.rs +808 -0
- package/crates/enact-core/src/kernel/replay.rs +153 -0
- package/crates/enact-core/src/lib.rs +413 -0
- package/crates/enact-core/src/memory/episodic.rs +0 -0
- package/crates/enact-core/src/memory/mod.rs +6 -0
- package/crates/enact-core/src/memory/semantic.rs +0 -0
- package/crates/enact-core/src/memory/trait.rs +0 -0
- package/crates/enact-core/src/memory/vector_db.rs +0 -0
- package/crates/enact-core/src/memory/working.rs +0 -0
- package/crates/enact-core/src/policy/execution_policy.rs +292 -0
- package/crates/enact-core/src/policy/filters.rs +458 -0
- package/crates/enact-core/src/policy/input_processor.rs +407 -0
- package/crates/enact-core/src/policy/long_running.rs +134 -0
- package/crates/enact-core/src/policy/mod.rs +193 -0
- package/crates/enact-core/src/policy/pii_input.rs +274 -0
- package/crates/enact-core/src/policy/tenant_policy.rs +453 -0
- package/crates/enact-core/src/policy/tool_policy.rs +407 -0
- package/crates/enact-core/src/providers/mod.rs +63 -0
- package/crates/enact-core/src/providers/trait.rs +292 -0
- package/crates/enact-core/src/runner/callbacks.rs +6 -0
- package/crates/enact-core/src/runner/execution_runner.rs +476 -0
- package/crates/enact-core/src/runner/loop.rs +117 -0
- package/crates/enact-core/src/runner/mod.rs +58 -0
- package/crates/enact-core/src/runner/protected_runner.rs +280 -0
- package/crates/enact-core/src/signal/inmemory.rs +231 -0
- package/crates/enact-core/src/signal/mod.rs +108 -0
- package/crates/enact-core/src/streaming/event_logger.rs +195 -0
- package/crates/enact-core/src/streaming/event_stream.rs +1423 -0
- package/crates/enact-core/src/streaming/mod.rs +108 -0
- package/crates/enact-core/src/streaming/pause_cancel.rs +0 -0
- package/crates/enact-core/src/streaming/protected_emitter.rs +173 -0
- package/crates/enact-core/src/streaming/protection/context.rs +136 -0
- package/crates/enact-core/src/streaming/protection/encryption.rs +289 -0
- package/crates/enact-core/src/streaming/protection/mod.rs +43 -0
- package/crates/enact-core/src/streaming/protection/pii_protection.rs +243 -0
- package/crates/enact-core/src/streaming/protection/processor.rs +166 -0
- package/crates/enact-core/src/streaming/sse.rs +0 -0
- package/crates/enact-core/src/telemetry/exporter.rs +0 -0
- package/crates/enact-core/src/telemetry/init.rs +0 -0
- package/crates/enact-core/src/telemetry/mod.rs +49 -0
- package/crates/enact-core/src/telemetry/spans.rs +245 -0
- package/crates/enact-core/src/tool/agent_tool.rs +177 -0
- package/crates/enact-core/src/tool/browser/mod.rs +0 -0
- package/crates/enact-core/src/tool/browser/webdriver.rs +0 -0
- package/crates/enact-core/src/tool/cost.rs +247 -0
- package/crates/enact-core/src/tool/discovery.rs +0 -0
- package/crates/enact-core/src/tool/dispatcher.rs +347 -0
- package/crates/enact-core/src/tool/filesystem.rs +231 -0
- package/crates/enact-core/src/tool/function.rs +99 -0
- package/crates/enact-core/src/tool/git.rs +162 -0
- package/crates/enact-core/src/tool/http.rs +214 -0
- package/crates/enact-core/src/tool/mcp/client.rs +0 -0
- package/crates/enact-core/src/tool/mcp/mod.rs +0 -0
- package/crates/enact-core/src/tool/mod.rs +51 -0
- package/crates/enact-core/src/tool/reasoning/debugging.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mcts.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/mod.rs +0 -0
- package/crates/enact-core/src/tool/reasoning/sequential.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/dagger.rs +0 -0
- package/crates/enact-core/src/tool/sandbox/mod.rs +0 -0
- package/crates/enact-core/src/tool/shell.rs +147 -0
- package/crates/enact-core/src/tool/trait.rs +33 -0
- package/crates/enact-core/src/tool/web_search.rs +277 -0
- package/crates/enact-core/src/util/config.rs +0 -0
- package/crates/enact-core/src/util/errors.rs +0 -0
- package/crates/enact-core/src/util/mod.rs +6 -0
- package/crates/enact-core/tests/airgapped_e2e_test.rs +291 -0
- package/crates/enact-core/tests/e2e_agentic_loop.rs +119 -0
- package/crates/enact-core/tests/e2e_test.rs +259 -0
- package/crates/enact-core/tests/graph_test.rs +130 -0
- package/crates/enact-core/tests/stream_event_id_validation.rs +435 -0
- package/crates/enact-cron/Cargo.toml +28 -0
- package/crates/enact-cron/src/lib.rs +44 -0
- package/crates/enact-cron/src/schedule.rs +156 -0
- package/crates/enact-cron/src/store.rs +589 -0
- package/crates/enact-cron/src/types.rs +148 -0
- package/crates/enact-gateway/Cargo.toml +31 -0
- package/crates/enact-gateway/README.md +30 -0
- package/crates/enact-gateway/examples/whatsapp-gateway-runner-mock.rs +59 -0
- package/crates/enact-gateway/examples/whatsapp-gateway.rs +42 -0
- package/crates/enact-gateway/src/lib.rs +582 -0
- package/crates/enact-mcp/Cargo.toml +24 -0
- package/crates/enact-mcp/src/lib.rs +178 -0
- package/crates/enact-memory/Cargo.toml +25 -0
- package/crates/enact-memory/src/backend.rs +20 -0
- package/crates/enact-memory/src/chunker.rs +230 -0
- package/crates/enact-memory/src/embeddings.rs +221 -0
- package/crates/enact-memory/src/lib.rs +67 -0
- package/crates/enact-memory/src/markdown.rs +127 -0
- package/crates/enact-memory/src/none.rs +61 -0
- package/crates/enact-memory/src/sqlite.rs +276 -0
- package/crates/enact-memory/src/traits.rs +65 -0
- package/crates/enact-memory/src/vector.rs +198 -0
- package/crates/enact-oauth/Cargo.toml +27 -0
- package/crates/enact-oauth/src/lib.rs +584 -0
- package/crates/enact-observability/Cargo.toml +22 -0
- package/crates/enact-observability/src/lib.rs +197 -0
- package/crates/enact-providers/Cargo.toml +33 -0
- package/crates/enact-providers/examples/hello-agent.rs +33 -0
- package/crates/enact-providers/src/anthropic.rs +182 -0
- package/crates/enact-providers/src/azure.rs +96 -0
- package/crates/enact-providers/src/bridge.rs +221 -0
- package/crates/enact-providers/src/gemini.rs +227 -0
- package/crates/enact-providers/src/http.rs +78 -0
- package/crates/enact-providers/src/lib.rs +53 -0
- package/crates/enact-providers/src/openai_compatible.rs +167 -0
- package/crates/enact-providers/src/openrouter.rs +33 -0
- package/crates/enact-runner/Cargo.toml +24 -0
- package/crates/enact-runner/README.md +76 -0
- package/crates/enact-runner/src/compaction.rs +225 -0
- package/crates/enact-runner/src/config.rs +118 -0
- package/crates/enact-runner/src/lib.rs +63 -0
- package/crates/enact-runner/src/loop_driver.rs +414 -0
- package/crates/enact-runner/src/parser.rs +421 -0
- package/crates/enact-runner/src/retry.rs +262 -0
- package/crates/enact-runner/tests/integration.rs +278 -0
- package/crates/enact-security/Cargo.toml +22 -0
- package/crates/enact-security/src/audit.rs +375 -0
- package/crates/enact-security/src/lib.rs +37 -0
- package/crates/enact-security/src/policy.rs +406 -0
- package/crates/enact-skills/Cargo.toml +25 -0
- package/crates/enact-skills/src/lib.rs +506 -0
- package/crates/enact-tools/Cargo.toml +22 -0
- package/crates/enact-tools/src/file_read.rs +166 -0
- package/crates/enact-tools/src/file_write.rs +216 -0
- package/crates/enact-tools/src/git_operations.rs +513 -0
- package/crates/enact-tools/src/http_request.rs +417 -0
- package/crates/enact-tools/src/lib.rs +104 -0
- package/crates/enact-tools/src/security.rs +227 -0
- package/crates/enact-tools/src/shell.rs +191 -0
- package/crates/enact-tools/src/traits.rs +159 -0
- package/docs/Makefile +74 -0
- package/docs/config.toml +62 -0
- package/docs/content/_index.md +174 -0
- package/docs/content/a2a/_index.md +431 -0
- package/docs/content/api/_index.md +323 -0
- package/docs/content/channels/_index.md +160 -0
- package/docs/content/channels/teams.md +205 -0
- package/docs/content/channels/telegram.md +182 -0
- package/docs/content/channels/webhook.md +423 -0
- package/docs/content/channels/whatsapp.md +240 -0
- package/docs/content/cli/_index.md +261 -0
- package/docs/content/concepts/_index.md +273 -0
- package/docs/content/configuration/_index.md +241 -0
- package/docs/content/cron/_index.md +248 -0
- package/docs/content/developers/_index.md +278 -0
- package/docs/content/getting-started/_index.md +180 -0
- package/docs/content/installation/_index.md +186 -0
- package/docs/content/installation/uninstall.md +101 -0
- package/docs/content/installation/updating.md +120 -0
- package/docs/content/mcp/_index.md +215 -0
- package/docs/content/memory/_index.md +163 -0
- package/docs/content/oauth/_index.md +515 -0
- package/docs/content/providers/_index.md +206 -0
- package/docs/content/roadmap/_index.md +199 -0
- package/docs/content/security/_index.md +219 -0
- package/docs/content/skills/_index.md +228 -0
- package/docs/content/tools/_index.md +485 -0
- package/docs/content/troubleshooting/_index.md +259 -0
- package/docs/content/yaml-schema/_index.md +294 -0
- package/docs/static/giallo-dark.css +91 -0
- package/docs/static/giallo-light.css +91 -0
- package/docs/themes/tanuki/.github/workflows/deploy.yml +44 -0
- package/docs/themes/tanuki/LICENSE +21 -0
- package/docs/themes/tanuki/README.md +166 -0
- package/docs/themes/tanuki/examples/blog/config.toml +58 -0
- package/docs/themes/tanuki/examples/blog/content/_index.md +4 -0
- package/docs/themes/tanuki/examples/blog/content/about.md +33 -0
- package/docs/themes/tanuki/examples/blog/content/blog/_index.md +7 -0
- package/docs/themes/tanuki/examples/blog/content/blog/api-design-best-practices.md +245 -0
- package/docs/themes/tanuki/examples/blog/content/blog/building-accessible-websites.md +147 -0
- package/docs/themes/tanuki/examples/blog/content/blog/css-grid-vs-flexbox.md +165 -0
- package/docs/themes/tanuki/examples/blog/content/blog/customizing-catppuccin-colors.md +137 -0
- package/docs/themes/tanuki/examples/blog/content/blog/dark-mode-best-practices.md +82 -0
- package/docs/themes/tanuki/examples/blog/content/blog/docker-essentials.md +301 -0
- package/docs/themes/tanuki/examples/blog/content/blog/getting-started-with-zola.md +129 -0
- package/docs/themes/tanuki/examples/blog/content/blog/git-workflow-for-content.md +112 -0
- package/docs/themes/tanuki/examples/blog/content/blog/introduction-to-webassembly.md +183 -0
- package/docs/themes/tanuki/examples/blog/content/blog/modern-javascript-features.md +234 -0
- package/docs/themes/tanuki/examples/blog/content/blog/testing-strategies.md +311 -0
- package/docs/themes/tanuki/examples/blog/content/blog/typography-for-developers.md +104 -0
- package/docs/themes/tanuki/examples/blog/content/blog/welcome-to-tanuki.md +67 -0
- package/docs/themes/tanuki/examples/blog/content/blog/why-static-sites.md +85 -0
- package/docs/themes/tanuki/examples/blog/content/projects.md +64 -0
- package/docs/themes/tanuki/examples/book/config.toml +17 -0
- package/docs/themes/tanuki/examples/book/content/_index.md +12 -0
- package/docs/themes/tanuki/examples/book/content/chapter-1.md +90 -0
- package/docs/themes/tanuki/examples/book/content/chapter-2.md +143 -0
- package/docs/themes/tanuki/examples/book/content/chapter-3.md +217 -0
- package/docs/themes/tanuki/examples/book/content/chapter-4.md +224 -0
- package/docs/themes/tanuki/examples/book/content/chapter-5.md +297 -0
- package/docs/themes/tanuki/examples/book/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/config.toml +28 -0
- package/docs/themes/tanuki/examples/docs/content/_index.md +20 -0
- package/docs/themes/tanuki/examples/docs/content/components.md +156 -0
- package/docs/themes/tanuki/examples/docs/content/configuration.md +94 -0
- package/docs/themes/tanuki/examples/docs/content/customization.md +202 -0
- package/docs/themes/tanuki/examples/docs/content/deployment.md +204 -0
- package/docs/themes/tanuki/examples/docs/content/installation.md +59 -0
- package/docs/themes/tanuki/examples/docs/content/print.md +6 -0
- package/docs/themes/tanuki/examples/docs/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/examples/index.html +2104 -0
- package/docs/themes/tanuki/mise.toml +108 -0
- package/docs/themes/tanuki/sass/base/_catppuccin.scss +164 -0
- package/docs/themes/tanuki/sass/base/_fonts.scss +64 -0
- package/docs/themes/tanuki/sass/base/_reset.scss +152 -0
- package/docs/themes/tanuki/sass/base/_typography.scss +523 -0
- package/docs/themes/tanuki/sass/components/_buttons.scss +209 -0
- package/docs/themes/tanuki/sass/components/_code.scss +457 -0
- package/docs/themes/tanuki/sass/components/_landing.scss +633 -0
- package/docs/themes/tanuki/sass/components/_layout.scss +294 -0
- package/docs/themes/tanuki/sass/components/_navigation.scss +1200 -0
- package/docs/themes/tanuki/sass/components/_print.scss +237 -0
- package/docs/themes/tanuki/sass/components/_search.scss +224 -0
- package/docs/themes/tanuki/sass/components/_sidebar.scss +473 -0
- package/docs/themes/tanuki/sass/components/_theme-toggle.scss +186 -0
- package/docs/themes/tanuki/sass/modes/_blog.scss +366 -0
- package/docs/themes/tanuki/sass/modes/_product.scss +875 -0
- package/docs/themes/tanuki/sass/modes/_raskell.scss +1696 -0
- package/docs/themes/tanuki/sass/patterns/_buttons.scss +183 -0
- package/docs/themes/tanuki/sass/patterns/_cards.scss +144 -0
- package/docs/themes/tanuki/sass/patterns/_index.scss +9 -0
- package/docs/themes/tanuki/sass/patterns/_lists.scss +259 -0
- package/docs/themes/tanuki/sass/patterns/_sections.scss +243 -0
- package/docs/themes/tanuki/sass/style.scss +47 -0
- package/docs/themes/tanuki/sass/tokens/_colors.scss +139 -0
- package/docs/themes/tanuki/sass/tokens/_spacing.scss +100 -0
- package/docs/themes/tanuki/sass/tokens/_typography.scss +186 -0
- package/docs/themes/tanuki/screenshot.png +0 -0
- package/docs/themes/tanuki/sentinel.kdl +59 -0
- package/docs/themes/tanuki/static/elasticlunr.min.js +10 -0
- package/docs/themes/tanuki/static/fonts/GEIST-LICENSE.txt +92 -0
- package/docs/themes/tanuki/static/fonts/Geist-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/fonts/GeistMono-Variable.woff2 +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.avif +0 -0
- package/docs/themes/tanuki/static/img/tanuki-icon.png +0 -0
- package/docs/themes/tanuki/static/js/anchors.js +18 -0
- package/docs/themes/tanuki/static/js/app.js +274 -0
- package/docs/themes/tanuki/static/js/code.js +394 -0
- package/docs/themes/tanuki/static/js/navigation.js +778 -0
- package/docs/themes/tanuki/static/js/scroll-to-top.js +33 -0
- package/docs/themes/tanuki/static/js/search-raskell.js +240 -0
- package/docs/themes/tanuki/static/js/search.js +215 -0
- package/docs/themes/tanuki/static/js/theme.js +169 -0
- package/docs/themes/tanuki/static/syntax-dark.css +151 -0
- package/docs/themes/tanuki/static/syntax-light.css +151 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm.js +486 -0
- package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm_bg.wasm +0 -0
- package/docs/themes/tanuki/templates/404.html +52 -0
- package/docs/themes/tanuki/templates/base.html +428 -0
- package/docs/themes/tanuki/templates/blog.html +66 -0
- package/docs/themes/tanuki/templates/home.html +108 -0
- package/docs/themes/tanuki/templates/index.html +178 -0
- package/docs/themes/tanuki/templates/landing.html +168 -0
- package/docs/themes/tanuki/templates/macros/nav.html +128 -0
- package/docs/themes/tanuki/templates/macros/posts.html +101 -0
- package/docs/themes/tanuki/templates/macros/ui.html +159 -0
- package/docs/themes/tanuki/templates/page.html +135 -0
- package/docs/themes/tanuki/templates/partials/footer.html +38 -0
- package/docs/themes/tanuki/templates/partials/header.html +366 -0
- package/docs/themes/tanuki/templates/partials/nav-buttons.html +55 -0
- package/docs/themes/tanuki/templates/partials/nav-overlay.html +81 -0
- package/docs/themes/tanuki/templates/partials/page-toc-panel.html +43 -0
- package/docs/themes/tanuki/templates/partials/search.html +52 -0
- package/docs/themes/tanuki/templates/partials/sidebar.html +107 -0
- package/docs/themes/tanuki/templates/partials/theme-toggle.html +35 -0
- package/docs/themes/tanuki/templates/partials/toc-overlay.html +146 -0
- package/docs/themes/tanuki/templates/partials/version-picker.html +38 -0
- package/docs/themes/tanuki/templates/print.html +244 -0
- package/docs/themes/tanuki/templates/section.html +186 -0
- package/docs/themes/tanuki/templates/taxonomy_list.html +18 -0
- package/docs/themes/tanuki/templates/taxonomy_single.html +31 -0
- package/docs/themes/tanuki/theme.toml +58 -0
- package/examples/hello-agent.rs +55 -0
- package/package.json +36 -0
- package/proto/config.proto +60 -0
- package/proto/events.proto +0 -0
- package/proto/runtime.proto +215 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "Building Accessible Websites: A Practical Guide"
|
|
3
|
+
description = "Accessibility isn't optional—it's essential. Learn the practical steps to make your website usable by everyone."
|
|
4
|
+
date = 2024-12-12
|
|
5
|
+
[taxonomies]
|
|
6
|
+
tags = ["accessibility", "html", "design"]
|
|
7
|
+
+++
|
|
8
|
+
|
|
9
|
+
# Building Accessible Websites: A Practical Guide
|
|
10
|
+
|
|
11
|
+
Web accessibility ensures your site works for everyone, including people with disabilities. Here's how to do it right.
|
|
12
|
+
|
|
13
|
+
## Semantic HTML
|
|
14
|
+
|
|
15
|
+
Use the right elements for the job:
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<!-- Bad -->
|
|
19
|
+
<div class="button" onclick="submit()">Submit</div>
|
|
20
|
+
|
|
21
|
+
<!-- Good -->
|
|
22
|
+
<button type="submit">Submit</button>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Semantic elements provide built-in accessibility features that `div`s don't have.
|
|
26
|
+
|
|
27
|
+
## Keyboard Navigation
|
|
28
|
+
|
|
29
|
+
Everything clickable should be keyboard accessible:
|
|
30
|
+
|
|
31
|
+
```css
|
|
32
|
+
/* Make focus visible */
|
|
33
|
+
:focus {
|
|
34
|
+
outline: 2px solid var(--accent);
|
|
35
|
+
outline-offset: 2px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Don't hide focus outlines */
|
|
39
|
+
:focus:not(:focus-visible) {
|
|
40
|
+
outline: none;
|
|
41
|
+
}
|
|
42
|
+
:focus-visible {
|
|
43
|
+
outline: 2px solid var(--accent);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Test your site using only the keyboard: Tab, Shift+Tab, Enter, and Escape should work everywhere.
|
|
48
|
+
|
|
49
|
+
## Alt Text for Images
|
|
50
|
+
|
|
51
|
+
Every image needs alt text:
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<!-- Informative image -->
|
|
55
|
+
<img src="chart.png" alt="Sales increased 50% in Q4 2024">
|
|
56
|
+
|
|
57
|
+
<!-- Decorative image -->
|
|
58
|
+
<img src="divider.png" alt="" role="presentation">
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If an image is decorative, use an empty alt attribute.
|
|
62
|
+
|
|
63
|
+
## Color Contrast
|
|
64
|
+
|
|
65
|
+
Ensure sufficient contrast between text and background:
|
|
66
|
+
|
|
67
|
+
- **4.5:1** minimum for normal text
|
|
68
|
+
- **3:1** minimum for large text (18px+ or 14px+ bold)
|
|
69
|
+
|
|
70
|
+
Don't rely on color alone to convey information:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<!-- Bad: color only -->
|
|
74
|
+
<span class="error">Invalid email</span>
|
|
75
|
+
|
|
76
|
+
<!-- Good: color + icon + text -->
|
|
77
|
+
<span class="error">
|
|
78
|
+
<svg aria-hidden="true"><!-- error icon --></svg>
|
|
79
|
+
Invalid email address
|
|
80
|
+
</span>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## ARIA Labels
|
|
84
|
+
|
|
85
|
+
Use ARIA when HTML semantics aren't enough:
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<button aria-label="Close dialog">
|
|
89
|
+
<svg><!-- X icon --></svg>
|
|
90
|
+
</button>
|
|
91
|
+
|
|
92
|
+
<nav aria-label="Main navigation">
|
|
93
|
+
<!-- links -->
|
|
94
|
+
</nav>
|
|
95
|
+
|
|
96
|
+
<div role="alert" aria-live="polite">
|
|
97
|
+
Your changes have been saved.
|
|
98
|
+
</div>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
But remember: **no ARIA is better than bad ARIA**.
|
|
102
|
+
|
|
103
|
+
## Skip Links
|
|
104
|
+
|
|
105
|
+
Let keyboard users skip repetitive navigation:
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<a href="#main-content" class="skip-link">
|
|
109
|
+
Skip to main content
|
|
110
|
+
</a>
|
|
111
|
+
|
|
112
|
+
<!-- ... navigation ... -->
|
|
113
|
+
|
|
114
|
+
<main id="main-content">
|
|
115
|
+
<!-- content -->
|
|
116
|
+
</main>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```css
|
|
120
|
+
.skip-link {
|
|
121
|
+
position: absolute;
|
|
122
|
+
top: -100%;
|
|
123
|
+
}
|
|
124
|
+
.skip-link:focus {
|
|
125
|
+
top: 0;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Testing Accessibility
|
|
130
|
+
|
|
131
|
+
Use these tools:
|
|
132
|
+
|
|
133
|
+
- **axe DevTools**: Browser extension for automated testing
|
|
134
|
+
- **WAVE**: Web accessibility evaluation tool
|
|
135
|
+
- **Screen readers**: VoiceOver (Mac), NVDA (Windows)
|
|
136
|
+
|
|
137
|
+
Run `lighthouse` in Chrome DevTools for an accessibility audit.
|
|
138
|
+
|
|
139
|
+
## Quick Wins
|
|
140
|
+
|
|
141
|
+
1. Add `lang` attribute to `<html>`
|
|
142
|
+
2. Use descriptive link text (not "click here")
|
|
143
|
+
3. Ensure form inputs have labels
|
|
144
|
+
4. Add captions to videos
|
|
145
|
+
5. Test at 200% zoom
|
|
146
|
+
|
|
147
|
+
Accessibility benefits everyone—not just users with disabilities.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "CSS Grid vs Flexbox: When to Use Each"
|
|
3
|
+
description = "Both CSS Grid and Flexbox solve layout problems, but they excel in different scenarios. Here's how to choose."
|
|
4
|
+
date = 2024-12-15
|
|
5
|
+
[taxonomies]
|
|
6
|
+
tags = ["css", "design", "frontend"]
|
|
7
|
+
+++
|
|
8
|
+
|
|
9
|
+
# CSS Grid vs Flexbox: When to Use Each
|
|
10
|
+
|
|
11
|
+
The age-old question: Grid or Flexbox? The answer is usually "both"—but knowing when to reach for each makes all the difference.
|
|
12
|
+
|
|
13
|
+
## The Mental Model
|
|
14
|
+
|
|
15
|
+
**Flexbox** is one-dimensional. It handles either a row *or* a column.
|
|
16
|
+
|
|
17
|
+
**Grid** is two-dimensional. It handles rows *and* columns simultaneously.
|
|
18
|
+
|
|
19
|
+
## Use Flexbox When...
|
|
20
|
+
|
|
21
|
+
### Aligning Items in a Single Direction
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
.navbar {
|
|
25
|
+
display: flex;
|
|
26
|
+
justify-content: space-between;
|
|
27
|
+
align-items: center;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Content Size Should Determine Layout
|
|
32
|
+
|
|
33
|
+
Flexbox lets items grow and shrink based on their content:
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
.tags {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-wrap: wrap;
|
|
39
|
+
gap: 0.5rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.tag {
|
|
43
|
+
/* Each tag sizes to its content */
|
|
44
|
+
padding: 0.25rem 0.5rem;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Centering Things
|
|
49
|
+
|
|
50
|
+
The classic centering trick:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
.centered {
|
|
54
|
+
display: flex;
|
|
55
|
+
justify-content: center;
|
|
56
|
+
align-items: center;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Use Grid When...
|
|
61
|
+
|
|
62
|
+
### Creating Page Layouts
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
.page {
|
|
66
|
+
display: grid;
|
|
67
|
+
grid-template-columns: 250px 1fr;
|
|
68
|
+
grid-template-rows: auto 1fr auto;
|
|
69
|
+
grid-template-areas:
|
|
70
|
+
"sidebar header"
|
|
71
|
+
"sidebar main"
|
|
72
|
+
"sidebar footer";
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Equal-Width Columns
|
|
77
|
+
|
|
78
|
+
```css
|
|
79
|
+
.card-grid {
|
|
80
|
+
display: grid;
|
|
81
|
+
grid-template-columns: repeat(3, 1fr);
|
|
82
|
+
gap: 1.5rem;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Overlapping Elements
|
|
87
|
+
|
|
88
|
+
Grid allows items to occupy the same cells:
|
|
89
|
+
|
|
90
|
+
```css
|
|
91
|
+
.hero {
|
|
92
|
+
display: grid;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.hero > * {
|
|
96
|
+
grid-area: 1 / 1;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.hero-image {
|
|
100
|
+
z-index: 1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.hero-text {
|
|
104
|
+
z-index: 2;
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Use Both Together
|
|
109
|
+
|
|
110
|
+
The real power comes from combining them:
|
|
111
|
+
|
|
112
|
+
```css
|
|
113
|
+
/* Grid for the overall layout */
|
|
114
|
+
.dashboard {
|
|
115
|
+
display: grid;
|
|
116
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
117
|
+
gap: 1rem;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Flexbox for card internals */
|
|
121
|
+
.card {
|
|
122
|
+
display: flex;
|
|
123
|
+
flex-direction: column;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.card-footer {
|
|
127
|
+
margin-top: auto; /* Push to bottom */
|
|
128
|
+
display: flex;
|
|
129
|
+
justify-content: space-between;
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Quick Reference
|
|
134
|
+
|
|
135
|
+
| Scenario | Use |
|
|
136
|
+
|----------|-----|
|
|
137
|
+
| Navigation bars | Flexbox |
|
|
138
|
+
| Page layout | Grid |
|
|
139
|
+
| Card grids | Grid |
|
|
140
|
+
| Card contents | Flexbox |
|
|
141
|
+
| Centering | Either |
|
|
142
|
+
| Form layouts | Grid |
|
|
143
|
+
| Button groups | Flexbox |
|
|
144
|
+
| Image galleries | Grid |
|
|
145
|
+
|
|
146
|
+
## The Subgrid Game-Changer
|
|
147
|
+
|
|
148
|
+
CSS Subgrid (now widely supported) lets nested grids align with their parent:
|
|
149
|
+
|
|
150
|
+
```css
|
|
151
|
+
.card-grid {
|
|
152
|
+
display: grid;
|
|
153
|
+
grid-template-columns: repeat(3, 1fr);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.card {
|
|
157
|
+
display: grid;
|
|
158
|
+
grid-template-rows: subgrid;
|
|
159
|
+
grid-row: span 3;
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
This ensures all card headers, bodies, and footers align across the row.
|
|
164
|
+
|
|
165
|
+
Stop asking "Grid or Flexbox?" Start asking "What problem am I solving?"
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "Customizing Catppuccin Colors"
|
|
3
|
+
description = "Learn how to customize the Tanuki theme's color palette using CSS custom properties."
|
|
4
|
+
date = 2024-12-25
|
|
5
|
+
[taxonomies]
|
|
6
|
+
tags = ["tutorial", "css", "theming"]
|
|
7
|
+
+++
|
|
8
|
+
|
|
9
|
+
# Customizing Catppuccin Colors
|
|
10
|
+
|
|
11
|
+
Tanuki uses the [Catppuccin](https://github.com/catppuccin/catppuccin) color palette, a soothing pastel theme that's easy on the eyes. But what if you want to customize it?
|
|
12
|
+
|
|
13
|
+
## Understanding the Color System
|
|
14
|
+
|
|
15
|
+
Tanuki uses CSS custom properties (variables) for all colors. This makes customization straightforward—just override the variables you want to change.
|
|
16
|
+
|
|
17
|
+
### The Base Palette
|
|
18
|
+
|
|
19
|
+
Each Catppuccin flavor (Latte for light, Mocha for dark) includes:
|
|
20
|
+
|
|
21
|
+
| Variable | Purpose |
|
|
22
|
+
|----------|---------|
|
|
23
|
+
| `--ctp-base` | Main background |
|
|
24
|
+
| `--ctp-mantle` | Secondary background |
|
|
25
|
+
| `--ctp-crust` | Tertiary background |
|
|
26
|
+
| `--ctp-surface0/1/2` | Surface layers |
|
|
27
|
+
| `--ctp-overlay0/1/2` | Overlay layers |
|
|
28
|
+
| `--ctp-text` | Primary text |
|
|
29
|
+
| `--ctp-subtext0/1` | Secondary text |
|
|
30
|
+
|
|
31
|
+
### Accent Colors
|
|
32
|
+
|
|
33
|
+
The fun colors for highlights and accents:
|
|
34
|
+
|
|
35
|
+
- `--ctp-rosewater` - Soft pink
|
|
36
|
+
- `--ctp-flamingo` - Coral
|
|
37
|
+
- `--ctp-pink` - Vibrant pink
|
|
38
|
+
- `--ctp-mauve` - Purple (default accent)
|
|
39
|
+
- `--ctp-red` - Error/danger
|
|
40
|
+
- `--ctp-maroon` - Deep red
|
|
41
|
+
- `--ctp-peach` - Orange
|
|
42
|
+
- `--ctp-yellow` - Warning/highlight
|
|
43
|
+
- `--ctp-green` - Success
|
|
44
|
+
- `--ctp-teal` - Teal
|
|
45
|
+
- `--ctp-sky` - Light blue
|
|
46
|
+
- `--ctp-sapphire` - Blue
|
|
47
|
+
- `--ctp-blue` - Primary blue
|
|
48
|
+
- `--ctp-lavender` - Soft purple
|
|
49
|
+
|
|
50
|
+
## Changing the Accent Color
|
|
51
|
+
|
|
52
|
+
The simplest customization is changing the accent color. Create a custom CSS file:
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
/* static/css/custom.css */
|
|
56
|
+
:root {
|
|
57
|
+
--color-accent: var(--ctp-pink);
|
|
58
|
+
--color-accent-hover: var(--ctp-pink);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then include it in your `config.toml`:
|
|
63
|
+
|
|
64
|
+
```toml
|
|
65
|
+
[extra]
|
|
66
|
+
stylesheets = ["css/custom.css"]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Creating a Custom Theme
|
|
70
|
+
|
|
71
|
+
Want something more dramatic? Override the entire palette:
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
/* A "cyberpunk" variant */
|
|
75
|
+
[data-theme="dark"] {
|
|
76
|
+
--ctp-base: #0a0a0f;
|
|
77
|
+
--ctp-mantle: #12121a;
|
|
78
|
+
--ctp-crust: #08080c;
|
|
79
|
+
--ctp-text: #00ff9f;
|
|
80
|
+
--ctp-subtext0: #00cc7f;
|
|
81
|
+
--ctp-mauve: #ff00ff;
|
|
82
|
+
--ctp-pink: #ff1493;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Using Other Catppuccin Flavors
|
|
87
|
+
|
|
88
|
+
Catppuccin has four flavors: Latte, Frappé, Macchiato, and Mocha. Tanuki uses Latte (light) and Mocha (dark) by default, but you can switch to others.
|
|
89
|
+
|
|
90
|
+
### Using Macchiato for Dark Mode
|
|
91
|
+
|
|
92
|
+
```css
|
|
93
|
+
[data-theme="dark"] {
|
|
94
|
+
/* Macchiato base colors */
|
|
95
|
+
--ctp-rosewater: #f4dbd6;
|
|
96
|
+
--ctp-flamingo: #f0c6c6;
|
|
97
|
+
--ctp-pink: #f5bde6;
|
|
98
|
+
--ctp-mauve: #c6a0f6;
|
|
99
|
+
--ctp-red: #ed8796;
|
|
100
|
+
--ctp-maroon: #ee99a0;
|
|
101
|
+
--ctp-peach: #f5a97f;
|
|
102
|
+
--ctp-yellow: #eed49f;
|
|
103
|
+
--ctp-green: #a6da95;
|
|
104
|
+
--ctp-teal: #8bd5ca;
|
|
105
|
+
--ctp-sky: #91d7e3;
|
|
106
|
+
--ctp-sapphire: #7dc4e4;
|
|
107
|
+
--ctp-blue: #8aadf4;
|
|
108
|
+
--ctp-lavender: #b7bdf8;
|
|
109
|
+
--ctp-text: #cad3f5;
|
|
110
|
+
--ctp-subtext1: #b8c0e0;
|
|
111
|
+
--ctp-subtext0: #a5adcb;
|
|
112
|
+
--ctp-overlay2: #939ab7;
|
|
113
|
+
--ctp-overlay1: #8087a2;
|
|
114
|
+
--ctp-overlay0: #6e738d;
|
|
115
|
+
--ctp-surface2: #5b6078;
|
|
116
|
+
--ctp-surface1: #494d64;
|
|
117
|
+
--ctp-surface0: #363a4f;
|
|
118
|
+
--ctp-base: #24273a;
|
|
119
|
+
--ctp-mantle: #1e2030;
|
|
120
|
+
--ctp-crust: #181926;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Tips for Color Customization
|
|
125
|
+
|
|
126
|
+
1. **Maintain contrast** - Ensure text remains readable against backgrounds
|
|
127
|
+
2. **Test both modes** - Check your changes in both light and dark themes
|
|
128
|
+
3. **Use the palette** - Stick to Catppuccin colors for a cohesive look
|
|
129
|
+
4. **Consider accessibility** - WCAG recommends 4.5:1 contrast for normal text
|
|
130
|
+
|
|
131
|
+
## Resources
|
|
132
|
+
|
|
133
|
+
- [Catppuccin GitHub](https://github.com/catppuccin/catppuccin)
|
|
134
|
+
- [Catppuccin Palette](https://catppuccin.com/palette)
|
|
135
|
+
- [Contrast Checker](https://webaim.org/resources/contrastchecker/)
|
|
136
|
+
|
|
137
|
+
Happy theming!
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
+++
|
|
2
|
+
title = "Dark Mode Best Practices for Web Development"
|
|
3
|
+
description = "Learn the key principles for implementing dark mode that respects user preferences and looks great."
|
|
4
|
+
date = 2024-12-20
|
|
5
|
+
[taxonomies]
|
|
6
|
+
tags = ["design", "css", "accessibility"]
|
|
7
|
+
+++
|
|
8
|
+
|
|
9
|
+
# Dark Mode Best Practices for Web Development
|
|
10
|
+
|
|
11
|
+
Dark mode has become an essential feature for modern websites. Here's how to implement it properly.
|
|
12
|
+
|
|
13
|
+
## Respect System Preferences
|
|
14
|
+
|
|
15
|
+
The first rule of dark mode is to respect what the user has already chosen at the OS level:
|
|
16
|
+
|
|
17
|
+
```css
|
|
18
|
+
@media (prefers-color-scheme: dark) {
|
|
19
|
+
:root {
|
|
20
|
+
--bg: #1e1e2e;
|
|
21
|
+
--text: #cdd6f4;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Use CSS Custom Properties
|
|
27
|
+
|
|
28
|
+
CSS custom properties make theme switching trivial:
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
:root {
|
|
32
|
+
--bg: #eff1f5;
|
|
33
|
+
--text: #4c4f69;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
[data-theme="dark"] {
|
|
37
|
+
--bg: #1e1e2e;
|
|
38
|
+
--text: #cdd6f4;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
body {
|
|
42
|
+
background: var(--bg);
|
|
43
|
+
color: var(--text);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Avoid Pure Black
|
|
48
|
+
|
|
49
|
+
Pure black (`#000000`) on screens can cause eye strain. Use a softer dark color like Catppuccin Mocha's base (`#1e1e2e`) instead.
|
|
50
|
+
|
|
51
|
+
## Consider Contrast Ratios
|
|
52
|
+
|
|
53
|
+
WCAG guidelines recommend:
|
|
54
|
+
- **4.5:1** for normal text
|
|
55
|
+
- **3:1** for large text and UI components
|
|
56
|
+
|
|
57
|
+
Tools like the [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/) can help verify your choices.
|
|
58
|
+
|
|
59
|
+
## Persist User Choice
|
|
60
|
+
|
|
61
|
+
Store the user's preference so it persists across sessions:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const theme = localStorage.getItem('theme') || 'auto';
|
|
65
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Smooth Transitions
|
|
69
|
+
|
|
70
|
+
Add a subtle transition to prevent jarring switches:
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
body {
|
|
74
|
+
transition: background-color 0.2s ease, color 0.2s ease;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Test Both Modes
|
|
79
|
+
|
|
80
|
+
Always test your site in both light and dark modes. Images, syntax highlighting, and embedded content can look different—or broken—in each mode.
|
|
81
|
+
|
|
82
|
+
Dark mode done right improves accessibility, reduces eye strain, and gives users control over their experience.
|