@vendoai/vendo 0.4.3 → 0.4.4
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/dist/capability-misses.js +2 -3
- package/dist/cli/cloud/client.d.ts +2 -5
- package/dist/cli/cloud/client.js +4 -4
- package/dist/cli/dep-versions.d.ts +1 -1
- package/dist/cli/dep-versions.js +1 -1
- package/dist/cli/doctor-codes.d.ts +4 -0
- package/dist/cli/doctor-codes.js +4 -0
- package/dist/cli/doctor.js +52 -1
- package/dist/cli/extract/apply.js +1 -1
- package/dist/cli/extract/delegate.js +9 -1
- package/dist/cli/extract/extraction.d.ts +4 -0
- package/dist/cli/extract/extraction.js +29 -2
- package/dist/cli/extract/harness.d.ts +12 -0
- package/dist/cli/extract/harness.js +3 -0
- package/dist/cli/extract/stages.js +5 -1
- package/dist/cli/init-scaffolds.d.ts +10 -1
- package/dist/cli/init-scaffolds.js +93 -1
- package/dist/cli/init.d.ts +3 -3
- package/dist/cli/init.js +53 -5
- package/dist/cli/playground/app/fake-client.js +11 -5
- package/dist/cli/playground/app/main.js +23 -13
- package/dist/cli/playground/app/scenario-mount.js +4 -1
- package/dist/cli/playground/app/theme-editor.js +27 -27
- package/dist/cli/playground/bundle.gen.d.ts +1 -1
- package/dist/cli/playground/bundle.gen.js +1 -1
- package/dist/cli/playground/embed-bundle.gen.d.ts +1 -1
- package/dist/cli/playground/embed-bundle.gen.js +1 -1
- package/dist/cli/shared.d.ts +1 -1
- package/dist/cli/shared.js +1 -1
- package/dist/cli/sync.d.ts +1 -1
- package/dist/cli/sync.js +1 -1
- package/dist/cloud-apps.js +2 -1
- package/dist/cloud-key-fetch.d.ts +16 -0
- package/dist/cloud-key-fetch.js +40 -0
- package/dist/cloud-tools.js +2 -1
- package/dist/connections.js +2 -2
- package/dist/dev-creds/model-edge.d.ts +21 -0
- package/dist/dev-creds/model-edge.js +24 -0
- package/dist/hosted-store.js +2 -1
- package/dist/refine.js +2 -1
- package/dist/sandbox.js +2 -2
- package/dist/server.d.ts +1 -1
- package/dist/server.js +56 -22
- package/dist/wire/shared.d.ts +2 -2
- package/dist/wire/shared.js +1 -1
- package/package.json +20 -11
package/dist/cli/init.js
CHANGED
|
@@ -2,7 +2,7 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
5
|
-
import { mergeOverrides, vendoSync
|
|
5
|
+
import { mergeOverrides, vendoSync } from "@vendoai/actions/sync";
|
|
6
6
|
import { createInterface } from "node:readline/promises";
|
|
7
7
|
import { stdin, stdout } from "node:process";
|
|
8
8
|
import { scrubErrorDetail } from "@vendoai/telemetry";
|
|
@@ -15,7 +15,7 @@ import { ENV_KEY_VARS, resolveDevCredential, describeDevCredential } from "../de
|
|
|
15
15
|
import { detectFramework, detectVendoWiring } from "./framework.js";
|
|
16
16
|
import { resolveScaffoldAuth } from "./init-auth.js";
|
|
17
17
|
import { ensureProviderDeps } from "./provider-deps.js";
|
|
18
|
-
import { expressServerSource, registrySource, routeSource, serverActionsModuleSource, VENDO_ENV_EXAMPLE, vendoRootWrapperSource, wiringServerActions, } from "./init-scaffolds.js";
|
|
18
|
+
import { customServerSource, expressServerSource, registrySource, routeSource, serverActionsModuleSource, VENDO_ENV_EXAMPLE, vendoRootWrapperSource, wiringServerActions, } from "./init-scaffolds.js";
|
|
19
19
|
import { createPrettyOutput, plainSelect, usePrettyOutput } from "./pretty.js";
|
|
20
20
|
import { contrastingText } from "./theme/color.js";
|
|
21
21
|
import { applyThemeDraft, extractTheme as extractThemeSlots, validateSlotValue, } from "./theme/extract-theme.js";
|
|
@@ -333,6 +333,16 @@ async function manualWiringLines(root, layout, withRegistry) {
|
|
|
333
333
|
`${wrap} // around your client root (see vendo/server for the imports; <VendoOverlay /> is the visible launcher + panel)`,
|
|
334
334
|
];
|
|
335
335
|
}
|
|
336
|
+
if (layout.kind === "custom") {
|
|
337
|
+
const wrap = withRegistry
|
|
338
|
+
? `<VendoRoot components={registry} theme={theme}>…<VendoOverlay /></VendoRoot>`
|
|
339
|
+
: `<VendoRoot theme={theme}>…<VendoOverlay /></VendoRoot>`;
|
|
340
|
+
return [
|
|
341
|
+
`Route your runtime's requests through the generated module — Cloudflare Workers: export default { fetch: (request, env) => handleVendoRequest(request, env) };`,
|
|
342
|
+
`${wrap} // around your client root (see vendo/server for the imports; <VendoOverlay /> is the visible launcher + panel)`,
|
|
343
|
+
`Set VENDO_BASE_URL to the deployed origin (credential forwarding fails closed without it).`,
|
|
344
|
+
];
|
|
345
|
+
}
|
|
336
346
|
if (layout.kind === "wired" || layout.kind === "already")
|
|
337
347
|
return [];
|
|
338
348
|
if (layout.kind === "overlay-missing") {
|
|
@@ -495,7 +505,12 @@ export function wireNextLayout(source, wrapperSpecifier) {
|
|
|
495
505
|
}
|
|
496
506
|
async function buildPlan(options, confirmAuth, selectAuth) {
|
|
497
507
|
const root = resolve(options.targetDir);
|
|
498
|
-
|
|
508
|
+
// "unknown" detection lands on the runtime-neutral custom scaffold — the
|
|
509
|
+
// safe default that exists now (guessing the Next layout into a Worker
|
|
510
|
+
// host was the field failure; the non-interactive guard still demands an
|
|
511
|
+
// explicit --framework so agents never inherit a guess silently).
|
|
512
|
+
const detected = options.framework ?? await detectFramework(root);
|
|
513
|
+
const framework = detected === "unknown" ? "custom" : detected;
|
|
499
514
|
const changes = [];
|
|
500
515
|
let authAdvice = null;
|
|
501
516
|
let authWired = null;
|
|
@@ -503,7 +518,40 @@ async function buildPlan(options, confirmAuth, selectAuth) {
|
|
|
503
518
|
let registryPath = null;
|
|
504
519
|
let withRegistry = false;
|
|
505
520
|
let layout = { kind: "manual" };
|
|
506
|
-
if (framework === "
|
|
521
|
+
if (framework === "custom") {
|
|
522
|
+
layout = { kind: "custom" };
|
|
523
|
+
const wiring = await detectVendoWiring(root);
|
|
524
|
+
if (!wiring.server || !wiring.client) {
|
|
525
|
+
const typescript = await exists(join(root, "tsconfig.json"));
|
|
526
|
+
const server = join(root, "vendo", typescript ? "server.ts" : "server.mjs");
|
|
527
|
+
const registryFile = join(root, "vendo", typescript ? "registry.tsx" : "registry.mjs");
|
|
528
|
+
const registryBefore = await readOptional(registryFile);
|
|
529
|
+
const serverBefore = await readOptional(server);
|
|
530
|
+
// Same ownership rules as the Express branch: init composes only when
|
|
531
|
+
// it CREATES the composition, and the registry regenerates only for a
|
|
532
|
+
// consumer that uses it.
|
|
533
|
+
const scaffolding = serverBefore === null && !wiring.server;
|
|
534
|
+
const registryPlanned = registryBefore === null
|
|
535
|
+
&& (scaffolding || serverBefore?.includes("./registry") === true);
|
|
536
|
+
if (registryPlanned) {
|
|
537
|
+
const path = relative(root, registryFile);
|
|
538
|
+
const registryAfter = registrySource(typescript ? "tsx" : "mjs");
|
|
539
|
+
changes.push({ absolute: registryFile, path, before: null, after: registryAfter, diff: diff(path, null, registryAfter) });
|
|
540
|
+
registryPath = path;
|
|
541
|
+
}
|
|
542
|
+
if (scaffolding) {
|
|
543
|
+
const path = relative(root, server);
|
|
544
|
+
const auth = await resolveScaffoldAuth(root, path, options.auth, confirmAuth, selectAuth);
|
|
545
|
+
const serverAfter = customServerSource(typescript, auth.wired);
|
|
546
|
+
changes.push({ absolute: server, path, before: null, after: serverAfter, diff: diff(path, null, serverAfter) });
|
|
547
|
+
authAdvice = auth.advice;
|
|
548
|
+
authWired = auth.wired;
|
|
549
|
+
compositionPath = path;
|
|
550
|
+
}
|
|
551
|
+
withRegistry = registryBefore !== null || registryPlanned;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
else if (framework === "express") {
|
|
507
555
|
layout = { kind: "express" };
|
|
508
556
|
const wiring = await detectVendoWiring(root);
|
|
509
557
|
if (!wiring.server || !wiring.client) {
|
|
@@ -773,7 +821,7 @@ export async function runInit(options) {
|
|
|
773
821
|
if (options.framework === undefined && (options.yes === true || !interactive)
|
|
774
822
|
&& await detectFramework(root) === "unknown") {
|
|
775
823
|
output.error("Framework not detected (no next or express dependency in package.json) and this run cannot ask. " +
|
|
776
|
-
"Pass --framework.
|
|
824
|
+
"Pass --framework. Examples: vendo init --yes --framework next · --framework custom (any Web-standard runtime: Cloudflare Workers, Bun, Hono, ...)");
|
|
777
825
|
return 1;
|
|
778
826
|
}
|
|
779
827
|
// (No stdin-TTY guard on these defaults, unlike the star ask's: an unshown
|
|
@@ -72,12 +72,18 @@ export function createFakeClient(fixtures) {
|
|
|
72
72
|
},
|
|
73
73
|
connections: {
|
|
74
74
|
list: async () => [...state.connections],
|
|
75
|
-
//
|
|
76
|
-
//
|
|
75
|
+
// A realistic host catalog: the toolkits the scenarios act through
|
|
76
|
+
// (slack, github) plus the breadth a real Composio-brokered host
|
|
77
|
+
// exposes, so the connect tray demos search + scroll + real brand
|
|
78
|
+
// marks (every slug below has a real logo on logos.composio.dev).
|
|
77
79
|
catalog: async () => [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
"slack", "github", "gmail", "googlecalendar", "googledrive",
|
|
81
|
+
"googlesheets", "notion", "linear", "jira", "confluence", "asana",
|
|
82
|
+
"trello", "clickup", "monday", "todoist", "hubspot", "salesforce",
|
|
83
|
+
"stripe", "shopify", "intercom", "zendesk", "airtable", "dropbox",
|
|
84
|
+
"figma", "discord", "zoom", "outlook", "calendly", "mailchimp",
|
|
85
|
+
"typeform",
|
|
86
|
+
].map((toolkit) => ({ toolkit, connector: "composio" })),
|
|
81
87
|
initiate: async ({ toolkit, connector }) => ({
|
|
82
88
|
id: `conn_${toolkit}_new`,
|
|
83
89
|
connector: connector ?? "composio",
|
|
@@ -6,27 +6,34 @@ import { ScenarioMount } from "./scenario-mount.js";
|
|
|
6
6
|
import { scenarios } from "./scenarios.js";
|
|
7
7
|
import { ThemeEditor, useGoogleFont } from "./theme-editor.js";
|
|
8
8
|
import { decodeThemeParam, encodeThemeParam } from "./theme-state.js";
|
|
9
|
+
/* Vendo brand shell (brand kit): Porcelain #FAFAF8, Ink #17171A, Ultramarine
|
|
10
|
+
#4338CA, Onest (its @font-face rides in via the chrome stylesheet). The
|
|
11
|
+
STAGE column deliberately has no fixed background — App paints it with the
|
|
12
|
+
active theme's colors.background so every chrome surface sits on its own
|
|
13
|
+
canvas edge-to-edge instead of printing an abrupt theme-colored rectangle
|
|
14
|
+
on the shell. */
|
|
9
15
|
const SHELL_CSS = `
|
|
10
16
|
:root { color-scheme: light; }
|
|
11
17
|
* { box-sizing: border-box; }
|
|
12
|
-
body { margin: 0; font-family: Inter, system-ui, -apple-system, sans-serif; background: #
|
|
18
|
+
body { margin: 0; font-family: Onest, Inter, system-ui, -apple-system, sans-serif; background: #fafaf8; color: #17171a; }
|
|
13
19
|
.pg-shell { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 100vh; }
|
|
14
|
-
.pg-nav { border-right: 1px solid
|
|
20
|
+
.pg-nav { border-right: 1px solid rgba(23, 23, 26, 0.08); background: #fafaf8; padding: 18px 14px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
|
|
15
21
|
.pg-brand { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; margin: 4px 6px 2px; }
|
|
16
|
-
.pg-brand
|
|
17
|
-
.pg-
|
|
18
|
-
.pg-
|
|
19
|
-
.pg-link
|
|
20
|
-
.pg-link
|
|
21
|
-
.pg-
|
|
22
|
+
.pg-brand-mark { color: #4338ca; }
|
|
23
|
+
.pg-brand small { display: block; font-weight: 500; font-size: 11px; color: #6f6f78; margin-top: 3px; }
|
|
24
|
+
.pg-group { font-size: 10.5px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.08em; color: #85858f; margin: 18px 6px 6px; }
|
|
25
|
+
.pg-link { display: block; padding: 7px 10px; border-radius: 8px; font-size: 13px; color: #3a3a41; text-decoration: none; transition: background .12s, color .12s; }
|
|
26
|
+
.pg-link:hover { background: rgba(67, 56, 202, 0.07); color: #17171a; }
|
|
27
|
+
.pg-link[aria-current="page"] { background: #17171a; color: #fafaf8; }
|
|
28
|
+
.pg-main { padding: 26px 30px 60px; min-width: 0; transition: background .2s, color .2s; }
|
|
22
29
|
@media (max-width: 640px) {
|
|
23
30
|
.pg-shell { grid-template-columns: 1fr; }
|
|
24
|
-
.pg-nav { position: static; height: auto; border-right: none; border-bottom: 1px solid
|
|
31
|
+
.pg-nav { position: static; height: auto; border-right: none; border-bottom: 1px solid rgba(23, 23, 26, 0.08); }
|
|
25
32
|
.pg-main { padding: 18px 16px 80px; }
|
|
26
33
|
}
|
|
27
34
|
.pg-head { max-width: 860px; margin-bottom: 20px; }
|
|
28
35
|
.pg-head h1 { font-size: 19px; letter-spacing: -0.01em; margin: 0 0 6px; }
|
|
29
|
-
.pg-head p { font-size: 13.5px;
|
|
36
|
+
.pg-head p { font-size: 13.5px; opacity: 0.72; line-height: 1.55; margin: 0; }
|
|
30
37
|
.pg-stage { max-width: 860px; }
|
|
31
38
|
.pg-embed { padding: 0; }
|
|
32
39
|
`;
|
|
@@ -95,12 +102,15 @@ function App() {
|
|
|
95
102
|
const embed = new URLSearchParams(window.location.search).has("embed");
|
|
96
103
|
const [theme, setTheme] = useThemeState(embed);
|
|
97
104
|
if (embed) {
|
|
98
|
-
return (
|
|
105
|
+
return (
|
|
106
|
+
// Same host-canvas rule as the stage: the embed page (the phone iframe's
|
|
107
|
+
// whole viewport) wears the theme background so the surface blends.
|
|
108
|
+
_jsx("div", { className: "pg-embed", style: { background: theme.colors.background, minHeight: "100vh" }, children: _jsx(ScenarioMount, { scenario: scenario, theme: theme }, scenario.id) }));
|
|
99
109
|
}
|
|
100
110
|
const groups = [...new Set(scenarios.map((entry) => entry.group))];
|
|
101
|
-
return (_jsxs("div", { className: "pg-shell", children: [_jsxs("nav", { className: "pg-nav", "aria-label": "Scenarios", children: [_jsxs("div", { className: "pg-brand", children: ["
|
|
111
|
+
return (_jsxs("div", { className: "pg-shell", children: [_jsxs("nav", { className: "pg-nav", "aria-label": "Scenarios", children: [_jsxs("div", { className: "pg-brand", children: [_jsx("span", { className: "pg-brand-mark", children: "vendo" }), " playground", _jsx("small", { children: "every surface \u00B7 scripted data \u00B7 no model key" })] }), groups.map((group) => (_jsxs("div", { children: [_jsx("div", { className: "pg-group", children: group }), scenarios
|
|
102
112
|
.filter((entry) => entry.group === group)
|
|
103
|
-
.map((entry) => (_jsx("a", { className: "pg-link", href: `#${entry.id}`, "aria-current": entry.id === scenario.id ? "page" : undefined, children: entry.title }, entry.id)))] }, group)))] }), _jsxs("main", { className: "pg-main", children: [_jsxs("header", { className: "pg-head", children: [_jsx("h1", { children: scenario.title }), _jsx("p", { children: scenario.description })] }), _jsx("div", { className: "pg-stage", children: _jsx(ScenarioMount, { scenario: scenario, theme: theme }, scenario.id) })] }), _jsx(ThemeEditor, { theme: theme, onChange: setTheme })] }));
|
|
113
|
+
.map((entry) => (_jsx("a", { className: "pg-link", href: `#${entry.id}`, "aria-current": entry.id === scenario.id ? "page" : undefined, children: entry.title }, entry.id)))] }, group)))] }), _jsxs("main", { className: "pg-main", style: { background: theme.colors.background, color: theme.colors.text }, children: [_jsxs("header", { className: "pg-head", children: [_jsx("h1", { children: scenario.title }), _jsx("p", { children: scenario.description })] }), _jsx("div", { className: "pg-stage", children: _jsx(ScenarioMount, { scenario: scenario, theme: theme }, scenario.id) })] }), _jsx(ThemeEditor, { theme: theme, onChange: setTheme })] }));
|
|
104
114
|
}
|
|
105
115
|
const style = document.createElement("style");
|
|
106
116
|
style.textContent = SHELL_CSS;
|
|
@@ -44,5 +44,8 @@ export function ScenarioMount({ scenario, theme, root }) {
|
|
|
44
44
|
const client = useMemo(() => createFakeClient((scenario.fixtures ?? playgroundFixtures)()), [scenario]);
|
|
45
45
|
const transport = useMemo(() => (scenario.script ? new ScriptedTransport(scenario.script, { speed: scenario.speed ?? 1 }) : undefined), [scenario]);
|
|
46
46
|
useAutoSend(scenario, root);
|
|
47
|
-
|
|
47
|
+
// No explicit `connectors` prop: the surfaces resolve the auto catalog from
|
|
48
|
+
// the fake client (fake-client.ts), so the tray demos search + scroll over
|
|
49
|
+
// a realistic host's toolkit breadth.
|
|
50
|
+
return (_jsx(VendoProvider, { client: client, transport: transport, theme: theme, tools: playgroundToolMeta, children: scenario.render() }));
|
|
48
51
|
}
|
|
@@ -5,51 +5,51 @@ const EDITOR_CSS = `
|
|
|
5
5
|
/* Above the chrome's own overlay/takeover layers (they top out at
|
|
6
6
|
2147483100) — the editor is harness tooling and must stay reachable
|
|
7
7
|
while the overlay scenario is open. */
|
|
8
|
-
.te-card, .te-pill { position: fixed; top: 16px; right: 16px; z-index: 2147483200; font-family: Inter, system-ui, sans-serif; }
|
|
9
|
-
.te-card { width: 302px; max-height: calc(100vh - 32px); display: flex; flex-direction: column; background: #
|
|
8
|
+
.te-card, .te-pill { position: fixed; top: 16px; right: 16px; z-index: 2147483200; font-family: Onest, Inter, system-ui, sans-serif; }
|
|
9
|
+
.te-card { width: 302px; max-height: calc(100vh - 32px); display: flex; flex-direction: column; background: #fafaf8; border: 1px solid rgba(23, 23, 26, 0.1); border-radius: 14px; box-shadow: 0 18px 44px rgba(23, 23, 26, 0.18); transform-origin: top right; transition: transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 320ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
|
10
10
|
.te-card[data-closed="true"] { transform: scale(0.6) translateY(-8px); opacity: 0; pointer-events: none; }
|
|
11
|
-
.te-pill { display: inline-flex; align-items: center; gap: 7px; background: #
|
|
11
|
+
.te-pill { display: inline-flex; align-items: center; gap: 7px; background: #17171a; color: #fafaf8; border: none; border-radius: 999px; font: 600 12.5px Onest, Inter, sans-serif; padding: 9px 15px; cursor: pointer; box-shadow: 0 10px 26px rgba(23, 23, 26, 0.25); opacity: 0; pointer-events: none; transition: opacity 320ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
|
12
12
|
.te-pill[data-shown="true"] { opacity: 1; pointer-events: auto; }
|
|
13
|
-
.te-dot { width: 13px; height: 13px; border-radius: 50%; background: conic-gradient(#
|
|
13
|
+
.te-dot { width: 13px; height: 13px; border-radius: 50%; background: conic-gradient(#4338ca, #818cf8, #22d3ee, #4338ca); border: 1px solid rgba(255, 255, 255, 0.4); }
|
|
14
14
|
.te-grab { display: none; }
|
|
15
|
-
.te-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px 10px; border-bottom: 1px solid
|
|
16
|
-
.te-head b { font-size: 12.5px; color: #
|
|
17
|
-
.te-head small { display: block; font-weight: 500; font-size: 10.5px; color: #
|
|
18
|
-
.te-x { border: none; background: none; color: #
|
|
19
|
-
.te-x:hover { background:
|
|
20
|
-
.te-body { overflow-y: auto; padding: 10px 14px 12px; font-size: 12.5px; color: #
|
|
15
|
+
.te-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px 10px; border-bottom: 1px solid rgba(23, 23, 26, 0.1); flex-shrink: 0; }
|
|
16
|
+
.te-head b { font-size: 12.5px; color: #17171a; }
|
|
17
|
+
.te-head small { display: block; font-weight: 500; font-size: 10.5px; color: #6f6f78; margin-top: 2px; }
|
|
18
|
+
.te-x { border: none; background: none; color: #6f6f78; font-size: 14px; cursor: pointer; padding: 2px 6px; border-radius: 6px; line-height: 1; }
|
|
19
|
+
.te-x:hover { background: rgba(67, 56, 202, 0.08); color: #17171a; }
|
|
20
|
+
.te-body { overflow-y: auto; padding: 10px 14px 12px; font-size: 12.5px; color: #17171a; }
|
|
21
21
|
.te-sec { margin-bottom: 14px; }
|
|
22
|
-
.te-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #
|
|
22
|
+
.te-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: #85858f; margin-bottom: 7px; }
|
|
23
23
|
.te-presets { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
24
|
-
.te-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid
|
|
24
|
+
.te-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(23, 23, 26, 0.1); background: #ffffff; border-radius: 999px; padding: 4px 10px 4px 5px; font: 600 11.5px Onest, Inter, sans-serif; cursor: pointer; color: #17171a; }
|
|
25
25
|
.te-chip .te-swatch { width: 16px; height: 16px; border-radius: 50%; border: 1px solid rgba(0, 0, 0, 0.12); }
|
|
26
|
-
.te-chip[aria-pressed="true"] { border-color: #
|
|
26
|
+
.te-chip[aria-pressed="true"] { border-color: #4338ca; box-shadow: inset 0 0 0 1px #4338ca; }
|
|
27
27
|
.te-crow { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
|
|
28
|
-
.te-crow input[type="color"] { width: 24px; height: 24px; border: 1px solid
|
|
28
|
+
.te-crow input[type="color"] { width: 24px; height: 24px; border: 1px solid rgba(23, 23, 26, 0.1); border-radius: 7px; padding: 1px; background: #ffffff; cursor: pointer; flex-shrink: 0; }
|
|
29
29
|
.te-crow span { flex: 1; font-weight: 550; font-size: 11.5px; }
|
|
30
|
-
.te-crow code { font: 500 10.5px ui-monospace, monospace; color: #
|
|
31
|
-
.te-body select, .te-body input[type="text"] { width: 100%; font: 500 12px Inter, sans-serif; color: #
|
|
30
|
+
.te-crow code { font: 500 10.5px ui-monospace, monospace; color: #6f6f78; }
|
|
31
|
+
.te-body select, .te-body input[type="text"] { width: 100%; font: 500 12px Onest, Inter, sans-serif; color: #17171a; background: #ffffff; border: 1px solid rgba(23, 23, 26, 0.1); border-radius: 8px; padding: 6px 8px; }
|
|
32
32
|
.te-body input[type="text"] { margin-top: 6px; }
|
|
33
33
|
.te-srow { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
|
|
34
34
|
.te-srow label { font-size: 11.5px; font-weight: 550; width: 62px; flex-shrink: 0; }
|
|
35
|
-
.te-srow input[type="range"] { flex: 1; accent-color: #
|
|
36
|
-
.te-srow output { font: 500 10.5px ui-monospace, monospace; color: #
|
|
35
|
+
.te-srow input[type="range"] { flex: 1; accent-color: #4338ca; min-width: 0; }
|
|
36
|
+
.te-srow output { font: 500 10.5px ui-monospace, monospace; color: #6f6f78; width: 34px; text-align: right; flex-shrink: 0; }
|
|
37
37
|
.te-segs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
38
|
-
.te-seg { display: flex; background: #
|
|
39
|
-
.te-seg button { flex: 1; border: none; background: none; font: 600 11px Inter, sans-serif; color: #
|
|
40
|
-
.te-seg button[aria-pressed="true"] { background: #
|
|
41
|
-
.te-foot { display: flex; gap: 8px; padding: 10px 14px; border-top: 1px solid
|
|
42
|
-
.te-foot button { flex: 1; font: 600 11.5px Inter, sans-serif; border-radius: 8px; padding: 7px 0; cursor: pointer; }
|
|
43
|
-
.te-copy { background: #
|
|
44
|
-
.te-link { background: #
|
|
38
|
+
.te-seg { display: flex; background: #ffffff; border: 1px solid rgba(23, 23, 26, 0.1); border-radius: 9px; padding: 2px; gap: 2px; }
|
|
39
|
+
.te-seg button { flex: 1; border: none; background: none; font: 600 11px Onest, Inter, sans-serif; color: #6f6f78; padding: 5px 0; border-radius: 7px; cursor: pointer; }
|
|
40
|
+
.te-seg button[aria-pressed="true"] { background: #17171a; color: #fafaf8; }
|
|
41
|
+
.te-foot { display: flex; gap: 8px; padding: 10px 14px; border-top: 1px solid rgba(23, 23, 26, 0.1); flex-shrink: 0; }
|
|
42
|
+
.te-foot button { flex: 1; font: 600 11.5px Onest, Inter, sans-serif; border-radius: 8px; padding: 7px 0; cursor: pointer; }
|
|
43
|
+
.te-copy { background: #17171a; color: #fafaf8; border: 1px solid #17171a; }
|
|
44
|
+
.te-link { background: #ffffff; color: #17171a; border: 1px solid rgba(23, 23, 26, 0.1); }
|
|
45
45
|
@media (prefers-reduced-motion: reduce) {
|
|
46
46
|
.te-card, .te-pill { transition: none; }
|
|
47
47
|
}
|
|
48
48
|
@media (max-width: 640px) {
|
|
49
|
-
.te-card { top: auto; right: 0; left: 0; bottom: 0; width: auto; max-height: 72vh; border-radius: 18px 18px 0 0; border-left: none; border-right: none; border-bottom: none; padding-bottom: env(safe-area-inset-bottom, 0px); transform-origin: bottom center; box-shadow: 0 -16px 44px rgba(
|
|
49
|
+
.te-card { top: auto; right: 0; left: 0; bottom: 0; width: auto; max-height: 72vh; border-radius: 18px 18px 0 0; border-left: none; border-right: none; border-bottom: none; padding-bottom: env(safe-area-inset-bottom, 0px); transform-origin: bottom center; box-shadow: 0 -16px 44px rgba(23, 23, 26, 0.3); }
|
|
50
50
|
.te-card[data-closed="true"] { transform: translateY(105%); opacity: 1; }
|
|
51
51
|
.te-pill { top: auto; bottom: calc(env(safe-area-inset-bottom, 0px) + 16px); }
|
|
52
|
-
.te-grab { display: block; width: 40px; height: 4px; border-radius: 2px; background:
|
|
52
|
+
.te-grab { display: block; width: 40px; height: 4px; border-radius: 2px; background: rgba(23, 23, 26, 0.18); margin: 8px auto 0; flex-shrink: 0; }
|
|
53
53
|
.te-x { padding: 6px 10px; }
|
|
54
54
|
}
|
|
55
55
|
`;
|