├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── main.yml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .npm-upgrade.json ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── extensions.json ├── i18n-ally-custom-framework.yml └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── artifacts └── .gitkeep ├── config └── default.json ├── crowdin.yml ├── definitions ├── assets.d.ts ├── btdGlobals.d.ts ├── globals.d.ts └── pronouns │ └── index.d.ts ├── docs └── filters.md ├── jest.config.js ├── meta ├── better.tw_.png ├── debug-infos.png ├── en_desc.md └── hotfixes.css ├── package-lock.json ├── package.json ├── safari └── Better TweetDeck for Safari │ ├── Better TweetDeck for Safari Extension │ ├── Better_TweetDeck_for_Safari_Extension.entitlements │ ├── Info.plist │ └── SafariWebExtensionHandler.swift │ ├── Better TweetDeck for Safari │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── icon-1024.png │ │ │ ├── icon-128.png │ │ │ ├── icon-16.png │ │ │ ├── icon-256.png │ │ │ ├── icon-32.png │ │ │ ├── icon-512.png │ │ │ └── icon-64.png │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── Better_TweetDeck_for_Safari.entitlements │ ├── Info.plist │ └── ViewController.swift │ └── BetterTDeck for TweetDeck.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── src ├── _locales │ ├── cs │ │ └── messages.json │ ├── de │ │ └── messages.json │ ├── en │ │ └── messages.json │ ├── fr │ │ └── messages.json │ ├── ja │ │ └── messages.json │ ├── nl │ │ └── messages.json │ ├── pt_BR │ │ └── messages.json │ └── ru │ │ └── messages.json ├── assets │ ├── accent-colors │ │ ├── any.svg │ │ ├── blue.svg │ │ ├── green.svg │ │ ├── orange.svg │ │ ├── pink.svg │ │ ├── purple.svg │ │ ├── rainbow.svg │ │ ├── red.svg │ │ └── yellow.svg │ ├── btd-logo-small.png │ ├── btd-logo.png │ ├── btd-stars │ │ ├── btd-stars.eot │ │ ├── btd-stars.svg │ │ ├── btd-stars.ttf │ │ ├── btd-stars.woff │ │ └── btd-stars.woff2 │ ├── business-verified.svg │ ├── clown-icon.svg │ ├── column-preview │ │ ├── clear-btn.png │ │ ├── collapse-btn.png │ │ ├── column-bg.png │ │ └── no-icon.png │ ├── crooked-icon.svg │ ├── dark-themes │ │ ├── default-dark.png │ │ ├── light.png │ │ ├── lights-out.png │ │ └── old-dark.png │ ├── dogears │ │ ├── fav-heart.png │ │ ├── fav-rt-heart.png │ │ ├── fav-rt-star.png │ │ ├── fav-star.png │ │ └── rt.png │ ├── dollar-icon.svg │ ├── emoji-mart-data.json │ ├── emoji-sheet-64.png │ ├── filledStar.svg │ ├── gov-verified.svg │ ├── heart-icon.svg │ ├── hexagone-mask.png │ ├── icons │ │ ├── icon-1024.png │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-256.png │ │ ├── icon-32.png │ │ ├── icon-48.png │ │ ├── icon-512.png │ │ ├── icon-64.png │ │ ├── icon-96.png │ │ ├── icon-beta-1024.png │ │ ├── icon-beta-128.png │ │ ├── icon-beta-16.png │ │ ├── icon-beta-256.png │ │ ├── icon-beta-32.png │ │ ├── icon-beta-48.png │ │ ├── icon-beta-512.png │ │ ├── icon-beta-64.png │ │ ├── icon-beta-96.png │ │ ├── toolbar-icon-16.png │ │ └── toolbar-icon-32.png │ ├── logo-tweaks │ │ ├── agender.svg │ │ ├── androgyne.svg │ │ ├── aromantic.svg │ │ ├── asexual.svg │ │ ├── bigender.svg │ │ ├── bisexual.svg │ │ ├── btd.svg │ │ ├── demigirl.svg │ │ ├── demiguy.svg │ │ ├── deminonbinary.svg │ │ ├── demisexual.svg │ │ ├── enbian.svg │ │ ├── genderfluid.svg │ │ ├── genderqueer.svg │ │ ├── intersex.svg │ │ ├── lesbian.svg │ │ ├── neutrois.svg │ │ ├── non binary.svg │ │ ├── omnisexual.svg │ │ ├── pansexual.svg │ │ ├── polyamory.svg │ │ ├── polysexual.svg │ │ ├── progress.svg │ │ ├── rainbow.svg │ │ └── trans.svg │ ├── mutual-icon.svg │ ├── nerd-checkmark.svg │ ├── pronouns.json │ ├── star.svg │ ├── translator-icon.svg │ ├── twitter-blue.svg │ └── verified-icon.svg ├── background.ts ├── components │ ├── conversationControlsButton.tsx │ ├── emojiProvider.tsx │ ├── fullscreenModalWrapper.tsx │ ├── gifButton.css │ ├── gifPicker │ │ ├── gifButton.tsx │ │ ├── gifPicker.tsx │ │ ├── gifProvider.tsx │ │ └── singleGif.tsx │ ├── muteCatchesModal.tsx │ ├── openBtdSettingsButton.tsx │ ├── settings │ │ ├── components │ │ │ ├── avatarsShape.tsx │ │ │ ├── badgesOnTopOfAvatars.tsx │ │ │ ├── booleanSettingRow.tsx │ │ │ ├── checkboxSelectSettingsRow.tsx │ │ │ ├── columnSettingsPreview.tsx │ │ │ ├── customAccentColor.tsx │ │ │ ├── newFeatureBadge.tsx │ │ │ ├── radioSelectSettingsRow.tsx │ │ │ ├── settingsButton.tsx │ │ │ ├── settingsCheckboxSelect.tsx │ │ │ ├── settingsCss.tsx │ │ │ ├── settingsCssEditor.tsx │ │ │ ├── settingsModalComponents.tsx │ │ │ ├── settingsRadioInput.tsx │ │ │ ├── settingsRadioSelect.tsx │ │ │ ├── settingsRow.tsx │ │ │ ├── settingsSeparator.tsx │ │ │ ├── settingsTextInput.tsx │ │ │ ├── settingsTextInputWithAnnotation.tsx │ │ │ ├── settingsToggle.tsx │ │ │ ├── settingsTokensList.tsx │ │ │ └── themeSelector.tsx │ │ ├── menu │ │ │ ├── settingsComposer.tsx │ │ │ ├── settingsCredits.tsx │ │ │ ├── settingsExportButton.tsx │ │ │ ├── settingsGeneral.tsx │ │ │ ├── settingsImportExport.tsx │ │ │ ├── settingsLogo.tsx │ │ │ ├── settingsSupport.tsx │ │ │ ├── settingsTheme.tsx │ │ │ ├── settingsTweetActions.tsx │ │ │ └── settingsTweetsDisplay.tsx │ │ ├── settingsComponents.tsx │ │ ├── settingsContext.tsx │ │ ├── settingsHelpers.ts │ │ ├── settingsMenu.tsx │ │ ├── settingsModal.css │ │ ├── settingsModal.tsx │ │ ├── settingsModalContent.tsx │ │ ├── settingsStyles.ts │ │ ├── settingsTweetContent.tsx │ │ └── settingsTypes.ts │ └── trans.tsx ├── content.ts ├── defineConfig.ts ├── features │ ├── __tests__ │ │ ├── contentWarnings.spec.ts │ │ ├── pronounsDisplay.spec.ts │ │ └── spoilerHelpers.spec.ts │ ├── addAccentColors.css │ ├── addColumnButtons.css │ ├── addColumnButtons.ts │ ├── addTweetActions.css │ ├── addTweetActions.ts │ ├── addTweetMenuItems.css │ ├── addTweetMenuItems.ts │ ├── advancedMuteEngine.ts │ ├── allowImagePaste.ts │ ├── alwaysShowCharacterCount.css │ ├── alwaysShowCharacterCount.ts │ ├── autoSwitchThemes.ts │ ├── badgesOnTopOfAvatars.css │ ├── badgesOnTopOfAvatars.ts │ ├── biggerEmoji.css │ ├── biggerEmoji.ts │ ├── blueVerified.css │ ├── blueVerified.ts │ ├── changeAvatarShape.css │ ├── changeAvatarShape.ts │ ├── changeScrollbars.css │ ├── changeScrollbars.ts │ ├── changeTimestampFormat.ts │ ├── changeTweetActions.css │ ├── changeTweetActions.ts │ ├── circleTweetBorder.css │ ├── circleTweetBorder.tsx │ ├── collapseDms.css │ ├── collapseDms.ts │ ├── contentWarnings.css │ ├── contentWarnings.ts │ ├── contentWarningsHelpers.ts │ ├── conversationControl.tsx │ ├── customCss.ts │ ├── emojiAutocompletion.tsx │ ├── emojiPicker.css │ ├── emojiPicker.tsx │ ├── extendTwitterStatus.ts │ ├── extendTwitterUser.ts │ ├── freezeGifsProfilePictures.ts │ ├── gifModals.css │ ├── gifModals.tsx │ ├── hideColumnIcons.css │ ├── hideColumnIcons.ts │ ├── hidePreviewButton.css │ ├── hidePreviewButton.ts │ ├── keepTweetedHashtags.ts │ ├── lightsOut.css │ ├── logoVariations.css │ ├── logoVariations.tsx │ ├── mainStyles.css │ ├── makeSearchColumnsFirst.ts │ ├── mediaWarnings.css │ ├── mediaWarnings.tsx │ ├── modernOverlays.css │ ├── modernOverlays.ts │ ├── muteNfts.css │ ├── muteNfts.ts │ ├── muteTwitterCircle.tsx │ ├── mutesCatcher.tsx │ ├── pauseColumnsOnHover.ts │ ├── profileLabels.ts │ ├── pronounsDisplay.ts │ ├── redraftTweet.ts │ ├── removeRedirection.ts │ ├── renderCardsInColumnsNative.ts │ ├── renderMediaAndQuotedTweets.ts │ ├── replaceHeartsByStars.css │ ├── replaceHeartsByStars.ts │ ├── requireAltImages.css │ ├── requireAltImages.ts │ ├── revertToLegacyReplies.css │ ├── revertToLegacyReplies.ts │ ├── setupGifPicker.tsx │ ├── showAvatarsInColumnsHeader.css │ ├── showAvatarsInColumnsHeader.ts │ ├── showTweetDogEars.css │ ├── showTweetDogEars.ts │ ├── smallerComposerButtons.css │ ├── smallerComposerButtons.ts │ ├── spoilerHelpers.ts │ ├── themeTweaks.ts │ ├── translateLanguageOverride.ts │ ├── twemojiRegex.ts │ ├── updateTabTitle.ts │ ├── updateTwemojiRegex.ts │ ├── useOriginalAspectRatio.css │ ├── useOriginalAspectRatio.ts │ └── usernameDisplay.ts ├── helpers │ ├── asyncHelpers.ts │ ├── browserHelpers.ts │ ├── colorHelpers.ts │ ├── communicationHelpers.ts │ ├── domHelpers.tsx │ ├── emojiHelpers.ts │ ├── hookHelpers.ts │ ├── modalHelpers.tsx │ ├── mustacheHelpers.ts │ ├── networkHelpers.ts │ ├── runtimeTypeHelpers.ts │ ├── tweetdeckHelpers.ts │ ├── typeHelpers.ts │ └── webExtensionHelpers.ts ├── inject.ts ├── options.tsx ├── optionsPage.ts ├── services │ ├── backgroundGifRequests.ts │ ├── backgroundSettings.ts │ ├── chirpHandler.ts │ ├── columnMediaSizeMonitor.ts │ ├── debugMethods.ts │ ├── injectInTD.ts │ ├── monitorBtdModal.ts │ ├── rollbackToLegacy.tsx │ ├── setupBTDNotifications.tsx │ ├── setupBTDRoot.tsx │ └── setupSettings.tsx └── types │ ├── btdCommonTypes.ts │ ├── btdMessageTypes.ts │ ├── btdSettingsEnums.ts │ ├── btdSettingsTypes.ts │ └── tweetdeckTypes.ts ├── tools ├── createDefineConfig.ts ├── generateEmojiMartData.ts ├── generatePronouns.ts ├── latestTag.ts ├── makeMozillaSourceZip.ts ├── manifests │ ├── chrome.js │ ├── common.js │ ├── commonHosts.js │ ├── firefox-beta.js │ ├── firefox.js │ └── safari.js ├── release.ts ├── tsconfig.json ├── update_safari_files.js └── uploadNightly.ts ├── tsconfig.json ├── webpack.config.js └── webpack ├── btdWebpackPlugin.js ├── common.js ├── main.webpack.config.js └── options.webpack.config.js /.eslintignore: -------------------------------------------------------------------------------- 1 | !.eslintrc.js 2 | artifacts/ 3 | dist/ 4 | safari/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['@typescript-eslint', 'unused-imports', 'simple-import-sort'], 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react-hooks/recommended', 8 | 'prettier', 9 | ], 10 | parserOptions: { 11 | ecmaVersion: 2020, 12 | ecmaFeatures: { 13 | jsx: true, 14 | }, 15 | sourceType: 'module', 16 | }, 17 | settings: { 18 | react: { 19 | version: 'detect', 20 | }, 21 | }, 22 | env: { 23 | node: true, 24 | }, 25 | rules: { 26 | 'react-hooks/exhaustive-deps': [ 27 | 'warn', 28 | { 29 | enableDangerousAutofixThisMayCauseInfiniteLoops: true, 30 | }, 31 | ], 32 | }, 33 | overrides: [ 34 | { 35 | files: ['src/**/*'], 36 | env: { 37 | browser: true, 38 | node: false, 39 | }, 40 | }, 41 | { 42 | files: ['*.ts', '*.tsx'], 43 | rules: { 44 | 'react/prop-types': 0, 45 | 'no-redeclare': 0, 46 | 'no-unused-vars': 0, 47 | 'react/display-name': 0, 48 | 'simple-import-sort/imports': 2, 49 | 'unused-imports/no-unused-imports-ts': 2, 50 | 'no-use-before-define': 0, 51 | 'no-undef': 0, 52 | 'no-restricted-globals': 0, 53 | }, 54 | }, 55 | ], 56 | }; 57 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text eol=lf 3 | 4 | # Denote all files that are truly binary and should not be modified. 5 | *.png binary 6 | *.jpg binary 7 | *.gif binary 8 | *.eot binary 9 | *.woff binary 10 | *.ttf binary 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Desktop (please complete the following information):** 28 | 29 | - OS: [e.g. iOS] 30 | - Browser [e.g. chrome, safari] 31 | - Version [e.g. 22] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Disclaimer: I consider Better TweetDeck to be in a feature freeze state due to the impending release of the newer TweetDeck and will instead shift my focus on building an alternative client. As such, I will most likely close/ignore any feature request for the time being. 11 | See the following issue for details https://github.com/eramdam/BetterTweetDeck/issues/848** 12 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the workflow will run 6 | on: 7 | # Triggers the workflow on push or pull request events but only for the main branch 8 | push: 9 | branches: [main, next] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 15 | jobs: 16 | # This workflow contains a single job called "build" 17 | build: 18 | # The type of runner that the job will run on 19 | runs-on: ubuntu-latest 20 | 21 | # Steps represent a sequence of tasks that will be executed as part of the job 22 | steps: 23 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 24 | - uses: actions/checkout@v3 25 | 26 | - name: Setup Node.js environment 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version-file: ".nvmrc" 30 | - run: npm ci 31 | 32 | - name: Typecheck + lint 33 | run: npm test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist/ 4 | web-ext-artifacts/ 5 | build/ 6 | artifacts/* 7 | config/*.json 8 | !config/default.json 9 | 10 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 11 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 12 | # From: https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore 13 | # User-specific stuff: 14 | .idea/**/workspace.xml 15 | .idea/**/tasks.xml 16 | .idea/dictionaries/* 17 | # Sensitive or high-churn files: 18 | .idea/**/dataSources/ 19 | .idea/**/dataSources.ids 20 | .idea/**/dataSources.xml 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | 26 | *.log 27 | *.xcuserstate 28 | *.xcworkspacedata 29 | xcuserdata 30 | .yarn 31 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npm-upgrade.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": { 3 | "chalk": { 4 | "versions": "5.0.1", 5 | "reason": "" 6 | }, 7 | "execa": { 8 | "versions": "6.*.*", 9 | "reason": "ESM" 10 | }, 11 | "moduleraid": { 12 | "versions": "6.*.*", 13 | "reason": "not needed" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | dist/ 3 | package.json 4 | public/*.html 5 | safari/ 6 | emoji-mart-data.json -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "printWidth": 100, 6 | "singleQuote": true, 7 | "bracketSpacing": false, 8 | "bracketSameLine": true, 9 | "arrowParens": "always", 10 | "overrides": [ 11 | { 12 | "files": "*.css", 13 | "options": { 14 | "printWidth": 900 15 | } 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["lokalise.i18n-ally", "dbaeumer.vscode-eslint"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/i18n-ally-custom-framework.yml: -------------------------------------------------------------------------------- 1 | # An array of strings which contain Language Ids defined by VS Code 2 | # You can check avaliable language ids here: https://code.visualstudio.com/docs/languages/overview#_language-id 3 | languageIds: 4 | - javascript 5 | - typescript 6 | - javascriptreact 7 | - typescriptreact 8 | 9 | # An array of RegExes to find the key usage. **The key should be captured in the first match group**. 10 | # You should unescape RegEx strings in order to fit in the YAML file 11 | # To help with this, you can use https://www.freeformatter.com/json-escape.html 12 | usageMatchRegex: 13 | # The following example shows how to detect `t("your.i18n.keys")` 14 | # the `{key}` will be placed by a proper keypath matching regex, 15 | # you can ignore it and use your own matching rules as well 16 | - 'Trans[\t\r\s]+id=[''"`]({key})[''"`]' 17 | - "getTransString\\('({key})'\\)" 18 | - '__MSG_({key})__' 19 | 20 | # An array of strings containing refactor templates. 21 | # The "$1" will be replaced by the keypath specified. 22 | # Optional: uncomment the following two lines to use 23 | 24 | refactorTemplates: 25 | - i18n.get("$1") 26 | - 27 | - getTransString('$1') 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "explicit" 4 | }, 5 | "editor.formatOnSave": true, 6 | "editor.defaultFormatter": "esbenp.prettier-vscode", 7 | "[css]": { 8 | "editor.formatOnSave": true 9 | }, 10 | "[json]": { 11 | "editor.formatOnSave": true, 12 | "editor.defaultFormatter": "vscode.json-language-features" 13 | }, 14 | "[markdown]": { 15 | "editor.formatOnSave": true 16 | }, 17 | "emmet.excludeLanguages": [], 18 | "emmet.includeLanguages": { 19 | "javascript": "javascriptreact", 20 | "markdown": "javascriptreact", 21 | "typescript": "typescriptreact" 22 | }, 23 | "files.eol": "\n", 24 | "files.exclude": { 25 | "**/.DS_Store": true, 26 | "**/.git": true, 27 | "**/.hg": true, 28 | "**/.svn": true, 29 | "**/CVS": true, 30 | ".cache-loader": true 31 | }, 32 | "i18n-ally.enabledFrameworks": ["chrome-ext", "custom"], 33 | "i18n-ally.extract.keyPrefix": "settings_", 34 | "i18n-ally.keystyle": "nested", 35 | "i18n-ally.localesPaths": ["src/_locales"], 36 | "i18n-ally.preferredDelimiter": "_", 37 | "movets.skipWarning": true, 38 | "search.exclude": { 39 | "**/bower_components": true, 40 | "**/node_modules": true 41 | }, 42 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false, 43 | "typescript.preferences.useAliasesForRenames": false, 44 | "typescript.tsdk": "node_modules/typescript/lib" 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Damien Erambert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://raw.githubusercontent.com/eramdam/BetterTweetDeck/master/meta/better.tw_.png) 2 | 3 |

Better TweetDeck

4 | 5 | This fork works with [OldTweetDeck](https://github.com/dimdenGD/OldTweetDeck)! Install the same way as you did with OldTweetDeck. [Releases page](https://github.com/dimdenGD/BetterTweetDeck/releases). 6 | -------------------------------------------------------------------------------- /artifacts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/artifacts/.gitkeep -------------------------------------------------------------------------------- /config/default.json: -------------------------------------------------------------------------------- 1 | { 2 | "FirefoxId": "BetterTweetDeckDev@erambert.me", 3 | "Client": { 4 | "debug": false, 5 | "APIs": { 6 | "giphy": "", 7 | "tenor": "" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /src/_locales/en/*.json 3 | translation: /src/_locales/%two_letters_code%/%original_file_name% 4 | -------------------------------------------------------------------------------- /definitions/assets.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | const content: string; 3 | export default content; 4 | } 5 | 6 | declare module '*.png' { 7 | const content: string; 8 | export default content; 9 | } 10 | -------------------------------------------------------------------------------- /definitions/btdGlobals.d.ts: -------------------------------------------------------------------------------- 1 | import ModuleRaid from 'moduleraid'; 2 | 3 | export {}; 4 | 5 | declare global { 6 | interface Window { 7 | BTD?: { 8 | debug?: { 9 | jq?: JQueryStatic; 10 | mR: ModuleRaid; 11 | findMustache: typeof findMustache; 12 | getChirpFromElement: typeof getChirpFromElement; 13 | getChirpFromKey: typeof getChirpFromKey; 14 | getChirpFromKeyAlone: typeof getChirpFromKeyAlone; 15 | clearMuteCatches: typeof clearMuteCatches; 16 | }; 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /definitions/globals.d.ts: -------------------------------------------------------------------------------- 1 | interface DOMRectReadOnly { 2 | readonly x: number; 3 | readonly y: number; 4 | readonly width: number; 5 | readonly height: number; 6 | readonly top: number; 7 | readonly right: number; 8 | readonly bottom: number; 9 | readonly left: number; 10 | } 11 | 12 | declare global {} 13 | 14 | interface ResizeObserverCallback { 15 | (entries: ResizeObserverEntry[], observer: ResizeObserver): void; 16 | } 17 | 18 | interface ResizeObserverEntry { 19 | readonly target: Element; 20 | readonly contentRect: DOMRectReadOnly; 21 | } 22 | 23 | interface ResizeObserver { 24 | observe(target: Element): void; 25 | unobserve(target: Element): void; 26 | disconnect(): void; 27 | } 28 | 29 | declare var ResizeObserver: { 30 | prototype: ResizeObserver; 31 | new (callback: ResizeObserverCallback): ResizeObserver; 32 | }; 33 | -------------------------------------------------------------------------------- /definitions/pronouns/index.d.ts: -------------------------------------------------------------------------------- 1 | // https://github.com/katacarbix/pronouns.js/pull/11/ 2 | declare module 'pronouns' { 3 | export type Pronoun = [ 4 | subject: string, 5 | object: string, 6 | determiner: string, 7 | possessive: string, 8 | reflexive: string 9 | ]; 10 | export type PartialPronoun = [string, string?, string?, string?, string?]; 11 | 12 | export interface Pronouns { 13 | pronouns: Pronoun[]; 14 | examples: Pronoun[]; 15 | 16 | subject: string; 17 | object: string; 18 | determiner: string; 19 | possessive: string; 20 | reflexive: string; 21 | 22 | sub: string; 23 | obj: string; 24 | det: string; 25 | pos: string; 26 | ref: string; 27 | 28 | constructor(input: string): void; 29 | 30 | generateForms(i: number): void; 31 | generateExamples(): void; 32 | toString(): string; 33 | toUrl(): string; 34 | add(input: string): void; 35 | } 36 | 37 | export default function (input: string, log?: boolean): Pronouns; 38 | 39 | export function complete(input: string): string[]; 40 | 41 | export const table: Pronoun[]; 42 | 43 | interface Util { 44 | logging: boolean; 45 | tableFrontFilter: (q: PartialPronoun, table: Pronoun[]) => Pronoun[]; 46 | tableEndFilter: (q: PartialPronoun, table: Pronoun[]) => Pronoun[]; 47 | tableLookup: (q: PartialPronoun, table: Pronoun[]) => Pronoun | undefined; 48 | shortestUnambiguousForwardPath: (table: Pronoun[], row: PartialPronoun) => PartialPronoun; 49 | shortestUnambiguousEllipsesPath: (table: Pronoun[], row: PartialPronoun) => PartialPronoun; 50 | shortestUnambiguousPath: (table: Pronoun[], row: PartialPronoun) => PartialPronoun; 51 | abbreviate: (table: Pronoun[]) => string[][]; 52 | sanitizeSet: (p: PartialPronoun[], table: Pronoun[]) => Pronoun[]; 53 | expandString: (str: string, table: Pronoun[]) => Pronoun[]; 54 | arrFormat: (x: T | T[]) => T[]; 55 | capitalize: (str: string) => string; 56 | rowsEqual: (a: PartialPronoun, b: Pronoun) => boolean; 57 | } 58 | 59 | export const util: Util; 60 | 61 | export const abbreviated: string[][]; 62 | } 63 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | module.exports = { 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | globals: {'ts-jest': {isolatedModules: true}}, 6 | }; 7 | -------------------------------------------------------------------------------- /meta/better.tw_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/meta/better.tw_.png -------------------------------------------------------------------------------- /meta/debug-infos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/meta/debug-infos.png -------------------------------------------------------------------------------- /meta/en_desc.md: -------------------------------------------------------------------------------- 1 | Improve your experience on TweetDeck web with tons of features! 2 | 3 | More informations on https://better.tw 4 | 5 | Report bugs here: 6 | https://github.com/eramdam/BetterTweetDeck/issues 7 | 8 | Source code: 9 | https://github.com/eramdam/BetterTweetDeck 10 | 11 | Follow @BetterTDeck on Twitter for news/support 12 | -------------------------------------------------------------------------------- /meta/hotfixes.css: -------------------------------------------------------------------------------- 1 | /** 2 | * This whole file is going to be embedded into Better TweetDeck as a "hotfix" file. 3 | * 4 | * Don't. 5 | * 6 | * Mess. 7 | * 8 | * Up. 9 | * 10 | * Anything. 11 | * 12 | * In. 13 | * 14 | * There. 15 | * 16 | * Please. 17 | * 18 | * Thanks :) 19 | */ 20 | 21 | .js-add-emojis.padding-v--9.js-add-emojis { 22 | padding-top: 6px !important; 23 | padding-left: 12px !important; 24 | padding-right: 12px !important; 25 | padding-bottom: 5px !important; 26 | } 27 | 28 | .js-add-emojis.padding-v--9.js-add-emojis .btd-emoji-icon { 29 | font-size: 18px !important; 30 | } 31 | 32 | .btd__small_icns_compose .js-add-emojis.padding-v--9.js-add-emojis .btd-emoji-icon { 33 | transform: translateY(-2px); 34 | } 35 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari Extension/Better_TweetDeck_for_Safari_Extension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Better TweetDeck for Safari Extension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | 2312181630 23 | ITSAppUsesNonExemptEncryption 24 | 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSExtension 28 | 29 | NSExtensionPointIdentifier 30 | com.apple.Safari.web-extension 31 | NSExtensionPrincipalClass 32 | $(PRODUCT_MODULE_NAME).SafariWebExtensionHandler 33 | 34 | 35 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari Extension/SafariWebExtensionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariWebExtensionHandler.swift 3 | // Better TweetDeck for Safari Extension 4 | // 5 | // Created by Damien Erambert on 1/16/21. 6 | // 7 | 8 | import SafariServices 9 | import os.log 10 | 11 | let SFExtensionMessageKey = "message" 12 | 13 | class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { 14 | 15 | func beginRequest(with context: NSExtensionContext) { 16 | let item = context.inputItems[0] as! NSExtensionItem 17 | let message = item.userInfo?[SFExtensionMessageKey] 18 | os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg) 19 | 20 | let response = NSExtensionItem() 21 | response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ] 22 | 23 | context.completeRequest(returningItems: [response], completionHandler: nil) 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Better TweetDeck for Safari 4 | // 5 | // Created by Damien Erambert on 1/16/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | @main 11 | class AppDelegate: NSObject, NSApplicationDelegate { 12 | 13 | func applicationDidFinishLaunching(_ notification: Notification) { 14 | // Insert code here to initialize your application 15 | } 16 | 17 | func applicationWillTerminate(_ notification: Notification) { 18 | // Insert code here to tear down your application 19 | } 20 | 21 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 22 | return true 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon-32.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon-32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon-64.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon-128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon-256.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon-256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon-512.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon-512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon-1024.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-1024.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-128.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-16.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-256.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-32.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-512.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/AppIcon.appiconset/icon-64.png -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Better_TweetDeck_for_Safari.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | 2312181630 23 | ITSAppUsesNonExemptEncryption 24 | 25 | LSApplicationCategoryType 26 | public.app-category.social-networking 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/Better TweetDeck for Safari/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Better TweetDeck for Safari 4 | // 5 | // Created by Damien Erambert on 1/16/21. 6 | // 7 | 8 | import Cocoa 9 | import SafariServices.SFSafariApplication 10 | import SafariServices.SFSafariExtensionManager 11 | 12 | let appName = "Better TDeck for TweetDeck" 13 | let extensionBundleIdentifier = "me.erambert.bettertweetdeck-safari.extension" 14 | 15 | class ViewController: NSViewController { 16 | 17 | @IBOutlet var appNameLabel: NSTextField! 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | self.appNameLabel.stringValue = appName 22 | SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionBundleIdentifier) { (state, error) in 23 | guard let state = state, error == nil else { 24 | // Insert code to inform the user that something went wrong. 25 | return 26 | } 27 | 28 | DispatchQueue.main.async { 29 | if (state.isEnabled) { 30 | self.appNameLabel.stringValue = "\(appName)'s extension is currently on." 31 | } else { 32 | self.appNameLabel.stringValue = "\(appName)'s extension is currently off. You can turn it on in Safari Extensions preferences." 33 | } 34 | } 35 | } 36 | } 37 | 38 | @IBAction func openSafariExtensionPreferences(_ sender: AnyObject?) { 39 | SFSafariApplication.showPreferencesForExtension(withIdentifier: extensionBundleIdentifier) { error in 40 | guard error == nil else { 41 | // Insert code to inform the user that something went wrong. 42 | return 43 | } 44 | 45 | DispatchQueue.main.async { 46 | NSApplication.shared.terminate(nil) 47 | } 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /safari/Better TweetDeck for Safari/BetterTDeck for TweetDeck.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/_locales/cs/messages.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /src/_locales/nl/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "app_desc": { 3 | "message": "Neem TweetDeck naar het volgende level!" 4 | }, 5 | "app_name": { 6 | "message": "Better TweetDeck" 7 | }, 8 | "settings_title": { 9 | "message": "Better TweetDeck" 10 | }, 11 | "settings_show_cards_inside_columns": { 12 | "message": "Toon tweet kaarten in kolommen" 13 | }, 14 | "settings_show_profile_badges_on_top_of_avatars": { 15 | "message": "Toon profielbadges boven aan avatars" 16 | }, 17 | "settings_collapse_read_dms": { 18 | "message": "Gelezen privéberichten inklappen" 19 | }, 20 | "settings_freeze_gifs_in_profile_pictures": { 21 | "message": "GIFs bevriezen in profielfoto's" 22 | }, 23 | "settings_remove_t_co_redirection_on_links": { 24 | "message": "Verwijder t.co omleiding op links" 25 | }, 26 | "settings_make_buttons_smaller_in_the_composer": { 27 | "message": "Knoppen kleiner maken in het opstelvenster" 28 | }, 29 | "settings_reflect_new_tweets_and_dms_in_the_tabs_title": { 30 | "message": "Nieuwe tweets en DMs in de tab titel reflecteren" 31 | }, 32 | "settings_auto_switch_light_theme": { 33 | "message": "Schakel over naar lichte thema wanneer OS in licht-modus is" 34 | }, 35 | "settings_scrollbar_default": { 36 | "message": "Standaard" 37 | }, 38 | "settings_scrollbar_hidden": { 39 | "message": "Verborgen" 40 | }, 41 | "settings_style_of_scrollbars": { 42 | "message": "Stijl van de schuifbalken" 43 | }, 44 | "settings_show_clear_button_column": { 45 | "message": "Toon de \"Wissen\" knop in kolomkop" 46 | }, 47 | "settings_show_collapse_button_in_columns_header": { 48 | "message": "Toon de \"Wissen\" knop in kolomkop" 49 | }, 50 | "settings_hide_icons_on_top_of_columns": { 51 | "message": "Pictogrammen op de bovenkant van kolommen verbergen" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/assets/accent-colors/any.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/accent-colors/blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/accent-colors/green.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/accent-colors/pink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/accent-colors/purple.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/accent-colors/rainbow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/assets/btd-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-logo-small.png -------------------------------------------------------------------------------- /src/assets/btd-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-logo.png -------------------------------------------------------------------------------- /src/assets/btd-stars/btd-stars.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-stars/btd-stars.eot -------------------------------------------------------------------------------- /src/assets/btd-stars/btd-stars.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-stars/btd-stars.ttf -------------------------------------------------------------------------------- /src/assets/btd-stars/btd-stars.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-stars/btd-stars.woff -------------------------------------------------------------------------------- /src/assets/btd-stars/btd-stars.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/btd-stars/btd-stars.woff2 -------------------------------------------------------------------------------- /src/assets/column-preview/clear-btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/column-preview/clear-btn.png -------------------------------------------------------------------------------- /src/assets/column-preview/collapse-btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/column-preview/collapse-btn.png -------------------------------------------------------------------------------- /src/assets/column-preview/column-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/column-preview/column-bg.png -------------------------------------------------------------------------------- /src/assets/column-preview/no-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/column-preview/no-icon.png -------------------------------------------------------------------------------- /src/assets/dark-themes/default-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dark-themes/default-dark.png -------------------------------------------------------------------------------- /src/assets/dark-themes/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dark-themes/light.png -------------------------------------------------------------------------------- /src/assets/dark-themes/lights-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dark-themes/lights-out.png -------------------------------------------------------------------------------- /src/assets/dark-themes/old-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dark-themes/old-dark.png -------------------------------------------------------------------------------- /src/assets/dogears/fav-heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dogears/fav-heart.png -------------------------------------------------------------------------------- /src/assets/dogears/fav-rt-heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dogears/fav-rt-heart.png -------------------------------------------------------------------------------- /src/assets/dogears/fav-rt-star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dogears/fav-rt-star.png -------------------------------------------------------------------------------- /src/assets/dogears/fav-star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dogears/fav-star.png -------------------------------------------------------------------------------- /src/assets/dogears/rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/dogears/rt.png -------------------------------------------------------------------------------- /src/assets/emoji-sheet-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/emoji-sheet-64.png -------------------------------------------------------------------------------- /src/assets/filledStar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/heart-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/hexagone-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/hexagone-mask.png -------------------------------------------------------------------------------- /src/assets/icons/icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-1024.png -------------------------------------------------------------------------------- /src/assets/icons/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-128.png -------------------------------------------------------------------------------- /src/assets/icons/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-16.png -------------------------------------------------------------------------------- /src/assets/icons/icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-256.png -------------------------------------------------------------------------------- /src/assets/icons/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-32.png -------------------------------------------------------------------------------- /src/assets/icons/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-48.png -------------------------------------------------------------------------------- /src/assets/icons/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-512.png -------------------------------------------------------------------------------- /src/assets/icons/icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-64.png -------------------------------------------------------------------------------- /src/assets/icons/icon-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-96.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-1024.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-128.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-16.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-256.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-32.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-48.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-512.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-64.png -------------------------------------------------------------------------------- /src/assets/icons/icon-beta-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/icon-beta-96.png -------------------------------------------------------------------------------- /src/assets/icons/toolbar-icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/toolbar-icon-16.png -------------------------------------------------------------------------------- /src/assets/icons/toolbar-icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimdenGD/BetterTweetDeck/641e4901108dfa7526340d78b7ce5a910de435fd/src/assets/icons/toolbar-icon-32.png -------------------------------------------------------------------------------- /src/assets/logo-tweaks/agender.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/androgyne.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/aromantic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/asexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/bigender.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/bisexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/btd.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/demigirl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/demiguy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/deminonbinary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/demisexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/enbian.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/genderfluid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/genderqueer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/lesbian.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/neutrois.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/non binary.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/omnisexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/pansexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/polyamory.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/polysexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/progress.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/rainbow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/logo-tweaks/trans.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/mutual-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/fullscreenModalWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React, {FC, ReactNode} from 'react'; 2 | 3 | import {Handler} from '../helpers/typeHelpers'; 4 | 5 | interface FullscreenModalWrapperProps { 6 | onClose: Handler; 7 | children: ReactNode; 8 | } 9 | 10 | export const FullscreenModal: FC = (props) => { 11 | return ( 12 |
13 |
14 |
15 | 20 | 21 | 22 |
28 |
29 |
30 |
38 | {props.children} 39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 | ); 49 | }; 50 | -------------------------------------------------------------------------------- /src/components/gifButton.css: -------------------------------------------------------------------------------- 1 | .btd-gif-button { 2 | transition-property: transform, opacity; 3 | transition-duration: 300ms; 4 | transition-timing-function: ease; 5 | float: left; 6 | 7 | &.-visible { 8 | opacity: 1; 9 | transform: translateX(0); 10 | } 11 | } 12 | 13 | .btd-gif-button { 14 | font-weight: bold; 15 | font-size: 10px; 16 | border-radius: 3px; 17 | padding: 2px 6px; 18 | border: 1px solid currentColor; 19 | cursor: pointer; 20 | overflow: hidden; 21 | position: absolute; 22 | left: 10px; 23 | bottom: 10px; 24 | z-index: 0; 25 | opacity: 0; 26 | transition-property: color, opacity; 27 | user-select: none; 28 | pointer-events: none; 29 | 30 | &:hover { 31 | color: #616161 !important; 32 | } 33 | } 34 | 35 | .btd-gif-button.-visible { 36 | opacity: 1; 37 | pointer-events: auto; 38 | } 39 | 40 | .btd-gif-button.btd-gif-button:hover { 41 | color: #616161; 42 | } 43 | -------------------------------------------------------------------------------- /src/components/gifPicker/gifButton.tsx: -------------------------------------------------------------------------------- 1 | import '../gifButton.css'; 2 | 3 | import React, {FC} from 'react'; 4 | 5 | import {Handler} from '../../helpers/typeHelpers'; 6 | 7 | export const BTDGifButton: FC<{ 8 | onClick: Handler; 9 | }> = (props) => { 10 | const d = new Date(); 11 | const fool = d.getDate() === 1 && d.getMonth() === 3; 12 | const GIFText = fool ? 'JIF' : 'GIF'; 13 | 14 | return ( 15 | 16 | {GIFText} 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /src/components/gifPicker/singleGif.tsx: -------------------------------------------------------------------------------- 1 | import React, {FC} from 'react'; 2 | 3 | import {Handler} from '../../helpers/typeHelpers'; 4 | 5 | export interface GifItemProps { 6 | previewUrl: string; 7 | onClick: Handler; 8 | } 9 | export const BTDGifItem: FC = (props) => { 10 | return ( 11 |
15 | 24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /src/components/openBtdSettingsButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const BTDSettingsButton = () => { 4 | return ( 5 | 9 |
10 | 11 |
12 |
13 | BTD Settings 14 |
15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /src/components/settings/components/badgesOnTopOfAvatars.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import {BaseSettingsProps} from '../settingsTypes'; 4 | import {BooleanSettingsRow} from './booleanSettingRow'; 5 | 6 | interface BadgesOnTopOfAvatarsProps extends BaseSettingsProps<'badgesOnTopOfAvatars'> {} 7 | 8 | export function BadgesOnTopOfAvatars(props: BadgesOnTopOfAvatarsProps) { 9 | return ( 10 | 14 | Show badges on top of avatars 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/settings/components/booleanSettingRow.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React, {PropsWithChildren} from 'react'; 3 | 4 | import {HandlerOf} from '../../../helpers/typeHelpers'; 5 | import {useSettingsSearch} from '../settingsContext'; 6 | import {reactElementToString} from '../settingsHelpers'; 7 | import {settingsDisabled} from '../settingsStyles'; 8 | import {featureBadgeClassname, NewFeatureBadge, NewFeatureBadgeProps} from './newFeatureBadge'; 9 | import {SettingsRow, SettingsRowContent} from './settingsRow'; 10 | import {SettingsToggle} from './settingsToggle'; 11 | 12 | interface BooleanSettingsRowProps extends Partial { 13 | initialValue: boolean; 14 | onChange: HandlerOf; 15 | settingsKey: string; 16 | className?: string; 17 | alignToTheLeft?: boolean; 18 | noPaddingTop?: boolean; 19 | disabled?: boolean; 20 | ignoreInSearch?: boolean; 21 | } 22 | 23 | export function BooleanSettingsRow(props: PropsWithChildren) { 24 | const {renderAndAddtoIndex} = useSettingsSearch(); 25 | const render = () => ( 26 | 30 | 39 | 44 | {props.children} 45 | {props.introducedIn && ( 46 | 47 | )} 48 | 49 | 50 | 51 | ); 52 | 53 | if (!props.ignoreInSearch) { 54 | renderAndAddtoIndex({ 55 | keywords: [reactElementToString(props.children)], 56 | key: props.settingsKey, 57 | render: () => render(), 58 | }); 59 | } 60 | 61 | return render(); 62 | } 63 | -------------------------------------------------------------------------------- /src/components/settings/components/newFeatureBadge.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React, {FC, useMemo} from 'react'; 3 | import semver from 'semver'; 4 | 5 | import {getExtensionVersion} from '../../../helpers/webExtensionHelpers'; 6 | 7 | export interface NewFeatureBadgeProps { 8 | introducedIn: string; 9 | } 10 | 11 | const currentVersion = semver.coerce(getExtensionVersion()); 12 | 13 | export const featureBadgeClassname = 'btd-feature-badge'; 14 | 15 | export const NewFeatureBadge: FC = (props) => { 16 | const featureVersion = semver.coerce(props.introducedIn); 17 | const maxMinorDiff = 3; 18 | 19 | const isOutdated = useMemo(() => { 20 | if (!currentVersion || !featureVersion) { 21 | return true; 22 | } 23 | 24 | if (currentVersion.major > featureVersion.major) { 25 | return true; 26 | } 27 | 28 | const minorDiff = currentVersion.minor - featureVersion.minor; 29 | if (minorDiff > maxMinorDiff) { 30 | return true; 31 | } 32 | 33 | return false; 34 | }, [featureVersion, maxMinorDiff]); 35 | 36 | if (isOutdated) { 37 | return null; 38 | } 39 | 40 | return ( 41 | 58 | NEW 59 | 60 | ); 61 | }; 62 | -------------------------------------------------------------------------------- /src/components/settings/components/radioSelectSettingsRow.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React, {PropsWithChildren} from 'react'; 3 | 4 | import {BTDSettings} from '../../../types/btdSettingsTypes'; 5 | import {useSettingsSearch} from '../settingsContext'; 6 | import {reactElementToString} from '../settingsHelpers'; 7 | import {SettingsRadioSettingSelect, SettingsRadioSettingsSelectProps} from './settingsRadioSelect'; 8 | import {SettingsRow, SettingsRowContent, SettingsRowTitle} from './settingsRow'; 9 | 10 | function RadioSelectSettingsRow( 11 | props: PropsWithChildren> 12 | ) { 13 | return ( 14 | 25 | {props.children} 26 | 32 | 33 | settingsKey={props.settingsKey} 34 | onChange={props.onChange} 35 | initialValue={props.initialValue} 36 | fields={props.fields} 37 | /> 38 | 39 | 40 | ); 41 | } 42 | 43 | export function BTDRadioSelectSettingsRow( 44 | props: PropsWithChildren> 45 | ) { 46 | const {renderAndAddtoIndex} = useSettingsSearch(); 47 | return ( 48 | <> 49 | {renderAndAddtoIndex({ 50 | key: props.settingsKey, 51 | keywords: props.fields.map((f) => reactElementToString(f.searchTerm || f.label)), 52 | render: (newSettings) => 53 | RadioSelectSettingsRow({...props, initialValue: newSettings[props.settingsKey]}), 54 | })} 55 | 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsButton.tsx: -------------------------------------------------------------------------------- 1 | import React, {PropsWithChildren} from 'react'; 2 | 3 | import {Handler} from '../../../helpers/typeHelpers'; 4 | 5 | interface SettingsButtonProps { 6 | onClick: Handler; 7 | variant?: 'primary' | 'secondary'; 8 | disabled?: boolean; 9 | } 10 | export function SettingsButton(props: PropsWithChildren) { 11 | return ( 12 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsCss.tsx: -------------------------------------------------------------------------------- 1 | import React, {FC} from 'react'; 2 | 3 | import {BTDSettings} from '../../../types/btdSettingsTypes'; 4 | import {getTransString} from '../../trans'; 5 | import {SettingsMenuSectionProps} from '../settingsComponents'; 6 | import {useSettingsSearch} from '../settingsContext'; 7 | import {SettingsCssEditor} from './settingsCssEditor'; 8 | 9 | export const SettingsCss: FC = (props) => { 10 | const {makeOnSettingsChange, setEditorHasErrors} = props; 11 | const {renderAndAddtoIndex} = useSettingsSearch(); 12 | const renderEditor = (newSettings: BTDSettings) => ( 13 | makeOnSettingsChange('customCss')(val)} 15 | onErrorChange={setEditorHasErrors} 16 | value={newSettings.customCss}> 17 | ); 18 | 19 | return ( 20 | <> 21 | {renderAndAddtoIndex({ 22 | key: 'custom_css', 23 | keywords: [getTransString('settings_custom_css')], 24 | render: renderEditor, 25 | })} 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsModalComponents.tsx: -------------------------------------------------------------------------------- 1 | import {cx} from '@emotion/css'; 2 | import React, {PropsWithChildren} from 'react'; 3 | 4 | type defaultProps = PropsWithChildren<{}>; 5 | 6 | export function SettingsModalWrapper(props: defaultProps) { 7 | return
{props.children}
; 8 | } 9 | export function SettingsHeader(props: defaultProps) { 10 | return
{props.children}
; 11 | } 12 | export function SettingsSidebar(props: defaultProps) { 13 | return
{props.children}
; 14 | } 15 | export function SettingsContent(props: defaultProps) { 16 | return
{props.children}
; 17 | } 18 | export function SettingsFooter( 19 | props: defaultProps & { 20 | className?: string; 21 | } 22 | ) { 23 | return
{props.children}
; 24 | } 25 | export function SettingsFooterLabel(props: defaultProps) { 26 | return
{props.children}
; 27 | } 28 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsRadioInput.tsx: -------------------------------------------------------------------------------- 1 | import {css} from '@emotion/css'; 2 | import React, {PropsWithChildren} from 'react'; 3 | 4 | import {Handler} from '../../../helpers/typeHelpers'; 5 | 6 | const mainInputStyles = css` 7 | appearance: none; 8 | width: 15px; 9 | height: 15px; 10 | border: 1px solid var(--twitter-blue); 11 | background: transparent; 12 | outline: 0; 13 | border-radius: 100%; 14 | 15 | &:checked, 16 | &[checked] { 17 | box-shadow: inset 0 0 0 3px var(--settings-modal-background), 18 | inset 0 0 0 8px var(--twitter-blue); 19 | } 20 | `; 21 | 22 | interface SettingsRadioSelectFieldProps { 23 | name: string; 24 | id: string; 25 | defaultChecked: boolean; 26 | onChange: Handler; 27 | className?: string; 28 | isDisabled?: boolean; 29 | } 30 | export function SettingsRadioInput(props: PropsWithChildren) { 31 | return ( 32 | 33 | 42 | 43 | 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsRadioSelect.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React, {ReactNode} from 'react'; 3 | 4 | import {HandlerOf} from '../../../helpers/typeHelpers'; 5 | import {BTDSettings} from '../../../types/btdSettingsTypes'; 6 | import {settingsDisabled} from '../settingsStyles'; 7 | import {SettingsRadioInput} from './settingsRadioInput'; 8 | 9 | export interface SettingsRadioSettingsSelectProps { 10 | fields: ReadonlyArray<{ 11 | label: ReactNode; 12 | searchTerm?: string; 13 | value: S[T]; 14 | }>; 15 | initialValue: S[T]; 16 | settingsKey: T; 17 | onChange: HandlerOf; 18 | ignoreSearch?: boolean; 19 | className?: string; 20 | isDisabled?: boolean; 21 | } 22 | 23 | const wrapperStyles = css` 24 | padding-top: 4px; 25 | display: grid; 26 | grid-auto-flow: row; 27 | grid-row-gap: 10px; 28 | grid-auto-columns: 100%; 29 | 30 | input + label { 31 | padding-left: 10px; 32 | } 33 | `; 34 | 35 | export function SettingsRadioSettingSelect( 36 | props: SettingsRadioSettingsSelectProps 37 | ) { 38 | return ( 39 |
40 | {props.fields.map((field) => { 41 | return ( 42 | props.onChange(field.value)} 48 | isDisabled={props.isDisabled}> 49 | {field.label} 50 | 51 | ); 52 | })} 53 |
54 | ); 55 | } 56 | 57 | export function BTDSettingsRadioSettingSelect( 58 | props: SettingsRadioSettingsSelectProps 59 | ) { 60 | return SettingsRadioSettingSelect(props); 61 | } 62 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsRow.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React from 'react'; 3 | import {PropsWithChildren} from 'react'; 4 | 5 | import {settingsDisabled, settingsRow, settingsRowTitle} from '../settingsStyles'; 6 | 7 | type SettingsRowProps = PropsWithChildren<{className?: string}>; 8 | 9 | export function SettingsRow( 10 | props: SettingsRowProps & {disabled?: boolean; stretch?: boolean; noPaddingTop?: boolean} 11 | ) { 12 | const stretch = props.stretch ?? true; 13 | return ( 14 |
28 | {props.children} 29 |
30 | ); 31 | } 32 | export function SettingsRowTitle(props: SettingsRowProps) { 33 | return

{props.children}

; 34 | } 35 | export function SettingsRowContent(props: SettingsRowProps) { 36 | return
{props.children}
; 37 | } 38 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsSeparator.tsx: -------------------------------------------------------------------------------- 1 | import {css} from '@emotion/css'; 2 | import React from 'react'; 3 | 4 | import {settingsRow} from '../settingsStyles'; 5 | 6 | export function SettingsSeparator() { 7 | return ( 8 |
21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /src/components/settings/components/settingsTextInput.tsx: -------------------------------------------------------------------------------- 1 | import {css, cx} from '@emotion/css'; 2 | import React from 'react'; 3 | 4 | import {HandlerOf} from '../../../helpers/typeHelpers'; 5 | 6 | export interface SettingsTextInputProps { 7 | placeholder?: string; 8 | className?: string; 9 | value: string; 10 | onChange: HandlerOf; 11 | isDisabled?: boolean; 12 | } 13 | 14 | const commonStyles = css` 15 | background: var(--twitter-input-bg); 16 | color: var(--settings-modal-text); 17 | border: 1px solid var(--twitter-input-border-color); 18 | display: inline-block; 19 | padding: 4px 8px; 20 | font-size: 13px; 21 | line-height: 18px; 22 | border-radius: 4px; 23 | 24 | &::placeholder { 25 | color: var(--twitter-input-placeholder); 26 | } 27 | 28 | &:focus { 29 | outline: 0; 30 | border-color: rgba(29, 161, 242, 0.8); 31 | box-shadow: inset 0 1px 3px rgba(20, 23, 26, 0.1), 0 0 8px rgba(29, 161, 242, 0.6); 32 | } 33 | `; 34 | 35 | export function SettingsTextarea(props: SettingsTextInputProps) { 36 | return ( 37 |