8

Продолжение поста «Добавил иконки в Gmail почту! Красота =)»

Напомню. Я сделал расширение, которое добавляет иконки в Gmail почту. И в комментариях попросили сделать не расширением, а скриптом для Tampermonkey. Мне было лень, но потом я подумал почему бы и нет. Скинул код в chatGPT и он подогнал его под формат Tampermonkey. Ниже расскажу как поставить чтоб работало.

Выглядит вот так:

Продолжение поста «Добавил иконки в Gmail почту! Красота =)»

Как поставить?

  1. Установить Tampermonkey если у вас его ещё нет https://chromewebstore.google.com/detail/tampermonkey/dhdgff...

  2. Правой кнопкой по иконке расширения и Параметры

  3. В верхнем меню панели Tampermonkey жмём на плюсик и открывается страница создания нового скрипта

  4. Вставляем код скприта сюда и сохраняем

  5. Готово.

Вот сам код скрипта:

// ==UserScript==

// @name Gmail Sender Favicon (base + S2, fallback letter)

// @namespace https://tampermonkey.net/

// @VERSION 2026-01-02

// @Description Gmail: show sender base-domain favicon; fallback to Google S2; then fallback to letter.

// @match https://mail.google.com/*

// @run-at document-idle

// ==/UserScript==

