mnfst 0.5.166 → 0.5.168
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/lib/manifest.appwrite.auth.js +83 -19
- package/lib/manifest.chat.js +173 -10
- package/lib/manifest.code.css +9 -2
- package/lib/manifest.code.min.css +1 -1
- package/lib/manifest.combobox.css +18 -1
- package/lib/manifest.css +349 -9
- package/lib/manifest.form.css +19 -6
- package/lib/manifest.input.css +101 -2
- package/lib/manifest.integrity.json +3 -3
- package/lib/manifest.min.css +1 -1
- package/lib/manifest.tooltips.js +23 -0
- package/package.json +2 -2
|
@@ -3215,29 +3215,50 @@ function mergeRoles(manifestRoles, userGeneratedRoles) {
|
|
|
3215
3215
|
return merged;
|
|
3216
3216
|
}
|
|
3217
3217
|
|
|
3218
|
-
//
|
|
3218
|
+
// Appwrite membership role tokens allow only [a-zA-Z0-9._-]. Role definitions are
|
|
3219
|
+
// keyed by display name (which may contain spaces/unicode), so we store an
|
|
3220
|
+
// Appwrite-safe slug on the membership and resolve by matching slug(token) against
|
|
3221
|
+
// slug(defName). Idempotent, and "owner" (Appwrite's intrinsic role) passes through.
|
|
3222
|
+
function roleSlug(name) {
|
|
3223
|
+
if (name === 'owner') return 'owner';
|
|
3224
|
+
return String(name)
|
|
3225
|
+
.trim()
|
|
3226
|
+
.toLowerCase()
|
|
3227
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
3228
|
+
.replace(/^-+|-+$/g, '');
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
// Normalize custom roles for Appwrite: slugify tokens (so space/unicode names stay
|
|
3232
|
+
// assignable) and add "owner" if any role requires it.
|
|
3219
3233
|
function normalizeRolesForAppwrite(customRoles, memberRoles, userGeneratedRoles = null) {
|
|
3220
3234
|
if (!Array.isArray(customRoles)) {
|
|
3221
3235
|
return customRoles;
|
|
3222
3236
|
}
|
|
3223
3237
|
|
|
3238
|
+
const slugged = customRoles.map(role => roleSlug(role));
|
|
3239
|
+
|
|
3224
3240
|
// Merge manifest and user-generated roles
|
|
3225
3241
|
const allRoles = mergeRoles(memberRoles, userGeneratedRoles);
|
|
3226
3242
|
|
|
3227
|
-
// If no roles config, return
|
|
3243
|
+
// If no roles config, return slugged tokens (Appwrite handles owner default)
|
|
3228
3244
|
if (!allRoles || Object.keys(allRoles).length === 0) {
|
|
3229
|
-
return
|
|
3245
|
+
return slugged;
|
|
3230
3246
|
}
|
|
3231
3247
|
|
|
3232
|
-
//
|
|
3233
|
-
|
|
3248
|
+
// Which definition slugs require owner — checked by slug so this works whether the
|
|
3249
|
+
// incoming tokens are display names or already slugged.
|
|
3250
|
+
const ownerSlugs = new Set();
|
|
3251
|
+
for (const name of Object.keys(allRoles)) {
|
|
3252
|
+
if (roleRequiresOwner(name, allRoles)) ownerSlugs.add(roleSlug(name));
|
|
3253
|
+
}
|
|
3254
|
+
const requiresOwner = slugged.some(s => ownerSlugs.has(s));
|
|
3234
3255
|
|
|
3235
3256
|
// If owner is already in the list, don't duplicate
|
|
3236
|
-
if (requiresOwner && !
|
|
3237
|
-
return [...
|
|
3257
|
+
if (requiresOwner && !slugged.includes('owner')) {
|
|
3258
|
+
return [...slugged, 'owner'];
|
|
3238
3259
|
}
|
|
3239
3260
|
|
|
3240
|
-
return
|
|
3261
|
+
return slugged;
|
|
3241
3262
|
}
|
|
3242
3263
|
|
|
3243
3264
|
// Normalize Appwrite roles for display (filter "owner" if a custom role replaces it)
|
|
@@ -3249,10 +3270,15 @@ function normalizeRolesForDisplay(appwriteRoles, memberRoles, userGeneratedRoles
|
|
|
3249
3270
|
// Merge manifest and user-generated roles
|
|
3250
3271
|
const allRoles = mergeRoles(memberRoles, userGeneratedRoles);
|
|
3251
3272
|
|
|
3252
|
-
// If custom roles are defined,
|
|
3253
|
-
//
|
|
3273
|
+
// If custom roles are defined, filter out "owner" (a background Appwrite role) and
|
|
3274
|
+
// translate slug tokens back to their display names (legacy exact-name tokens map
|
|
3275
|
+
// through slug() too; unknown tokens pass through as-is).
|
|
3254
3276
|
if (allRoles && Object.keys(allRoles).length > 0) {
|
|
3255
|
-
|
|
3277
|
+
const bySlug = {};
|
|
3278
|
+
for (const name of Object.keys(allRoles)) bySlug[roleSlug(name)] = name;
|
|
3279
|
+
return appwriteRoles
|
|
3280
|
+
.filter(role => role !== 'owner')
|
|
3281
|
+
.map(role => bySlug[roleSlug(role)] || role);
|
|
3256
3282
|
}
|
|
3257
3283
|
|
|
3258
3284
|
// If no custom roles config, show "owner" as-is (legacy behavior)
|
|
@@ -3303,9 +3329,13 @@ function hasPermission(userRoles, permission, memberRoles, userGeneratedRoles =
|
|
|
3303
3329
|
return true;
|
|
3304
3330
|
}
|
|
3305
3331
|
|
|
3306
|
-
// Check if any of the user's custom roles has this permission
|
|
3332
|
+
// Check if any of the user's custom roles has this permission. Match by slug so
|
|
3333
|
+
// display-name definitions resolve against slugged membership tokens, and legacy
|
|
3334
|
+
// exact-name tokens still resolve.
|
|
3335
|
+
const bySlug = {};
|
|
3336
|
+
for (const [name, perms] of Object.entries(allRoles)) bySlug[roleSlug(name)] = perms;
|
|
3307
3337
|
for (const roleName of customRoles) {
|
|
3308
|
-
const rolePermissions =
|
|
3338
|
+
const rolePermissions = bySlug[roleSlug(roleName)];
|
|
3309
3339
|
if (rolePermissions && Array.isArray(rolePermissions) && rolePermissions.includes(permission)) {
|
|
3310
3340
|
return true;
|
|
3311
3341
|
}
|
|
@@ -3360,6 +3390,10 @@ function initializeTeamsRoles() {
|
|
|
3360
3390
|
return getOwnerPermissions();
|
|
3361
3391
|
};
|
|
3362
3392
|
|
|
3393
|
+
store.roleSlug = function (name) {
|
|
3394
|
+
return roleSlug(name);
|
|
3395
|
+
};
|
|
3396
|
+
|
|
3363
3397
|
store.validateRoleConfig = async function () {
|
|
3364
3398
|
const appwriteConfig = await config.getAppwriteConfig();
|
|
3365
3399
|
const memberRoles = appwriteConfig?.memberRoles || null;
|
|
@@ -3532,6 +3566,7 @@ window.ManifestAppwriteAuthTeamsRoles = {
|
|
|
3532
3566
|
roleHasAllOwnerPermissions,
|
|
3533
3567
|
getUserGeneratedRoles,
|
|
3534
3568
|
mergeRoles,
|
|
3569
|
+
roleSlug,
|
|
3535
3570
|
normalizeRolesForAppwrite,
|
|
3536
3571
|
normalizeRolesForDisplay,
|
|
3537
3572
|
getPrimaryDisplayRole,
|
|
@@ -4218,7 +4253,13 @@ function initializeTeamsMembers() {
|
|
|
4218
4253
|
|
|
4219
4254
|
const result = await this._appwrite.teams.createMembership(membershipParams);
|
|
4220
4255
|
|
|
4221
|
-
|
|
4256
|
+
// Surface the requested vs. stored tokens. They diverge by design —
|
|
4257
|
+
// role names are slugified for Appwrite, and owner-level roles carry the
|
|
4258
|
+
// "owner" token — so `normalized: true` signals an intentional transform,
|
|
4259
|
+
// not a failed write.
|
|
4260
|
+
const normalized = !(rolesArray.length === normalizedRoles.length
|
|
4261
|
+
&& rolesArray.every((r, i) => r === normalizedRoles[i]));
|
|
4262
|
+
return { success: true, membership: result, requestedRoles: rolesArray, normalizedRoles, normalized };
|
|
4222
4263
|
} catch (error) {
|
|
4223
4264
|
this.error = error.message;
|
|
4224
4265
|
return { success: false, error: error.message };
|
|
@@ -4475,7 +4516,13 @@ function initializeTeamsMembers() {
|
|
|
4475
4516
|
await this.refreshPermissionCache();
|
|
4476
4517
|
}
|
|
4477
4518
|
|
|
4478
|
-
|
|
4519
|
+
// `normalized: true` signals the stored tokens intentionally differ from
|
|
4520
|
+
// the requested roles (slugified names, and an appended "owner" token for
|
|
4521
|
+
// owner-level roles) — a by-design transform, not a failed write.
|
|
4522
|
+
const normalized = !(Array.isArray(roles) && Array.isArray(normalizedRoles)
|
|
4523
|
+
&& roles.length === normalizedRoles.length
|
|
4524
|
+
&& roles.every((r, i) => r === normalizedRoles[i]));
|
|
4525
|
+
return { success: true, membership: result, requestedRoles: roles, normalizedRoles, normalized };
|
|
4479
4526
|
} catch (error) {
|
|
4480
4527
|
// Revert optimistic update on error
|
|
4481
4528
|
if (this.currentTeam && this.currentTeam.$id === teamId && this.listMemberships) {
|
|
@@ -5446,7 +5493,19 @@ function initializeTeamsConvenience() {
|
|
|
5446
5493
|
const userMembership = this.currentTeamMemberships.find(
|
|
5447
5494
|
m => m.userId === this.user.$id
|
|
5448
5495
|
);
|
|
5449
|
-
|
|
5496
|
+
const raw = userMembership?.roles || [];
|
|
5497
|
+
// Membership tokens are Appwrite-safe slugs; translate them back to the
|
|
5498
|
+
// author's display names using the cached role map. "owner" and unknown
|
|
5499
|
+
// tokens pass through unchanged.
|
|
5500
|
+
const slug = this.roleSlug;
|
|
5501
|
+
const allRoles = (this.allTeamRoles && this.allTeamRoles(this.currentTeam)) || {};
|
|
5502
|
+
const keys = Object.keys(allRoles);
|
|
5503
|
+
if (typeof slug !== 'function' || !keys.length) {
|
|
5504
|
+
return raw;
|
|
5505
|
+
}
|
|
5506
|
+
const bySlug = {};
|
|
5507
|
+
for (const name of keys) bySlug[slug(name)] = name;
|
|
5508
|
+
return raw.map(r => (r === 'owner' ? 'owner' : (bySlug[slug(r)] || r)));
|
|
5450
5509
|
};
|
|
5451
5510
|
|
|
5452
5511
|
// Check if current user has a specific permission in the current team
|
|
@@ -5494,9 +5553,13 @@ function initializeTeamsConvenience() {
|
|
|
5494
5553
|
}
|
|
5495
5554
|
|
|
5496
5555
|
// Granted if any of the user's custom roles includes this permission
|
|
5497
|
-
// (built-in or custom key).
|
|
5556
|
+
// (built-in or custom key). Match by slug so slugged/legacy membership
|
|
5557
|
+
// tokens resolve against display-name definitions.
|
|
5558
|
+
const slug = this.roleSlug || (x => x);
|
|
5559
|
+
const bySlug = {};
|
|
5560
|
+
for (const [name, perms] of Object.entries(allRoles)) bySlug[slug(name)] = perms;
|
|
5498
5561
|
for (const roleName of customRoles) {
|
|
5499
|
-
const rolePermissions =
|
|
5562
|
+
const rolePermissions = bySlug[slug(roleName)];
|
|
5500
5563
|
if (Array.isArray(rolePermissions) && rolePermissions.includes(permission)) {
|
|
5501
5564
|
return true;
|
|
5502
5565
|
}
|
|
@@ -5510,7 +5573,8 @@ function initializeTeamsConvenience() {
|
|
|
5510
5573
|
return false;
|
|
5511
5574
|
}
|
|
5512
5575
|
const userRoles = this.getCurrentTeamRoles();
|
|
5513
|
-
|
|
5576
|
+
const slug = this.roleSlug || (x => x);
|
|
5577
|
+
return userRoles.some(r => slug(r) === slug(roleName));
|
|
5514
5578
|
};
|
|
5515
5579
|
|
|
5516
5580
|
// Get current user's primary role in current team
|
package/lib/manifest.chat.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* https://manifestx.dev
|
|
4
4
|
/*
|
|
5
5
|
/* Handle = reactive conversation view fed by an adapter; drives intents. The
|
|
6
|
-
/* plugin transports/stores nothing — see
|
|
6
|
+
/* plugin transports/stores nothing — see templates/chat-adapter/README.md.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
(function () {
|
|
@@ -287,8 +287,11 @@
|
|
|
287
287
|
function mk(cid, channel, parts, msgs, closed) {
|
|
288
288
|
convs.set(cid, { id: cid, channel, closed: !!closed, participants: parts, messages: msgs });
|
|
289
289
|
}
|
|
290
|
-
const m = (cid, author, text, minsAgo, extra) =>
|
|
291
|
-
Object.assign({ id: id('m'), conversationId: cid, author, body: { text }, ts: t(minsAgo), status: 'delivered' }, extra || {});
|
|
290
|
+
const m = (cid, author, text, minsAgo, extra) => {
|
|
291
|
+
const msg = Object.assign({ id: id('m'), conversationId: cid, author, body: { text }, ts: t(minsAgo), status: 'delivered' }, extra || {});
|
|
292
|
+
if (msg.media) { msg.body.media = msg.media; delete msg.media; } // media lives on body
|
|
293
|
+
return msg;
|
|
294
|
+
};
|
|
292
295
|
|
|
293
296
|
// 1:1 AI co-pilot
|
|
294
297
|
mk('dm-ai', 'webchat', [me, bot], [
|
|
@@ -296,6 +299,26 @@
|
|
|
296
299
|
m('dm-ai', me, 'How many free credits do I get?', 11)
|
|
297
300
|
]);
|
|
298
301
|
|
|
302
|
+
// Attachment showcase — one of every media kind, both directions
|
|
303
|
+
// (harness-only conversation; asset paths resolve in the test project)
|
|
304
|
+
mk('media-1', 'webchat', [me, bot], [
|
|
305
|
+
m('media-1', me, 'Here is the artwork and the brief.', 22, {
|
|
306
|
+
media: [
|
|
307
|
+
{ kind: 'image', url: '/test/media/sample.png', name: 'artwork.png', mediaType: 'image/png' },
|
|
308
|
+
{ kind: 'document', url: '/test/media/sample.pdf', name: 'brief.pdf', mediaType: 'application/pdf' }
|
|
309
|
+
]
|
|
310
|
+
}),
|
|
311
|
+
m('media-1', bot, 'Received — and here is everything back in every format:', 20, {
|
|
312
|
+
media: [
|
|
313
|
+
{ kind: 'image', url: '/test/media/sample.png', name: 'render.png', mediaType: 'image/png' },
|
|
314
|
+
{ kind: 'audio', url: '/test/media/sample.wav', name: 'jingle.wav', mediaType: 'audio/wav' },
|
|
315
|
+
{ kind: 'voice', url: '/test/media/sample.wav', name: 'voice note', mediaType: 'audio/wav' },
|
|
316
|
+
{ kind: 'video', url: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4', name: 'clip.mp4', mediaType: 'video/mp4' },
|
|
317
|
+
{ kind: 'document', url: '/test/media/sample.pdf', name: 'summary.pdf', mediaType: 'application/pdf' }
|
|
318
|
+
]
|
|
319
|
+
})
|
|
320
|
+
]);
|
|
321
|
+
|
|
299
322
|
// group with reactions + a small reply tree
|
|
300
323
|
const g1 = m('grp-1', ana, 'Ship the v2 doc today?', 30);
|
|
301
324
|
mk('grp-1', 'webchat', [me, ana, bo], [
|
|
@@ -378,7 +401,20 @@
|
|
|
378
401
|
setTimeout(() => deliver(target, msg), 60); // server echo (reconciles media/status by id)
|
|
379
402
|
return { id: msg.id, ts: msg.ts, conversationId: target.id };
|
|
380
403
|
},
|
|
381
|
-
async react(cid, mid, emoji) {
|
|
404
|
+
async react(cid, mid, emoji) {
|
|
405
|
+
// toggle: off if I reacted, join if others did, add if new
|
|
406
|
+
const c = backend.convs.get(cid); const msg = c && c.messages.find(x => x.id === mid);
|
|
407
|
+
if (msg) {
|
|
408
|
+
const rs = (msg.reactions || []).map(r => Object.assign({}, r));
|
|
409
|
+
const r = rs.find(x => x.emoji === emoji);
|
|
410
|
+
if (r && r.byMe) { r.count--; r.byMe = false; }
|
|
411
|
+
else if (r) { r.count++; r.byMe = true; }
|
|
412
|
+
else rs.push({ emoji, count: 1, byMe: true });
|
|
413
|
+
msg.reactions = rs.filter(x => x.count > 0);
|
|
414
|
+
emit(cid, h => h.onReaction && h.onReaction(mid, msg.reactions));
|
|
415
|
+
}
|
|
416
|
+
return { ok: true };
|
|
417
|
+
},
|
|
382
418
|
async addParticipant(cid, p) { const c = backend.convs.get(cid); if (c && !c.participants.some(x => x.id === p.id)) { c.participants.push(p); emit(cid, h => h.onParticipant && h.onParticipant(p, 'added')); } return { ok: true }; },
|
|
383
419
|
async transfer(cid, from, to, role) { emit(cid, h => h.onParticipant && h.onParticipant({ id: to, role: role || 'assignee' }, 'changed')); return { ok: true }; },
|
|
384
420
|
async setTyping(cid, on) { emit(cid, h => h.onTyping && h.onTyping(backend.me.id, on)); },
|
|
@@ -413,11 +449,11 @@
|
|
|
413
449
|
|
|
414
450
|
// ---- simulation hooks (button-driven; deterministic for verification) ---
|
|
415
451
|
const sim = {
|
|
416
|
-
// stream an AI reply token-by-token into a conversation
|
|
417
|
-
aiReply(cid, text) {
|
|
452
|
+
// stream an AI reply token-by-token into a conversation (media attaches on completion)
|
|
453
|
+
aiReply(cid, text, media) {
|
|
418
454
|
const c = backend.convs.get(cid); if (!c) return;
|
|
419
455
|
const mid = backend.id('m');
|
|
420
|
-
const msg = { id: mid, conversationId: cid, author: backend.bot, body: { text: '' }, ts: backend.t(0), status: 'streaming', meta: { authoredBy: 'u_me' } };
|
|
456
|
+
const msg = { id: mid, conversationId: cid, author: backend.bot, body: { text: '', media: media || undefined }, ts: backend.t(0), status: 'streaming', meta: { authoredBy: 'u_me' } };
|
|
421
457
|
c.messages.push(msg);
|
|
422
458
|
emit(cid, h => h.onMessage && h.onMessage(msg));
|
|
423
459
|
const words = (text || 'Every account starts with 5,000 free credits each month.').split(' ');
|
|
@@ -482,7 +518,8 @@
|
|
|
482
518
|
// Same-origin relay mnfst-run serves for an `ai` block; override via
|
|
483
519
|
// opts.endpoint / window.CHAT_LLM_ENDPOINT.
|
|
484
520
|
const endpoint = opts.endpoint || window.CHAT_LLM_ENDPOINT || '/_ai/chat';
|
|
485
|
-
|
|
521
|
+
// only when set — the relay's ai block (system + grounding) is the default
|
|
522
|
+
const system = opts.system || undefined;
|
|
486
523
|
const handlers = {}; // conversationId -> subscribe handlers
|
|
487
524
|
let seq = 0;
|
|
488
525
|
const id = (p) => p + '_' + Date.now().toString(36) + '_' + (++seq);
|
|
@@ -498,12 +535,15 @@
|
|
|
498
535
|
const toMsg = (r) => ({ id: r.id, conversationId: null, author: r.role === 'assistant' ? BOT : USER, body: { text: r.text }, ts: r.ts, status: 'delivered' });
|
|
499
536
|
|
|
500
537
|
// Build the Anthropic messages array; attachments → image/document blocks.
|
|
538
|
+
// Only what the API accepts is forwarded (images + PDFs with data);
|
|
539
|
+
// audio/video/voice render locally but don't reach the model.
|
|
501
540
|
function apiMessages(cid, draft) {
|
|
502
541
|
const hist = loadStore(cid).map(r => ({ role: r.role, content: r.text }));
|
|
503
|
-
const media = (draft.body && draft.body.media) || []
|
|
542
|
+
const media = ((draft.body && draft.body.media) || []).filter(a =>
|
|
543
|
+
a.data && (a.kind === 'image' || a.mediaType === 'application/pdf'));
|
|
504
544
|
const blocks = media.map(a => a.kind === 'image'
|
|
505
545
|
? { type: 'image', source: { type: 'base64', media_type: a.mediaType, data: a.data } }
|
|
506
|
-
: { type: 'document', source: { type: 'base64', media_type:
|
|
546
|
+
: { type: 'document', source: { type: 'base64', media_type: 'application/pdf', data: a.data } });
|
|
507
547
|
const text = (draft.body && draft.body.text) || draft.text || '';
|
|
508
548
|
const last = blocks.length ? { role: 'user', content: [...blocks, { type: 'text', text }] } : { role: 'user', content: text };
|
|
509
549
|
return [...hist, last];
|
|
@@ -555,6 +595,129 @@
|
|
|
555
595
|
})();
|
|
556
596
|
|
|
557
597
|
|
|
598
|
+
/* Manifest Chat — Appwrite adapter (conversations as app data)
|
|
599
|
+
* By Andrew Matlock under MIT license
|
|
600
|
+
* https://manifestx.dev
|
|
601
|
+
*
|
|
602
|
+
* Messages live as rows in an Appwrite table; inbound arrives over Appwrite
|
|
603
|
+
* Realtime; identity comes from $auth (guest sessions cover anonymous use).
|
|
604
|
+
* Built for comments, support threads, and small-group chat — high-volume
|
|
605
|
+
* messaging belongs on a purpose-built bus behind a custom adapter.
|
|
606
|
+
*
|
|
607
|
+
* Config: opts { databaseId, tableId, ttlHours } or manifest.json
|
|
608
|
+
* chat: { appwriteDatabaseId, appwriteTableId, ttlHours }.
|
|
609
|
+
* Table columns: conversationId (indexed) · text · authorId · authorName ·
|
|
610
|
+
* authorColor? · replyTo? — ts/id come from $createdAt/$id.
|
|
611
|
+
*/
|
|
612
|
+
|
|
613
|
+
(function () {
|
|
614
|
+
'use strict';
|
|
615
|
+
|
|
616
|
+
function ready(fn) {
|
|
617
|
+
if (window.ManifestChatAdapters) return fn();
|
|
618
|
+
const t = setInterval(() => { if (window.ManifestChatAdapters) { clearInterval(t); fn(); } }, 20);
|
|
619
|
+
setTimeout(() => clearInterval(t), 5000);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
ready(function () {
|
|
623
|
+
function hashColor(id) {
|
|
624
|
+
let h = 0; for (const ch of String(id)) h = (h * 31 + ch.charCodeAt(0)) >>> 0;
|
|
625
|
+
return `hsl(${h % 360} 60% 45%)`;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function appwriteAdapter(opts) {
|
|
629
|
+
opts = opts || {};
|
|
630
|
+
let cfg = null;
|
|
631
|
+
|
|
632
|
+
async function config() {
|
|
633
|
+
if (cfg) return cfg;
|
|
634
|
+
let databaseId = opts.databaseId, tableId = opts.tableId, ttlHours = opts.ttlHours;
|
|
635
|
+
if ((!databaseId || !tableId) && window.ManifestDataConfig && window.ManifestDataConfig.ensureManifest) {
|
|
636
|
+
const m = await window.ManifestDataConfig.ensureManifest();
|
|
637
|
+
const c = (m && m.chat) || {};
|
|
638
|
+
databaseId = databaseId || c.appwriteDatabaseId;
|
|
639
|
+
tableId = tableId || c.appwriteTableId;
|
|
640
|
+
if (ttlHours == null) ttlHours = c.ttlHours;
|
|
641
|
+
}
|
|
642
|
+
if (!databaseId || !tableId) console.warn('[Manifest Chat] appwrite adapter needs databaseId + tableId (opts or manifest.json chat block).');
|
|
643
|
+
cfg = { databaseId, tableId, ttlHours };
|
|
644
|
+
return cfg;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function me() {
|
|
648
|
+
const auth = window.Alpine ? window.Alpine.store('auth') : null;
|
|
649
|
+
const u = auth && auth.user;
|
|
650
|
+
if (u && u.$id) return { id: u.$id, kind: 'human', displayName: u.name || u.email || 'Guest', color: hashColor(u.$id) };
|
|
651
|
+
let gid = null;
|
|
652
|
+
try { gid = localStorage.getItem('mnfst.chat.gid'); if (!gid) { gid = 'g_' + Math.random().toString(36).slice(2, 10); localStorage.setItem('mnfst.chat.gid', gid); } } catch (_) { gid = 'g_anon'; }
|
|
653
|
+
return { id: gid, kind: 'human', displayName: 'Guest', color: hashColor(gid) };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function toMsg(row) {
|
|
657
|
+
return {
|
|
658
|
+
id: row.$id, conversationId: row.conversationId,
|
|
659
|
+
author: { id: row.authorId, kind: 'human', displayName: row.authorName, color: row.authorColor || hashColor(row.authorId) },
|
|
660
|
+
body: { text: row.text }, replyTo: row.replyTo || undefined,
|
|
661
|
+
ts: row.$createdAt, status: 'delivered'
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
identity: () => me(),
|
|
667
|
+
|
|
668
|
+
async load(cid) {
|
|
669
|
+
const { databaseId, tableId, ttlHours } = await config();
|
|
670
|
+
if (!databaseId) return { messages: [], participants: [] };
|
|
671
|
+
// tablesDB directly (not loadTableRows): public read("any") tables
|
|
672
|
+
// must load before any session exists — no auth gate on reads.
|
|
673
|
+
const services = await window.ManifestDataAppwrite.getAppwriteDataServices();
|
|
674
|
+
const Q = window.Appwrite.Query;
|
|
675
|
+
const queries = [Q.equal('conversationId', cid), Q.orderDesc('$createdAt'), Q.limit(100)];
|
|
676
|
+
if (ttlHours) queries.push(Q.greaterThan('$createdAt', new Date(Date.now() - ttlHours * 3600e3).toISOString()));
|
|
677
|
+
const res = await services.tablesDB.listRows({ databaseId, tableId, queries });
|
|
678
|
+
return { messages: res.rows.map(toMsg).reverse(), participants: [] };
|
|
679
|
+
},
|
|
680
|
+
|
|
681
|
+
subscribe(cid, handlers) {
|
|
682
|
+
let unsub = null, closed = false;
|
|
683
|
+
(async () => {
|
|
684
|
+
const { databaseId, tableId } = await config();
|
|
685
|
+
if (!databaseId) return;
|
|
686
|
+
const services = await window.ManifestDataAppwrite.getAppwriteDataServices();
|
|
687
|
+
if (!services || !services.realtime || closed) return;
|
|
688
|
+
unsub = services.realtime.subscribe(`databases.${databaseId}.tables.${tableId}.rows`, (res) => {
|
|
689
|
+
if (!res || !res.payload || res.payload.conversationId !== cid) return;
|
|
690
|
+
const events = Array.isArray(res.events) ? res.events : [res.events];
|
|
691
|
+
if (events.some(e => typeof e === 'string' && e.endsWith('.create'))) handlers.onMessage(toMsg(res.payload));
|
|
692
|
+
});
|
|
693
|
+
if (handlers.onConnection) handlers.onConnection(true);
|
|
694
|
+
})();
|
|
695
|
+
return () => { closed = true; try { unsub && unsub(); } catch (_) { } };
|
|
696
|
+
},
|
|
697
|
+
|
|
698
|
+
async send(cid, draft) {
|
|
699
|
+
const { databaseId, tableId } = await config();
|
|
700
|
+
const auth = window.Alpine ? window.Alpine.store('auth') : null;
|
|
701
|
+
if (auth && !auth.isAuthenticated && typeof auth.requestGuest === 'function') {
|
|
702
|
+
try { await auth.requestGuest(); } catch (_) { } // guests may create
|
|
703
|
+
}
|
|
704
|
+
const who = me();
|
|
705
|
+
const text = (draft.body && draft.body.text) || draft.text || '';
|
|
706
|
+
const row = await window.ManifestDataAppwrite.createRow(databaseId, tableId, {
|
|
707
|
+
conversationId: cid, text,
|
|
708
|
+
authorId: who.id, authorName: who.displayName, authorColor: who.color,
|
|
709
|
+
replyTo: draft.replyTo || null
|
|
710
|
+
});
|
|
711
|
+
return { id: row.$id, ts: row.$createdAt };
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
window.ManifestChatAdapters.register('appwrite', appwriteAdapter);
|
|
717
|
+
});
|
|
718
|
+
})();
|
|
719
|
+
|
|
720
|
+
|
|
558
721
|
/* Manifest Chat — magic + init
|
|
559
722
|
/* By Andrew Matlock under MIT license
|
|
560
723
|
/* https://manifestx.dev
|
package/lib/manifest.code.css
CHANGED
|
@@ -220,13 +220,20 @@
|
|
|
220
220
|
|
|
221
221
|
:where(.code-copied-icon) {
|
|
222
222
|
display: inline-block;
|
|
223
|
+
vertical-align: middle;
|
|
223
224
|
width: 1em;
|
|
224
225
|
height: 1em;
|
|
225
226
|
background-color: currentColor;
|
|
226
227
|
mask-image: var(--icon-code-copied);
|
|
227
|
-
mask-size:
|
|
228
|
+
mask-size: 1em;
|
|
228
229
|
mask-repeat: no-repeat;
|
|
229
|
-
mask-position: center
|
|
230
|
+
mask-position: center;
|
|
231
|
+
|
|
232
|
+
/* Fill the line box so the mask centers optically */
|
|
233
|
+
@supports (height: 1lh) {
|
|
234
|
+
height: 1lh;
|
|
235
|
+
vertical-align: top
|
|
236
|
+
}
|
|
230
237
|
}
|
|
231
238
|
|
|
232
239
|
/* Pre code blocks (individual or tab grouped) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");:root{--icon-code-copy:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");--icon-code-copied:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1jb3B5LWNoZWNrLWljb24gbHVjaWRlLWNvcHktY2hlY2siIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTEyIDE1IDIgMiA0LTQiLz48cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIvPjxwYXRoIGQ9Ik00IDE2Yy0xLjEgMC0yLS45LTItMlY0YzAtMS4xLjktMiAyLTJoMTBjMS4xIDAgMiAuOSAyIDIiLz48L3N2Zz4=");--icon-code-expand:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--color-code-keyword:#b8860b;--color-code-string:#8b4513;--color-code-comment:gray;--color-code-function:peru;--color-code-number:sienna;--color-code-operator:#2f4f4f;--color-code-class-name:#daa520;--color-code-tag:#4682b4;--color-code-attr-name:#ff8c00;--color-code-attr-value:#8b4513;--color-code-property:sienna;--color-code-selector:#4682b4;--color-code-punctuation:#2f4f4f;--color-code-builtin:#b8860b;--color-code-constant:sienna;--color-code-boolean:sienna;--color-code-regex:#8b4513;--color-code-symbol:#daa520;--color-code-entity:#daa520;--color-code-url:sienna;--color-code-atrule:#b8860b;--color-code-rule:#4682b4;--color-code-doctype:gray;--color-code-cdata:gray;--color-code-prolog:gray;--color-code-namespace:gray;--color-code-important:#b8860b;--color-code-inserted:#228b22;--color-code-deleted:#dc143c;--color-code-char:#8b4513}.dark{--color-code-keyword:#f4a460;--color-code-string:#deb887;--color-code-comment:#8b8b8b;--color-code-function:#daa520;--color-code-number:tan;--color-code-operator:wheat;--color-code-class-name:peru;--color-code-tag:#87ceeb;--color-code-attr-name:gold;--color-code-attr-value:#deb887;--color-code-property:tan;--color-code-selector:#87ceeb;--color-code-punctuation:wheat;--color-code-builtin:#f4a460;--color-code-constant:tan;--color-code-boolean:tan;--color-code-regex:#deb887;--color-code-symbol:peru;--color-code-entity:peru;--color-code-url:tan;--color-code-atrule:#f4a460;--color-code-rule:#98fb98;--color-code-doctype:#8b8b8b;--color-code-cdata:#8b8b8b;--color-code-prolog:#8b8b8b;--color-code-namespace:#8b8b8b;--color-code-important:#f4a460;--color-code-inserted:#98fb98;--color-code-deleted:#f08080;--color-code-char:#deb887}@layer utilities{.hljs-comment{color:var(--color-code-comment)!important}.hljs-keyword{color:var(--color-code-keyword)!important}.hljs-string{color:var(--color-code-string)!important}.hljs-number{color:var(--color-code-number)!important}.hljs-literal{color:var(--color-code-constant)!important}.hljs-type{color:var(--color-code-class-name)!important}.hljs-variable{color:var(--color-code-property)!important}.hljs-variable.language_{color:var(--color-code-keyword)!important}.hljs-variable.constant_{color:var(--color-code-constant)!important}.hljs-title{color:var(--color-code-function)!important}.hljs-title.class_.inherited__{color:var(--color-code-class-name)!important}.hljs-title.function_.invoke__{color:var(--color-code-function)!important}.hljs-params{color:var(--color-code-property)!important}.hljs-doctag{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-meta{color:var(--color-code-comment)!important}.hljs-meta.keyword_,.hljs-meta.prompt_{color:var(--color-code-keyword)!important}.hljs-meta.string_{color:var(--color-code-string)!important}.hljs-section{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-name{color:var(--color-code-tag)!important}.hljs-attribute{color:var(--color-code-attr-name)!important}.hljs-bullet{color:var(--color-code-punctuation)!important}.hljs-code{color:var(--color-code-property)!important}.hljs-formula{color:var(--color-code-number)!important}.hljs-quote{color:var(--color-code-string)!important}.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo{color:var(--color-code-selector)!important}.hljs-template-tag{color:var(--color-code-tag)!important}.hljs-template-variable{color:var(--color-code-property)!important}.hljs-subst{color:var(--color-code-string)!important}}@layer components{:where(code[role=button]){height:fit-content}:where(.code-copied-icon){background-color:currentColor;display:inline-block;height:1em;mask-image:var(--icon-code-copied);mask-position:center;mask-repeat:no-repeat;mask-size:
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");:root{--icon-code-copy:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/g%3E%3C/svg%3E");--icon-code-copied:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1jb3B5LWNoZWNrLWljb24gbHVjaWRlLWNvcHktY2hlY2siIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0ibTEyIDE1IDIgMiA0LTQiLz48cmVjdCB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHg9IjgiIHk9IjgiIHJ4PSIyIiByeT0iMiIvPjxwYXRoIGQ9Ik00IDE2Yy0xLjEgMC0yLS45LTItMlY0YzAtMS4xLjktMiAyLTJoMTBjMS4xIDAgMiAuOSAyIDIiLz48L3N2Zz4=");--icon-code-expand:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3E%3C/svg%3E");--color-code-keyword:#b8860b;--color-code-string:#8b4513;--color-code-comment:gray;--color-code-function:peru;--color-code-number:sienna;--color-code-operator:#2f4f4f;--color-code-class-name:#daa520;--color-code-tag:#4682b4;--color-code-attr-name:#ff8c00;--color-code-attr-value:#8b4513;--color-code-property:sienna;--color-code-selector:#4682b4;--color-code-punctuation:#2f4f4f;--color-code-builtin:#b8860b;--color-code-constant:sienna;--color-code-boolean:sienna;--color-code-regex:#8b4513;--color-code-symbol:#daa520;--color-code-entity:#daa520;--color-code-url:sienna;--color-code-atrule:#b8860b;--color-code-rule:#4682b4;--color-code-doctype:gray;--color-code-cdata:gray;--color-code-prolog:gray;--color-code-namespace:gray;--color-code-important:#b8860b;--color-code-inserted:#228b22;--color-code-deleted:#dc143c;--color-code-char:#8b4513}.dark{--color-code-keyword:#f4a460;--color-code-string:#deb887;--color-code-comment:#8b8b8b;--color-code-function:#daa520;--color-code-number:tan;--color-code-operator:wheat;--color-code-class-name:peru;--color-code-tag:#87ceeb;--color-code-attr-name:gold;--color-code-attr-value:#deb887;--color-code-property:tan;--color-code-selector:#87ceeb;--color-code-punctuation:wheat;--color-code-builtin:#f4a460;--color-code-constant:tan;--color-code-boolean:tan;--color-code-regex:#deb887;--color-code-symbol:peru;--color-code-entity:peru;--color-code-url:tan;--color-code-atrule:#f4a460;--color-code-rule:#98fb98;--color-code-doctype:#8b8b8b;--color-code-cdata:#8b8b8b;--color-code-prolog:#8b8b8b;--color-code-namespace:#8b8b8b;--color-code-important:#f4a460;--color-code-inserted:#98fb98;--color-code-deleted:#f08080;--color-code-char:#deb887}@layer utilities{.hljs-comment{color:var(--color-code-comment)!important}.hljs-keyword{color:var(--color-code-keyword)!important}.hljs-string{color:var(--color-code-string)!important}.hljs-number{color:var(--color-code-number)!important}.hljs-literal{color:var(--color-code-constant)!important}.hljs-type{color:var(--color-code-class-name)!important}.hljs-variable{color:var(--color-code-property)!important}.hljs-variable.language_{color:var(--color-code-keyword)!important}.hljs-variable.constant_{color:var(--color-code-constant)!important}.hljs-title{color:var(--color-code-function)!important}.hljs-title.class_.inherited__{color:var(--color-code-class-name)!important}.hljs-title.function_.invoke__{color:var(--color-code-function)!important}.hljs-params{color:var(--color-code-property)!important}.hljs-doctag{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-meta{color:var(--color-code-comment)!important}.hljs-meta.keyword_,.hljs-meta.prompt_{color:var(--color-code-keyword)!important}.hljs-meta.string_{color:var(--color-code-string)!important}.hljs-section{color:var(--color-code-keyword)!important;font-weight:600!important}.hljs-name{color:var(--color-code-tag)!important}.hljs-attribute{color:var(--color-code-attr-name)!important}.hljs-bullet{color:var(--color-code-punctuation)!important}.hljs-code{color:var(--color-code-property)!important}.hljs-formula{color:var(--color-code-number)!important}.hljs-quote{color:var(--color-code-string)!important}.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-selector-pseudo{color:var(--color-code-selector)!important}.hljs-template-tag{color:var(--color-code-tag)!important}.hljs-template-variable{color:var(--color-code-property)!important}.hljs-subst{color:var(--color-code-string)!important}}@layer components{:where(code[role=button]){height:fit-content}:where(.code-copied-icon){background-color:currentColor;display:inline-block;height:1em;mask-image:var(--icon-code-copied);mask-position:center;mask-repeat:no-repeat;mask-size:1em;vertical-align:middle;width:1em;@supports (height:1lh){height:1lh;vertical-align:top}}:where([x-code],[x-code-group]):not(.unstyle){position:relative;:where(header):not(:where(:is(aside.frame) header)){align-items:center;background-color:color-mix(in oklch,var(--color-content-stark,oklch(43.9% 0 0)) 8%,transparent);color:var(--color-content-neutral,oklch(43.9% 0 0));display:flex;flex-direction:row;font-family:var(--font-sans,sans-serif);font-size:inherit;min-height:var(--spacing-field-height,2.25rem);padding-inline-end:var(--spacing-field-height);padding-inline-start:calc(var(--spacing, .25rem)*4);width:100%;&:has(button[role=tab]){padding-inline-start:calc(var(--spacing, .25rem)*2)}& [role=tablist]{display:flex;flex-direction:row;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;&::-webkit-scrollbar{display:none}& button[role=tab]{background:transparent;border:0;color:inherit;flex-shrink:0;font-family:inherit;font-size:inherit;height:fit-content;justify-content:start;&:hover{background-color:var(--color-field-surface,color-mix(oklch(20.5% 0 0) 10%,transparent));color:var(--color-content-stark,oklch(43.9% 0 0))}&[aria-selected=true]{color:var(--color-brand-content,oklch(68.1% .162 75.834));pointer-events:none;position:relative}}}}& button.copy{background-color:transparent;font-size:75%;inset-inline-end:0;position:absolute;top:0;&:hover{background-color:transparent;&:after{background-color:var(--color-field-inverse,oklch(43.9% 0 0))}}&:after{background-color:var(--color-content-neutral,oklch(43.9% 0 0));content:"";display:block;height:.8125rem;mask-image:var(--icon-code-copy);mask-repeat:no-repeat;mask-size:contain;width:.8125rem}&.copied:after{mask-image:var(--icon-code-copied)}}:where(header)::-webkit-scrollbar{display:none}& .lines{background-color:var(--color-page,oklch(98.5% 0 0));color:var(--color-content-subtle,oklch(55.6% 0 0));display:inline-flex;flex-direction:column;font-family:inherit;font-size:inherit;inset-inline-start:0;line-height:inherit;padding:calc(var(--spacing, .25rem)*4);pointer-events:none;position:absolute;text-align:end;user-select:none}&:has(.lines) code{padding-inline-start:calc(var(--spacing, .25rem)*8 + 2ch)}:where(code){flex:1 1 100%;min-width:0;white-space:pre;white-space-collapse:preserve}& button.expand{align-items:center;background:transparent;border:0;border-radius:0;color:var(--color-content-subtle,oklch(55.6% 0 0));cursor:pointer;display:flex;font-family:var(--font-sans,sans-serif);font-size:inherit;height:var(--spacing-field-height,2.25rem);justify-content:center;order:99;padding:0 calc(var(--spacing, .25rem)*2);transition:var(--transition,all .05s ease-in-out);width:100%;&:hover{background:color-mix(in oklch,var(--color-content-stark,oklch(43.9% 0 0)) 8%,transparent);color:var(--color-content-neutral,oklch(43.9% 0 0))}}&[data-collapsed] .lines,&[data-collapsed] code{mask-image:linear-gradient(180deg,#000 0,#000 calc(100% - 3em),transparent calc(100% - .75em),transparent);max-height:calc(var(--collapse-lines, 20)*1.7em + var(--spacing, .25rem)*8);overflow:hidden}:where(aside.frame){background:unset;border:0;box-shadow:unset;color:unset;font-family:unset;font-size:unset;font-weight:unset;line-height:unset;white-space:normal;white-space-collapse:collapse}}:where([x-code-group]){flex-flow:column;:where([x-code]){background:transparent;border:0;border-radius:0}}:where([x-code]):has(>header){& .lines{top:var(--spacing-field-height,2.25rem)}}}
|
|
@@ -72,16 +72,25 @@
|
|
|
72
72
|
gap: var(--spacing, 0.25rem);
|
|
73
73
|
max-width: 100%;
|
|
74
74
|
height: calc(var(--spacing-field-height, 2.25rem) - var(--spacing, 0.25rem) * 2.5);
|
|
75
|
+
margin: 0;
|
|
76
|
+
padding: 0;
|
|
75
77
|
padding-inline-start: calc(var(--spacing, 0.25rem) * 2);
|
|
76
78
|
font-size: 0.875rem;
|
|
79
|
+
line-height: normal;
|
|
77
80
|
color: var(--color-content-stark, oklch(43.9% 0 0));
|
|
78
81
|
background-color: var(--color-popover-surface, oklch(100% 0 0));
|
|
82
|
+
border: 0;
|
|
79
83
|
border-radius: calc(var(--radius, 0.5rem) * 0.7);
|
|
80
84
|
overflow: hidden;
|
|
81
85
|
user-select: none;
|
|
82
86
|
|
|
83
87
|
/* Label */
|
|
84
88
|
&>span {
|
|
89
|
+
min-width: 0;
|
|
90
|
+
margin: 0;
|
|
91
|
+
padding: 0;
|
|
92
|
+
border: 0;
|
|
93
|
+
font: inherit;
|
|
85
94
|
overflow: hidden;
|
|
86
95
|
text-overflow: ellipsis;
|
|
87
96
|
white-space: nowrap
|
|
@@ -92,15 +101,23 @@
|
|
|
92
101
|
display: inline-flex;
|
|
93
102
|
align-items: center;
|
|
94
103
|
justify-content: center;
|
|
104
|
+
box-sizing: border-box;
|
|
105
|
+
flex: none;
|
|
106
|
+
width: auto !important;
|
|
95
107
|
min-width: 0;
|
|
108
|
+
max-width: none;
|
|
96
109
|
height: 100%;
|
|
110
|
+
min-height: 0;
|
|
97
111
|
aspect-ratio: 1 / 1;
|
|
112
|
+
margin: 0;
|
|
98
113
|
padding: 0;
|
|
114
|
+
border: 0;
|
|
115
|
+
border-radius: 0;
|
|
99
116
|
font-size: 1em;
|
|
100
117
|
line-height: 1;
|
|
101
118
|
color: var(--color-content-neutral, oklch(43.9% 0 0));
|
|
102
119
|
background: transparent;
|
|
103
|
-
|
|
120
|
+
box-shadow: none;
|
|
104
121
|
cursor: pointer;
|
|
105
122
|
|
|
106
123
|
&:hover {
|