diff --git a/index.html b/index.html
index 009c5a2..d86f918 100644
--- a/index.html
+++ b/index.html
@@ -7,7 +7,7 @@
name="description"
content="amerc is an agent mercenary layer for embedding, bringing, and hosting agents across vertical software boundaries."
/>
-
+
diff --git a/package.json b/package.json
index 61e10b2..e6c414d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "amerc-site",
- "version": "0.31.0-activity",
+ "version": "0.32.0-toasts",
"private": true,
"type": "module",
"scripts": {
diff --git a/src/AgentPlatform.jsx b/src/AgentPlatform.jsx
index ececd17..c475fdc 100644
--- a/src/AgentPlatform.jsx
+++ b/src/AgentPlatform.jsx
@@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react';
import { api } from './api.js';
+import { copyToast } from './toast.js';
const STATUS_COLOR = { online: '#36f0b0', pending: '#f2b85f', lost: '#ff9f5a', down: '#ff7a8c' };
const TAG_EMOJI = { backend: '๐ ๏ธ', model: '๐ง ', frontend: '๐จ', ui: '๐๏ธ', web: '๐', data: '๐', devops: 'โ๏ธ', ml: '๐ค', security: '๐', api: '๐', bot: '๐ค', chat: '๐ฌ', test: '๐งช', docs: '๐', design: 'โ๏ธ', ops: '๐ฆ', research: '๐ฌ' };
@@ -92,7 +93,7 @@ function ClassModal({ id, auth, onClose }) {
{err &&
{err}
}
{auth.user ? : Log in to subscribe.}
- {sub && navigator.clipboard?.writeText(sub)}>{sub} โง}
+ {sub && copyToast(sub)}>{sub} โง}
Instances
@@ -178,7 +179,7 @@ function KeysCard() {
setName(e.target.value)} required />
- {created &&
โ
minted โ copy now, shown once:
navigator.clipboard?.writeText(created.key)}>{created.key} โง}
+ {created &&
โ
minted โ copy now, shown once:
copyToast(created.key)}>{created.key} โง}
{err &&
{err}
}
{keys.map((k) => (
@@ -257,7 +258,7 @@ export function BoothDashboard({ auth, setRoute }) {
{insts.map((i) => (
#{i.id} {i.status}
- {i.accesskey && navigator.clipboard?.writeText(i.accesskey)}>{i.accesskey.slice(0, 14)}โฆ โง}
+ {i.accesskey && copyToast(i.accesskey)}>{i.accesskey.slice(0, 14)}โฆ โง}
))}
@@ -270,8 +271,8 @@ export function BoothDashboard({ auth, setRoute }) {
e.stopPropagation()}>
Instance #{newInst.id} created
Run your broker against this instance, then it shows online. The accesskey is the relay token.
-
-
+
+
diff --git a/src/Mansion.jsx b/src/Mansion.jsx
index 2e66a85..9107917 100644
--- a/src/Mansion.jsx
+++ b/src/Mansion.jsx
@@ -1,5 +1,6 @@
import React, { useCallback, useEffect, useState } from 'react';
import { api } from './api.js';
+import { copyToast } from './toast.js';
// amerc Mansion โ a hub of amerc services. First service: Showcase (reverse proxy).
export default function Mansion({ auth, setRoute }) {
@@ -33,7 +34,7 @@ function Showcase({ handle }) {
catch (e2) { setErr(e2.message); }
};
const del = async (id) => { if (!window.confirm('Delete this showcase?')) return; try { await api(`/showcase/${id}`, { method: 'DELETE' }); load(); } catch (e2) { setErr(e2.message); } };
- const copy = (t) => navigator.clipboard?.writeText(t);
+ const copy = (t) => copyToast(t);
return (
diff --git a/src/Scene2D.jsx b/src/Scene2D.jsx
index a70b063..7bc70b3 100644
--- a/src/Scene2D.jsx
+++ b/src/Scene2D.jsx
@@ -6,7 +6,7 @@ import Mansion from './Mansion.jsx';
import TavernGame from './TavernGame.jsx';
import { api } from './api.js';
-const RELEASE = '0.31.0-activity';
+const RELEASE = '0.32.0-toasts';
const NAV = [
{ id: 'home', label: 'Tavern' },
diff --git a/src/styles.css b/src/styles.css
index 2883040..f496a03 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1146,3 +1146,9 @@ button {
.act-ico { font-size: 16px; flex: none; }
.act-text { font-size: 13px; color: #c9b8e6; flex: 1; }
.act-time { font-size: 11px; color: #6f5b8c; flex: none; }
+
+/* toasts (0.32) */
+#amerc-toasts { position: fixed; bottom: 20px; right: 20px; z-index: 99999; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
+.amerc-toast { background: #142238; color: #eaf2ff; border: 1px solid #2e4a6e; border-left: 3px solid #36f0b0; border-radius: 9px; padding: 11px 16px; font-family: Inter, sans-serif; font-size: 13px; box-shadow: 0 10px 28px rgba(0,0,0,0.55); opacity: 0; transform: translateX(24px); transition: opacity .25s ease, transform .25s ease; max-width: 320px; }
+.amerc-toast.in { opacity: 1; transform: none; }
+.amerc-toast.t-err { border-left-color: #ff7a8c; }
diff --git a/src/toast.js b/src/toast.js
new file mode 100644
index 0000000..f001f6c
--- /dev/null
+++ b/src/toast.js
@@ -0,0 +1,16 @@
+// Tiny dependency-free toast notifications, callable from anywhere.
+export function toast(msg, type = 'ok', ms = 2600) {
+ let c = document.getElementById('amerc-toasts');
+ if (!c) { c = document.createElement('div'); c.id = 'amerc-toasts'; document.body.appendChild(c); }
+ const t = document.createElement('div');
+ t.className = `amerc-toast t-${type}`;
+ t.textContent = msg;
+ c.appendChild(t);
+ requestAnimationFrame(() => t.classList.add('in'));
+ setTimeout(() => { t.classList.remove('in'); setTimeout(() => t.remove(), 300); }, ms);
+}
+
+export function copyToast(text, label = 'Copied') {
+ try { navigator.clipboard.writeText(text).then(() => toast(`${label} โ`)).catch(() => toast('Copy failed', 'err')); }
+ catch { toast('Copy failed', 'err'); }
+}