Skip to content

bthos/telegramito

Repository files navigation

Telegramito

A static, browser-only Telegram client built on GramJS (MTProto). No first-party backend — the session and all settings live on the device.

Features

  • MTProto connection via GramJS in the browser
  • Chat list with message previews and unread counts
  • Message thread with media rendering (photos, video, audio, files, polls, stickers, dice, paid media, and more)
  • Compose area with auto-grow textarea and reply/forward support
  • Image lightbox, inline location maps, poll voting
  • Chat context panel — peer info, shared media grid, quick actions (see below)
  • Parental / supervised mode: child profile, allowlist, PIN-gated settings, night-hours lock
  • Infinite scroll via IntersectionObserver sentinel (no load-more button)
  • PWA, single-file production HTML output
  • i18n: English, Belarusian, Spanish

Tech stack

Layer Library
UI React 19, TypeScript
Bundler Vite 8, vite-plugin-pwa, vite-plugin-singlefile
Telegram GramJS — исходники в git submodule vendor/gramjs, сборка в vendor/telegram-built при npm install (см. ниже)
i18n i18next, react-i18next
Persistence IndexedDB via idb
Tests Vitest, jsdom, @testing-library/react

Getting started

Prerequisites

Clone

GramJS is vendored as a git submodule (vendor/gramjs). On npm install, preinstall runs scripts/prepare-vendor-telegram.mjs: installs devDependencies inside the submodule, runs tsc, and copies the emit into vendor/telegram-built (gitignored), which is what the telegram dependency points at. The first install can take a few minutes.

To force a rebuild after changing the submodule commit:

npm run rebuild:telegram

Clone with submodules (or init them after clone):

git clone --recurse-submodules https://github.com/<you>/telegramito.git
# or, if you already cloned without submodules:
git submodule update --init --recursive

Install

npm install

Configure

Copy .env.example to .env and fill in your credentials:

VITE_TELEGRAM_API_ID=<your api_id>
VITE_TELEGRAM_API_HASH=<your api_hash>

Develop

npm run dev

Test

npm test

Build

npm run build

The output is a single HTML file in dist/.

After changing GramJS (vendor/gramjs)

  1. npm run rebuild:telegram
  2. npm run build and npm test
  3. Manual smoke: forum topic with a poll and a small message id gap in history

Details: .artefacts/GRAMJS.md.

Project structure

src/
  context/        TelegramContext, ParentalContext
  hooks/          Custom React hooks (usePeerRecentMedia, etc.)
  telegram/       GramJS helpers
  parental/       Parental policy and storage
  ui/             React components
  styles/         app.css, tokens.css
  locales/        en.json, be.json, es.json

Chat context panel

Toggled from any open chat by the info button in the chat header.

Viewport Behaviour
≥ 1024 px 360 px side column, side-by-side with the chat pane
640–1023 px Fixed right overlay with a dim backdrop
< 640 px Bottom sheet (82 dvh) with drag handle and dim backdrop

The panel closes automatically on every chat switch.

Contents:

  • Peer header — avatar (48 px) and display name
  • Shared media grid — 3 × 2 most recent photo thumbnails (blob-rendered); loading skeleton and "No shared media" fallback
  • Quick actions — Search in chat (stub, pending UX-14), Mute/Unmute (stub, V2), Block user (private peers, stub V2), Leave group (groups/megagroups, with inline confirmation)

Keyboard / a11y: Escape dismisses the panel. Panel root is role="dialog" aria-modal="true". Backdrop click also dismisses.

usePeerRecentMedia hook

usePeerRecentMedia(
  entity: Api.User | Api.Chat | Api.Channel | null | undefined,
  client: TelegramClient | null,
): { items: Api.Message[]; loading: boolean; error: string | null }

Fetches up to 6 recent photo messages for a peer. Serves from a session-scoped module-level cache on repeated calls to the same peer.

Parental mode

Switch between Child and Parent profiles in the top bar. In Child mode:

  • Unknown private chats are hidden until allowlisted or approved by the parent
  • Link previews, GIF-heavy messages, and the chat list during night hours can each be independently restricted
  • Destructive actions (block user, leave group) require a parent PIN when set

License

MIT

About

A static, browser-only Telegram client. No first-party backend - the session and all settings live on the device.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors