https://github.com/bthos/telegramito
A static, browser-only Telegram client. No first-party backend - the session and all settings live on the device.
https://github.com/bthos/telegramito
childrens-web parental-controls telegram
Last synced: 17 days ago
JSON representation
A static, browser-only Telegram client. No first-party backend - the session and all settings live on the device.
- Host: GitHub
- URL: https://github.com/bthos/telegramito
- Owner: bthos
- License: mit
- Created: 2026-04-27T13:11:57.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-15T22:28:33.000Z (about 1 month ago)
- Last Synced: 2026-05-15T23:58:12.381Z (about 1 month ago)
- Topics: childrens-web, parental-controls, telegram
- Language: TypeScript
- Homepage: https://bthos.github.io/telegramito/
- Size: 687 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Telegramito
[](https://github.com/bthos/telegramito/actions/workflows/ci.yml)
A static, browser-only Telegram client built on [GramJS](https://gram.js.org/) (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`](https://github.com/bthos/gramjs), сборка в `vendor/telegram-built` при `npm install` (см. ниже) |
| i18n | i18next, react-i18next |
| Persistence | IndexedDB via `idb` |
| Tests | Vitest, jsdom, `@testing-library/react` |
## Getting started
### Prerequisites
- Node.js 20+
- Telegram API credentials from [my.telegram.org](https://my.telegram.org)
### 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:
```bash
npm run rebuild:telegram
```
Clone with submodules (or init them after clone):
```bash
git clone --recurse-submodules https://github.com//telegramito.git
# or, if you already cloned without submodules:
git submodule update --init --recursive
```
### Install
```bash
npm install
```
### Configure
Copy `.env.example` to `.env` and fill in your credentials:
```
VITE_TELEGRAM_API_ID=
VITE_TELEGRAM_API_HASH=
```
### Develop
```bash
npm run dev
```
### Test
```bash
npm test
```
### Build
```bash
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](.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
```ts
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