Channels UI + read/unread + unique views + style polish

This commit is contained in:
DrygMira
2026-04-23 13:36:01 +03:00
parent 78d6124f2a
commit c0dfa6c7ab
25 changed files with 2369 additions and 145 deletions
+52
View File
@@ -168,3 +168,55 @@ export function normalizeChannelDescription(value) {
if (chars.length <= 200) return text;
return chars.slice(0, 200).join('');
}
function fallbackCopyText(text) {
const ta = document.createElement('textarea');
ta.value = String(text || '');
ta.setAttribute('readonly', 'readonly');
ta.style.position = 'fixed';
ta.style.opacity = '0';
ta.style.pointerEvents = 'none';
document.body.append(ta);
ta.focus();
ta.select();
const ok = document.execCommand('copy');
ta.remove();
return !!ok;
}
export async function shareOrCopyLink({ title = '', text = '', url = '' }) {
const link = String(url || '').trim();
if (!link) {
throw new Error('Ссылка для передачи не подготовлена.');
}
const payload = { title: String(title || '').trim(), text: String(text || '').trim(), url: link };
if (navigator?.share) {
try {
await navigator.share(payload);
return 'shared';
} catch (error) {
if (error?.name === 'AbortError') return 'cancelled';
// fallback to copy path
}
}
if (navigator?.clipboard?.writeText) {
await navigator.clipboard.writeText(link);
return 'copied';
}
if (fallbackCopyText(link)) {
return 'copied';
}
throw new Error('Не удалось передать ссылку.');
}
export async function longPressFeel(el, delayMs = 130) {
const node = el instanceof Element ? el : null;
if (node) node.classList.add('is-long-press');
await new Promise((resolve) => setTimeout(resolve, Math.max(60, Number(delayMs) || 130)));
if (node) node.classList.remove('is-long-press');
}