(() => {

'use strict';

const STYLE_ID = 'gm-sender-favicon-style-final';

const BADGE_CLASS = 'gm-sender-badge-final';

function injectStyles() {

if (document.getElementById(STYLE_ID)) return;

const style = document.createElement('style');

style.id = STYLE_ID;

style.textContent = `

.${BADGE_CLASS}{

display:inline-flex;

align-items:center;

margin-right:6px;

vertical-align:middle;

flex: 0 0 auto;

transform: translateY(-0.5px);

}

.${BADGE_CLASS} img{

width:14px;height:14px;border-radius:3px;display:block;

}

.${BADGE_CLASS} .gm-letter{

font-weight:700;

font-size:12px;

line-height:1;

display:inline-block;

}

`;

document.documentElement.appendChild(style);

}

// ---------- domain/email helpers ----------

function extractEmailLike(str) {

if (!str) return '';

const s = String(str);

// <mail@domain>

const m1 = s.match(/<\s*([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\s*>/i);

if (m1) return m1[1];

// mail@domain

const m2 = s.match(/([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})/i);

if (m2) return m2[1];

return '';

}

function getDomainFromEmail(email) {

const at = (email || '').indexOf('@');

if (at === -1) return '';

return email.slice(at + 1).trim().toLowerCase();

}

// Простая нормализация к base-domain: example.com

function baseDomain(domain) {

const parts = (domain || '').split('.').filter(Boolean);

if (parts.length < 2) return domain || '';

return parts.slice(-2).join('.');

}

// стабильный цвет по seed (чтобы буква была “привычного” цвета)

function stableColor(seed) {

let h = 0;

for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;

const hue = Math.abs(h) % 360;

return `hsl(${hue}, 70%, 40%)`;

}

function pickLetter(senderText, base) {

const m = (senderText || '').match(/[a-z0-9а-яё]/i);

if (m) return m[0].toUpperCase();

if (base) return base[0].toUpperCase();

return '?';

}

// ---------- locating sender in a row ----------

function findSenderInfo(row) {

// 1) самый надежный: span[email]

const emailSpan = row.querySelector('span[email]');

if (emailSpan) {

const email = emailSpan.getAttribute('email') || '';

const senderText =

(emailSpan.getAttribute('name') || '').trim() ||

(emailSpan.getAttribute('aria-label') || '').trim() ||

(emailSpan.textContent || '').trim();

return { email, senderText, senderNode: emailSpan };

}

// 2) data-hovercard-id часто содержит email

const hcSpan = row.querySelector('span[data-hovercard-id]');

if (hcSpan) {

const hc = hcSpan.getAttribute('data-hovercard-id') || '';

const email = extractEmailLike(hc) || extractEmailLike(hcSpan.getAttribute('aria-label')) || '';

const senderText =

(hcSpan.getAttribute('name') || '').trim() ||

(hcSpan.getAttribute('aria-label') || '').trim() ||

(hcSpan.textContent || '').trim();

return { email, senderText, senderNode: hcSpan };

}

// 3) иногда sender виден как yP/zF

const nameSpan = row.querySelector('span.yP, span.zF');

if (nameSpan) {

const email =

extractEmailLike(nameSpan.getAttribute('aria-label')) ||

extractEmailLike(nameSpan.getAttribute('title')) ||

'';

const senderText =

(nameSpan.getAttribute('aria-label') || '').trim() ||

(nameSpan.getAttribute('title') || '').trim() ||

(nameSpan.textContent || '').trim();

return { email, senderText, senderNode: nameSpan };

}

return null;

}

// ---------- badge creation ----------

function makeBadge(base, letter, fontSizePx) {

const badge = document.createElement('span');

badge.className = BADGE_CLASS;

badge.setAttribute('data-base', base || '');

const img = document.createElement('img');

img.alt = '';

img.referrerPolicy = 'no-referrer';

const sources = base

? [

`https://${base}/favicon.ico`,

`https://www.google.com/s2/favicons?sz=64&amp;domain=%24%7Ben...}`

]

: [];

let idx = 0;

const fallbackToLetter = () => {

img.remove();

const span = document.createElement('span');

span.className = 'gm-letter';

span.textContent = letter;

span.style.color = stableColor(base || letter || 'x');

if (fontSizePx) span.style.fontSize = fontSizePx;

badge.appendChild(span);

};

img.onerror = () => {

idx++;

if (idx < sources.length) {

img.src = sources[idx];

} else {

fallbackToLetter();

}

};

if (sources.length) {

img.src = sources[0];

badge.appendChild(img);

} else {

fallbackToLetter();

}

return badge;

}

// ---------- main enhancer ----------

function enhanceRow(row) {

const info = findSenderInfo(row);

if (!info) return;

const domain = getDomainFromEmail(info.email);

const base = baseDomain(domain);

// текст для буквы

const senderText = info.senderText || (info.senderNode?.textContent || '').trim();

const letter = pickLetter(senderText, base);

// куда вставлять:

// A) предпочитаем контейнер отправителя (как у тебя работало)

let target = row.querySelector('.yX.xY');

// B) если нет — рядом с узлом senderNode

let insertBeforeNode = null;

if (!target && info.senderNode && info.senderNode.parentElement) {

target = info.senderNode.parentElement;

insertBeforeNode = info.senderNode;

}

if (!target) return;

// уже вставлено?

const existing = target.querySelector(`:scope > .${BADGE_CLASS}`);

if (existing) {

const exBase = existing.getAttribute('data-base') || '';

if (exBase === (base || '')) return;

existing.remove();

}

const cs = window.getComputedStyle(target);

const fontSizePx = cs.fontSize ? `calc(${cs.fontSize} - 1px)` : '';

const badge = makeBadge(base, letter, fontSizePx);

if (insertBeforeNode) target.insertBefore(badge, insertBeforeNode);

else target.prepend(badge);

}

function enhanceAll() {

injectStyles();

document.querySelectorAll('.zA').forEach(enhanceRow);

}

// ---------- observer (throttled) ----------

let rafPending = false;

function schedule() {

if (rafPending) return;

rafPending = true;

requestAnimationFrame(() => {

rafPending = false;

enhanceAll();

});

}

const obs = new MutationObserver(schedule);

obs.observe(document.body, { childList: true, subtree: true });

enhanceAll();

})();

Показать полностью
68

Добавил иконки в Gmail почту! Красота =)

Сегодня переписал бесплатное расширение меток для гугловской почты и теперь это расширение, которое добавляет в гугл почту иконки отправителей, а если иконки нет, то показывается метку.

Мне кажется, что стало красиво!
Скачать можно тут https://chromewebstore.google.com/detail/gmail-email-icons/n...

Стало:

Было:

Работает локально, ничего не собирает, никуда не отправляет, рекламу не показывает.
Всё как мы любим.

Поднимите вверх, чтоб больше людей увидело =)

Показать полностью 1
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества