diff --git a/src/facets/connect/atproto/index.html b/src/facets/connect/atproto/index.html
index 73a40a7a..5af1bed6 100644
--- a/src/facets/connect/atproto/index.html
+++ b/src/facets/connect/atproto/index.html
@@ -1,10 +1,12 @@
-
+
diff --git a/src/facets/connect/atproto/index.inline.js b/src/facets/connect/atproto/index.inline.js
index a186e820..11c82249 100644
--- a/src/facets/connect/atproto/index.inline.js
+++ b/src/facets/connect/atproto/index.inline.js
@@ -1,6 +1,3 @@
-import "@awesome.me/webawesome/dist/components/callout/callout.js";
-import "@awesome.me/webawesome/dist/components/input/input.js";
-
import { html, nothing, render as litRender } from "lit-html";
import { NAME as ATPROTO_NAME } from "~/components/output/raw/atproto/element.js";
@@ -13,7 +10,6 @@ import { setup } from "~/facets/connect/common.js";
foundation.setup({ title: "Connect AT Protocol | Diffuse" });
/**
- * @import { default as WaInput } from "@awesome.me/webawesome/dist/components/input/input.js"
* @import { ATProtoOutputElement } from "~/components/output/raw/atproto/types.d.ts"
* @import TrackUriPasskeyTransformer from "~/components/transformer/output/refiner/track-uri-passkey/element.js"
*/
@@ -23,22 +19,39 @@ foundation.setup({ title: "Connect AT Protocol | Diffuse" });
////////////////////////////////////////////
const outputOrchestrator = await foundation.orchestrator.output();
+
await customElements.whenDefined(outputOrchestrator.localName);
+await customElements.whenDefined(ATPROTO_NAME);
+
+// The AT Protocol option is added dynamically by the output-bundle facet, which
+// runs in a separate script and appends the element to the output configurator
+// via a signal effect. That effect may not have fired yet when this facet loads,
+// so we observe the configurator for child-list mutations and resolve as soon as
+// the option appears.
+const outputConfigurator = outputOrchestrator.outputConfigurator;
+
+const atprotoOption = await new Promise((resolve) => {
+ const check = async () => {
+ const opt = (await outputOrchestrator.options()).find(
+ (o) => o.label === "AT Protocol",
+ );
+ if (opt) {
+ observer.disconnect();
+ resolve(opt);
+ }
+ };
+
+ const observer = new MutationObserver(check);
+ observer.observe(outputConfigurator, { childList: true });
+ check();
+});
-const atprotoOption = (await outputOrchestrator.options()).find(
- (o) => o.label === "AT Protocol",
-);
+const ATPROTO_OUTPUT_ID = atprotoOption.id;
const atprotoEl = /** @type {ATProtoOutputElement | undefined} */ (
outputOrchestrator.root().querySelector(ATPROTO_NAME)
);
-if (!atprotoOption) {
- throw new Error("AT Protocol output was not enabled!");
-}
-
-const ATPROTO_OUTPUT_ID = atprotoOption.id;
-
const atprotoPasskeyEl = /** @type {TrackUriPasskeyTransformer | null} */ (
outputOrchestrator.root().querySelector(
`${PASSKEY_NAME}[namespace="atproto"]`,
@@ -64,19 +77,13 @@ const { setItems } = setup({
Connect to your AT Protocol identity to use it as user-data storage.
-
+
Your data is stored as lexicon records in your personal data server (PDS).
`,
formFields: html`
-
- * Required fields
+ Handle
`,
onSubmit: (_mode) => connect(),
@@ -87,7 +94,7 @@ const { setItems } = setup({
});
const handleInput =
- /** @type {WaInput} */ (document.querySelector("#atproto-handle"));
+ /** @type {HTMLInputElement} */ (document.querySelector("#atproto-handle"));
////////////////////////////////////////////
// REACTIVE LIST
@@ -120,8 +127,7 @@ effect(() => {
if (atprotoPasskeyEl) {
const passkeyRoot = document.createElement("div");
- passkeyRoot.classList.add("wa-stack");
- document.querySelector("main .card-body")?.appendChild(passkeyRoot);
+ document.querySelector("main .facet__right")?.appendChild(passkeyRoot);
effect(() => {
const passkeyActive = atprotoPasskeyEl.passkeyActive() ?? false;
@@ -131,7 +137,7 @@ if (atprotoPasskeyEl) {
litRender(
html`
-
+
Passkey encryption (optional)
@@ -142,61 +148,44 @@ if (atprotoPasskeyEl) {
Passkey active — Track URIs are encrypted.
${passkeyError
- ? html`
-
${passkeyError}
- `
+ ? html`
${passkeyError}
`
: nothing}
- Remove passkey
+ Remove passkey
-
+
Removing the passkey will expose all the sensitive information that was
previously encrypted.
`
: html`
-
+
Track URIs can optionally be encrypted so that passwords and other sensitive
authentication details are kept private. Note that, with this enabled, other
people cannot play audio listed on your account.
${passkeyError
- ? html`
-
${passkeyError}
- `
+ ? html`
${passkeyError}
`
: nothing}
- ${passkeyWorking
- ? "Setting up …"
- : "Set up passkey encryption"}
- ${passkeyWorking
- ? "Authenticating …"
- : "Use existing passkey"}
+
+ ${passkeyWorking ? "Setting up …" : "Set up passkey encryption"}
+
+
+ ${passkeyWorking ? "Authenticating …" : "Use existing passkey"}
+
- `} ${lockedTracksCount > 0
+ `}
+ ${lockedTracksCount > 0
? html`
-
+
${lockedTracksCount} encrypted track(s) cannot be played until you unlock them with
your passkey.
-
+
`
: nothing}
`,
diff --git a/src/facets/connect/common.css b/src/facets/connect/common.css
index 54a52250..1c7ca20a 100644
--- a/src/facets/connect/common.css
+++ b/src/facets/connect/common.css
@@ -1,116 +1,70 @@
-main {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 100dvh;
- padding: var(--wa-space-m);
-}
-
-wa-card {
- width: min(400px, calc(100vw - 2rem));
-}
-
-.card-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
-}
+@import "../../styles/diffuse/facet.css";
-.card-body {
- display: flex;
- flex-direction: column;
- gap: var(--wa-space-m);
-}
-
-.button-row {
- display: flex;
- gap: var(--wa-space-s);
- flex-wrap: wrap;
-}
-
-.dialog-body {
+.connect-list {
display: flex;
flex-direction: column;
- gap: var(--wa-space-m);
-}
-
-.dialog-footer {
- display: flex;
- gap: var(--wa-space-s);
-}
-
-.connect-list {
+ gap: var(--space-xs);
list-style: none;
- padding: 0;
margin: 0;
- display: flex;
- flex-direction: column;
- gap: var(--wa-space-s);
+ padding: 0;
}
.connect-item {
- display: flex;
align-items: center;
- gap: var(--wa-space-s);
+ display: flex;
+ gap: var(--space-xs);
margin-left: 0;
}
.connect-item__info {
display: flex;
flex-direction: column;
- gap: var(--wa-space-2xs);
flex: 1;
+ gap: var(--space-3xs);
min-width: 0;
}
.connect-item__name {
- font-weight: var(--wa-font-weight-semibold);
- white-space: nowrap;
+ font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
+ white-space: nowrap;
}
.connect-item__detail {
- font-size: var(--wa-font-size-xs);
- color: var(--wa-color-text-quiet);
- white-space: nowrap;
+ color: oklch(from var(--text-color) l c h / 0.55);
+ font-size: var(--fs-xs);
overflow: hidden;
text-overflow: ellipsis;
+ white-space: nowrap;
}
.connect-item__tags {
display: flex;
- gap: var(--wa-space-2xs);
flex-shrink: 0;
+ gap: var(--space-3xs);
}
.dropzone {
align-items: center;
- border: 2px dashed var(--wa-color-neutral-border-quiet);
- border-radius: var(--wa-border-radius-m);
- color: var(--wa-color-text-quiet);
+ border: 2px dashed var(--border-color);
+ border-radius: var(--radius-md);
+ color: oklch(from var(--text-color) l c h / 0.55);
+ cursor: pointer;
display: flex;
flex-direction: column;
- gap: var(--wa-space-xs);
- font-size: var(--wa-font-size-s);
+ font-size: var(--fs-sm);
+ gap: var(--space-2xs);
justify-content: center;
- padding: var(--wa-space-l);
+ padding: var(--space-md);
transition:
background-color 150ms,
border-color 150ms,
color 150ms;
&.dropzone--active {
- background-color: var(--wa-color-surface-sunken);
- border-color: var(--wa-color-brand-500);
- color: var(--wa-color-text-normal);
+ background-color: var(--form-color);
+ border-color: var(--accent);
+ color: var(--text-color);
}
}
-
-[hidden] {
- display: none !important;
-}
-
-p {
- margin: 0;
-}
diff --git a/src/facets/connect/common.js b/src/facets/connect/common.js
index 12ee180a..c986d3c8 100644
--- a/src/facets/connect/common.js
+++ b/src/facets/connect/common.js
@@ -1,19 +1,6 @@
-import "@awesome.me/webawesome/dist/components/badge/badge.js";
-import "@awesome.me/webawesome/dist/components/button/button.js";
-import "@awesome.me/webawesome/dist/components/callout/callout.js";
-import "@awesome.me/webawesome/dist/components/card/card.js";
-import "@awesome.me/webawesome/dist/components/dialog/dialog.js";
-import "@awesome.me/webawesome/dist/components/divider/divider.js";
-import "@awesome.me/webawesome/dist/components/icon/icon.js";
-
-import "~/common/webawesome/detect-dark.js";
-import "~/common/webawesome/phosphor/bold.js";
-import "~/common/webawesome/phosphor/fill.js";
-
import { html, nothing, render as litRender } from "lit-html";
/**
- * @import { default as WaDialog } from "@awesome.me/webawesome/dist/components/dialog/dialog.js"
* @import { TemplateResult } from "lit-html"
*/
@@ -28,7 +15,8 @@ import { html, nothing, render as litRender } from "lit-html";
*
* @param {Object} config
* @param {string} config.title - Card header title
- * @param {TemplateResult | string} config.description - Content above the buttons
+ * @param {TemplateResult | string} config.description - Content shown on the left side
+ * @param {TemplateResult} [config.rightContent] - Extra content shown at the top of the right side
* @param {TemplateResult} config.formFields - Form body content (inputs, footnotes, etc.)
* @param {(mode: 'input' | 'output') => Promise} config.onSubmit
* @param {boolean} [config.hasInput] - Whether to show the "Add audio input" button (default: true)
@@ -41,6 +29,7 @@ export function setup(
{
title,
description,
+ rightContent = nothing,
formFields,
onSubmit,
hasInput = true,
@@ -53,64 +42,67 @@ export function setup(
litRender(
html`
-
-