{"id":15387255,"url":"https://github.com/rhysd/tui","last_synced_at":"2025-04-15T17:32:13.005Z","repository":{"id":57142951,"uuid":"78424186","full_name":"rhysd/Tui","owner":"rhysd","description":"Twitter client based on mobile.twitter.com in menu bar","archived":false,"fork":false,"pushed_at":"2018-04-13T18:20:17.000Z","size":709,"stargazers_count":63,"open_issues_count":4,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T20:46:41.630Z","etag":null,"topics":["desktop-app","electron","twitter"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhysd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-09T11:49:19.000Z","updated_at":"2025-02-06T14:37:18.000Z","dependencies_parsed_at":"2022-09-05T22:30:13.118Z","dependency_job_id":null,"html_url":"https://github.com/rhysd/Tui","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2FTui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2FTui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2FTui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2FTui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhysd","download_url":"https://codeload.github.com/rhysd/Tui/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249118798,"owners_count":21215622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["desktop-app","electron","twitter"],"created_at":"2024-10-01T14:53:03.316Z","updated_at":"2025-04-15T17:32:12.647Z","avatar_url":"https://github.com/rhysd.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Tui\n===\n\nTwitter client based on https://mobile.twitter.com in menu bar.\n\n\u003cimg src=\"https://github.com/rhysd/ss/blob/master/Tui/desktop.jpg?raw=true\" width=\"700\" alt=\"application screenshot\"/\u003e\n\nFeatures\n\n- Provide all features even if Twitter API doesn't provide (tracing conversation, group DM, votes, sync with https://twitter.com, ...)\n- Support [multi-accounts](#multi-accounts)\n- User defined CSS and [Themes](#themes)\n- User defined tweet filters written in JavaScript as commonjs modules ([plugins](#plugins))\n- Various keymaps to do many things only with keyboard\n- You can choose menu bar window, (split view) fullscreen or normal window\n- Available on macOS, Linux and Windows\n\nAll links outside https://mobile.twitter.com in tweets are opened in an external browser.\n\nWhen you want to make a new tweet, press `n` (it can be changed in config).\n\nEven if you use menubar window, you can enter/leave fullscreen mode via menu item (View -\u003e Enter/Leave FullScreen).\nIn fullscreen mode, app behaves like as normal window. Fullscreen mode is especially useful on macOS with split view.\n\n## Installation\n\nDownload archived file for your environment from [release page](https://github.com/rhysd/Tui/releases). Please follow the instruction in the release page.\n\nOr available as [npm package](https://www.npmjs.com/package/tuitter).\n\n```\n$ npm install --global tuitter\n```\n\n## Usage\n\nIf you installed this app from the release page, start this app by executing the binary.\n\nIf you installed this app via npm, start from command line.\n\n```\n$ tuitter\n```\n\nAlmost all usage is the same as original https://mobile.twitter.com . You can use various key shortcuts\nto operate the page (focusing on tweet, make new tweet, see image, open link in browser, and so on).\nAnd you can use themes or plugins to extend this app (or even you can create one by yourself).\nYou can always access to this app via hot key.\n\nthis application can be in 3 modes:\n\n- **Menubar window (default)**: Small window near the menu bar icon. When the window loses its focus, automatically window will be hidden. You can change window size.\n- **(Split view) fullscreen**: Click 'Enter Fullscreen' in menu item. You can put this app in fullscreen mode as split view (in macOS).\n- **Normal window**: By configuring, this app can be launched with normal window. You can use this app like as other normal applications.\n\n\nTo show DevTools, set the environment variable. There will be two DevTools window.\nOne is for renderer process of native window. Another is for `\u003cwebview\u003e` which actually renders https://mobile.twitter.com.\n\n```\n$ NODE_ENV=development tuitter\n```\n\n## Application Directory\n\nTui has a directory for application data. The path depends on your OS.\n\n- `~/Library/Application\\ Support/Tui` for macOS\n- `~/.config/Tui` for Linux\n- `%APPDATA%\\Tui` for Windows.\n\n## Notifications\n\nThere is an icon in menu bar. You can toggle application window by clicking it.\nAnd you can notice that there are notifications or direct messages by the color of it.\n\n### Normal Icon\n\n![normal icon](https://github.com/rhysd/ss/blob/master/Tui/normal.jpg?raw=true)\n\nNormally icon in menu bar is black (or white).\n\n### Notified Icon\n\n![informed icon](https://github.com/rhysd/ss/blob/master/Tui/informed.jpg?raw=true)\n\nWhen there are some unread notifications in 'Notifications' tab, icon will be blue.\n\n### Important Notice Icon\n\n![notified icon](https://github.com/rhysd/ss/blob/master/Tui/notified.jpg?raw=true)\n\nWhen there are unread direct messages, icon will be red.\n\n## Config\n\nConfiguration is written in JSON file in application directory. Please edit it with your favorite editor.\nIf you want to reset configuration, please simply remove the JSON file and restart application.\n\n```sh\n$ $EDITOR {app dir}/config.json\n```\n\nTo know type of values of each keys, please see [type definition](./typings/config.d.ts).\n\n### keymaps\n\nDefine keymaps of this application as JSON object. The key is a key sequence and the value is an action name.\nFor example, `\"mod+shift+j\": \"next-tweet\"` assigns `next-tweet` action to key sequence `Cmd+Shift+J` (or `Ctrl+Shift+J` on other OS).\n`mod` means `Cmd` in macOS and `Ctrl` in other OS.\n\nThe key sequence format is [mousetrap](https://craig.is/killing/mice). Note that this format is different from `hot_key` above.\n\n| Action Name              | Description                                                 | Default Key   |\n|--------------------------|-------------------------------------------------------------|---------------|\n| `next-tweet`             | Scroll down window per one tweet                            | `j`           |\n| `previous-tweet`         | Scroll up window per one tweet                              | `k`           |\n| `unfocus-tweet`          | Unfocus current focus on tweet. It can cancel editing tweet | `esc`         |\n| `scroll-down-page`       | Scroll down window per page                                 | `f`           |\n| `scroll-up-page`         | Scroll up window per page                                   | `b`           |\n| `scroll-up-to-top`       | Scroll to newest tweet when 'New Tweet' popup is displayed  | `t`           |\n| `scroll-down-to-bottom`  | Scroll to the bottom of timeline                            | N/A           |\n| `switch-home-timeline`   | Switch to 'Home Timeline' tab                               | `1`           |\n| `switch-notifications`   | Switch to 'Notifications' tab                               | `2`           |\n| `switch-direct-messages` | Switch to 'Direct Messages' tab                             | `3`           |\n| `switch-search`          | Switch to 'Search' tab                                      | `4`           |\n| `new-tweet`              | Start editing a new tweet                                   | `n`           |\n| `send-tweet`             | Send current editing tweet                                  | `ctrl+enter`  |\n| `reply-tweet`            | Reply to the focused tweet                                  | `enter`       |\n| `retweet-tweet`          | Retweet the focused tweet                                   | `R`           |\n| `quote-tweet`            | Retweet with quoting the focused tweet                      | `Q`           |\n| `like-tweet`             | Like with quoting the focused tweet                         | `L`           |\n| `open-images`            | Open image or video in the focused tweet                    | `i`           |\n| `open-images-in-browser` | Open image or video in focused tweet with external browser  | `I`           |\n| `open-tweet`             | Open tweet page for the focused tweet                       | `o`           |\n| `open-links`             | Open links contained in the focused tweet with browser      | `l`           |\n| `show-user`              | Open user page of the focused tweet's author                | `u`           |\n| `browser-go-back`        | Navigate to go back like a browser                          | `backspace`   |\n| `browser-go-forward`     | Navigate to go forward like a browser                       | N/A           |\n| `browser-reload`         | Navigate to reload like a browser                           | N/A           |\n| `zoom-in`                | Zoom font size by 10%                                       | `mod+plus`    |\n| `zoom-out`               | Zoom font size by -10%                                      | `mod+-`       |\n| `last-account`           | Switch account to most recently used one                    | `mod+shift+l` |\n| `next-account`           | Switch account to next one in accounts list                 | `mod+shift+n` |\n| `previous-account`       | Switch account to previous one in accounts list             | `mod+shift+p` |\n| `quit-app`               | Quit application                                            | N/A           |\n| `open-devtools`          | Open DevTools for current page                              | N/A           |\n\n### normal\\_window\n\nWhen this value is set to `true`, application will be launched as a normal window application.\nIf menu bar behavior does not work for you, please use set this value to `true` to avoid it.\nDefault value is `false` on macOS or Linux, `true` on Windows because window position is broken in some version of Windows.\n\n\u003cimg src=\"https://github.com/rhysd/ss/blob/master/Tui/normal_window.png?raw=true\" width=\"443\" alt=\"normal window mode\"/\u003e\n\n### hot\\_key\n\n`hot_key` is a key sequence to toggle application window. The shortcut key is defined globally.\nThe format is a [Electron's accelerator](https://github.com/electron/electron/blob/master/docs/api/accelerator.md). Please see the document to know how to configure this value.\nDefault value is `\"CmdOrCtrl+Shift+S\"`. If you want to disable, please set empty string or `null`. \n\n### plugins\n\nString array of paths to your plugins. As described below, plugin is loaded with Node.js's `require()`.\nSo it can be a single file path or npm package directory path.\nYou can specify both absolute path and relative path to application directory.\nFor example, when you have `{app dir}/some_plugin.js`, you can specify `[\"some_plugin.js\"]` as the value.\n\nThese paths can contain glob. For example, `plugins/*.js` will load all JavaScript files in `{app dir}/plugins` directory.\n\nDefault value is `[]`.\n\n### accounts\n\n`accounts` is a list of your accounts. Items should be `@screen_name`.\nWhen this value is set, you can [switch account via menu item](#multi-accounts)\nThis value is not set by default (`null`).\n\n```json\n{\n  \"accounts\": [\n    \"@main_account\",\n    \"@sub_account\"\n  ]\n}\n```\n\n### refresh\\_on\\_sleep\n\nIf this value is set to `true`, Tui will refresh its web contents at PC suspending when it consumes much memory.\nThe threshold which detemines the refresh occur or not is up to `refresh_threshold_memory_mb` config.\nDefault value is `true`.\n\n### refresh\\_threshold\\_memory\\_mb\n\nInteger value (defaults to `500`). If `\u003cwebview\u003e`'s current memory usage exceeds this value, app will refresh `\u003cwebview\u003e` on PC suspending.\nThe unit is mega bytes. By default, when `\u003cwebview\u003e` consuming more than 500MB, it will be refreshed at suspending.\nPlease see above `refresh_on_sleep` config also.\n\n### icon\\_color\n\nColor of icon in menu bar. `\"white\"` or `\"black\"` is available. In macOS, it's depending on the system is dark mode or not.\nIn other platforms, default value is or `\"black\"`.\n\n### always\\_on\\_top\n\nWhen this value is set to `true`, the window won't be hidden if it loses a focus. Default value is `false`.\n\n### zoom\\_factor\n\nFont zoom factor in application. It should be positive number. For example, `0.7` means `70%` font zooming.\nDefault font size is a bit bigger because https://mobile.twitter.com is originally for mobile devices. So default value is `0.9`.\n\n### home\\_url\n\nHome URL loaded when application starts. If you see a list or something instead of home timeline, please modify this URL.\nDefault value is `\"https://mobile.twitter.com\"`.\n\n### notification\n\nWhen this value is set to `false`, notification will be disabled and icon won't be changed even if new mentions or direct messages arrive. Default value is `true`.\n\n## \u003ca name=\"multi-accounts\"\u003eMulti-accounts\n\nWhen you set `accounts` value in your `config.json`, you can switch among your accounts via menu item.\nWhen application has a focus, you can see 'Accounts' menu item in menu bar.\nBy clicking the item, you can see current one and switch to other.\n\n\u003cimg src=\"https://github.com/rhysd/ss/blob/master/Tui/accounts.jpg?raw=true\" width=\"435\" alt=\"screenshot of switching accounts\"/\u003e\n\nIf you use Windows, you can show menu bar by pressing Alt key.\n\n## Plugin\n\nTui can load your JavaScript plugin and you can hook some points in application. Plugin paths can be specified in `config.json` (see above).\nEach paths will be loaded with Node.js's `require()`. So you can create a plugin as a single JavaScript or npm package structure directory.\n\nPlugin must export one object which (may) contains hooks as property. Current supported hooks are:\n\n- `onStart(ctx)`: When application started\n- `onTweetStatus(tw, ctx)`: When a tweet appears in application's timeline. `tw` is a DOM element which represents a tweet.\n- `onKeymap`: An object value whose keys are keymap name and values are the corresponding process.\n\nThe `ctx` parameter is an instance of [`AppContext` class](./webview/context.ts).\nInterface definition is [described in TypeScript code](./webview/plugin_manager.ts).\n\nPlugins are loaded in https://mobile.twitter.com context. So you can modify DOM element directly and freely.\nAs member of `AppContext` instance, there are [many useful CSS selectors](./webview/constants.ts) to choose proper element.\n\nBelow is a super simple plugin to filter f\\*ck words.\n\n```javascript\nconst FWORDS = [\n    'Fuck',\n    'fuck',\n];\n\nmodule.exports = {\n    onTweetStatus(tw, ctx) {\n        const textElement = tw.querySelector(ctx.selectors.tweetTextBody);\n        if (textElement === null) {\n            return;\n        }\n        const text = textElement.innerText;\n        for (const w of FWORDS) {\n            if (text.indexOf(w) \u003e= 0) {\n                tw.style.display = 'none';\n                break;\n            }\n        }\n    }\n};\n```\n\nYou can also create your original keymap with this. The `ctx` parameter is the same as above (`AppContext` instance), and\nthe `event` parameter is a `KeyboardEvent` on the keydown event. Note that `event.preventDefault()` is already called.\nAnd keymap is not invoked when `\u003cinput\u003e` or `\u003ctextarea\u003e` is focused. So you need not to take care about them.\n\n```javascript\nmodule.exports = {\n    onKeymap: {\n        'show-my-cool-list': (ctx, event) =\u003e {\n            // Note that all external links outside https://mobile.twitter.com are opened in a browser.\n            href.location = 'https://mobile.twitter.com/Linda_pp/lists/my-cool-list';\n        }\n    }\n};\n\n// And add your original keymap in config.json\n//  \"keymaps\": {\n//    \"mod+l\": \"show-my-cool-list\"\n//  },\n```\n\nTo see the log, it's easy way to specify environment variable `NODE_ENV=development`. It opens DevTools at app starting.\nOr there is a keymap to open DevTools (it's not assigned to any key by default).\n\nNote that hooks are called with blocking. Please do not execute heavy process or consider to use `setTimeout()` to defer heavy process.\n\n### \u003ca name=\"plugins\"\u003e Plugins List\n\n- [tui-plugin-filter-by-text](https://github.com/rhysd/tui-plugin-filter-by-text)\n\n## User Defined CSS\n\nWhen you put `user.css` in application directory, Tui automatically loads it and applies to underlying https://mobile.twitter.com.\nYou can create a theme for https://mobile.twitter.com and hide some elements by `display: none`.\n\n[This](https://github.com/rhysd/dogfiles/blob/master/stylish/twitter.css) is one example of `user.css`.\n\n## \u003ca name=\"themes\"\u003e Themes\n\nYou can also put `theme.css` in application directory. It's also applied on loading https://mobile.twitter.com.\nThis CSS file intends to be used for changing colors in the page. `theme.css` is always loaded before loading `user.css`.\nSo you can override theme styles in `user.css` without modifying `theme.css`.\n\nBelow is a list of themes provided:\n\n- [tui-theme-dark](https://github.com/rhysd/tui-theme-dark)\n\n## User Defined JS Script\n\nYou can also put `user.js` in application directory. It will be loaded when loading https://mobile.twitter.com at first.\nPlease do not assume that it's loaded deterministically. It will be loaded while loading https://mobile.twitter.com.\nDOM may not be ready yet. In that case, you need to wait `load` event.\n\n## Future\n\n- Dynamically toggle menubar \u003c-\u003e normal window\n- Tests\n\n## Development\n\n```\n$ git clone https://github.com/rhysd/Tui.git \u0026\u0026 cd Tui\n\n# Install all dependencies into node_modules/\n$ npm install\n\n# Build app (it's written in TypeScript)\n$ npm run build\n\n# Run app in debug mode\n$ npm run debug\n\n# Apply tslint and stylelint to codes\n$ npm run lint\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Ftui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhysd%2Ftui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Ftui/lists"}