From 1f11f1b068be68cb846056223eca15d40cfee776 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Wed, 15 Jan 2025 15:49:50 +0100 Subject: [PATCH] chore: Migrate to tailwind --- .babelrc | 2 +- .dockerignore | 1 - .gitignore | 1 - .sass-lint.yml | 95 - README.md | 1 - app/API/no_internet_error.js | 16 +- app/App.jsx | 6 +- app/components/App/LanguageSelector.jsx | 41 +- app/components/App/Layout.jsx | 32 +- app/components/App/Logo.jsx | 8 +- app/components/App/Navbar.jsx | 30 +- app/components/App/Sidebar.jsx | 145 +- app/components/Help/Help.jsx | 70 +- app/components/Help/HelpPageContent.jsx | 83 +- app/components/Home/CFSocialProfiles.jsx | 84 +- app/components/Home/Home.jsx | 330 +- .../Pages/BrowserExtensionsPage.jsx | 135 +- app/components/Search/SearchBox.js | 4 +- .../Users/InvitationRequestForm.jsx | 5 +- app/components/Utils/FlashMessages.jsx | 131 - app/components/Utils/index.js | 1 - app/components/ui/button.tsx | 50 + app/components/ui/card.tsx | 55 + app/components/ui/select.tsx | 157 + app/components/ui/toast.tsx | 127 + app/components/ui/toaster.tsx | 33 + app/constants.js | 3 - app/hooks/use-toast.ts | 194 + app/i18n/ar/home.json | 33 +- app/i18n/en/home.json | 3 +- app/i18n/es/home.json | 1 - app/i18n/fr/extension.json | 2 +- app/i18n/fr/home.json | 9 +- app/i18n/nb_NO/home.json | 33 +- app/i18n/pt_BR/home.json | 1 - app/i18n/pt_PT/home.json | 33 +- app/i18n/ru/home.json | 3 +- app/lib/css-utils.js | 6 + app/state/flashes/record.js | 23 - app/state/flashes/reducer.js | 66 +- app/state/index.js | 2 - app/styles/_components/App/app.sass | 12 - app/styles/_components/App/logo.sass | 18 - app/styles/_components/App/sidebar.sass | 121 - .../Moderation/flag_reason_select.sass | 5 - .../_components/Moderation/moderation.sass | 25 - .../_components/Pages/browser_extensions.sass | 20 - app/styles/_components/Pages/home_page.sass | 235 - .../_components/Speakers/speaker_page.sass | 14 - .../_components/Speakers/speaker_preview.sass | 21 - app/styles/_components/User/achievements.sass | 41 - app/styles/_components/User/activity_log.sass | 4 - app/styles/_components/User/authenticate.sass | 10 - app/styles/_components/User/picture.sass | 5 - app/styles/_components/User/score_tag.sass | 2 - .../_components/User/user_appellation.sass | 9 - app/styles/_components/User/user_page.sass | 69 - .../_components/User/user_reset_password.sass | 5 - .../_components/UsersActions/entity.sass | 11 - .../_components/UsersActions/history.sass | 19 - .../_components/UsersActions/user_action.sass | 49 - app/styles/_components/Utils/error_page.sass | 6 - .../_components/Utils/flash_messages.sass | 33 - .../_components/Utils/loading_frame.sass | 40 - app/styles/_components/Utils/modal_share.sass | 3 - app/styles/_components/Utils/popover.sass | 10 - .../Utils/reputation_guard_tooltip.sass | 6 - .../Utils/textarea_length_counter.sass | 9 - .../Utils/third_party_service_button.sass | 13 - .../VideoDebate/action_bubble_menu.sass | 100 - .../VideoDebate/comments/_variables.sass | 6 - .../VideoDebate/comments/comment.sass | 135 - .../VideoDebate/comments/comment_form.sass | 15 - .../VideoDebate/comments/comments_list.sass | 107 - .../_components/VideoDebate/history.sass | 17 - .../_components/VideoDebate/presence.sass | 10 - .../VideoDebate/speaker_preview.sass | 22 - .../_components/VideoDebate/video_debate.sass | 95 - app/styles/_components/Videos/card.sass | 58 - app/styles/_components/Videos/index.sass | 36 - app/styles/_components/Videos/player.sass | 3 - .../_components/Videos/videos_pagination.sass | 9 - app/styles/_components/flag_form.sass | 2 - app/styles/_components/form.sass | 8 - app/styles/_components/help.sass | 15 - .../_components/invitation_request_form.sass | 5 - app/styles/_components/modal.sass | 69 - app/styles/_components/statements.sass | 149 - app/styles/_fonts/Merriweather.eot | Bin 21180 -> 0 bytes app/styles/_fonts/Merriweather.svg | 374 - app/styles/_fonts/Merriweather.ttf | Bin 39324 -> 0 bytes app/styles/_fonts/Merriweather.woff | Bin 23036 -> 0 bytes app/styles/_fonts/Merriweather.woff2 | Bin 18816 -> 0 bytes app/styles/_fonts/icomoon.eot | Bin 16256 -> 0 bytes app/styles/_fonts/icomoon.svg | 72 - app/styles/_fonts/icomoon.ttf | Bin 16092 -> 0 bytes app/styles/_fonts/icomoon.woff | Bin 16168 -> 0 bytes app/styles/_fonts/icomoon.woff2 | Bin 8076 -> 0 bytes app/styles/_global/buttons.sass | 11 - app/styles/_global/card.sass | 10 - app/styles/_global/global.sass | 120 - app/styles/_global/icons.sass | 44 - app/styles/_global/icons_list.scss | 211 - app/styles/_global/language_adapter.sass | 25 - app/styles/_global/spinner.sass | 44 - app/styles/_global/variables.sass | 103 - app/styles/_helpers/is_blurred.sass | 2 - app/styles/_helpers/quoted.sass | 8 - .../_libraries_overrides/bulma_message.sass | 2 - app/styles/_mixins/font_face.scss | 42 - .../_mixins/progressive_animation_delay.sass | 11 - app/styles/application.sass | 109 - app/styles/main.css | 60 + components.json | 21 + package-lock.json | 9091 +++++------------ package.json | 21 +- tailwind.config.js | 50 + tsconfig.json | 24 + webpack.config.js | 13 +- webpack.loaders.js | 37 +- 120 files changed, 3978 insertions(+), 10258 deletions(-) delete mode 100644 .sass-lint.yml delete mode 100644 app/components/Utils/FlashMessages.jsx create mode 100644 app/components/ui/button.tsx create mode 100644 app/components/ui/card.tsx create mode 100644 app/components/ui/select.tsx create mode 100644 app/components/ui/toast.tsx create mode 100644 app/components/ui/toaster.tsx create mode 100644 app/hooks/use-toast.ts create mode 100644 app/lib/css-utils.js delete mode 100644 app/state/flashes/record.js delete mode 100644 app/styles/_components/App/app.sass delete mode 100644 app/styles/_components/App/logo.sass delete mode 100644 app/styles/_components/App/sidebar.sass delete mode 100644 app/styles/_components/Moderation/flag_reason_select.sass delete mode 100644 app/styles/_components/Moderation/moderation.sass delete mode 100644 app/styles/_components/Pages/browser_extensions.sass delete mode 100644 app/styles/_components/Pages/home_page.sass delete mode 100644 app/styles/_components/Speakers/speaker_page.sass delete mode 100644 app/styles/_components/Speakers/speaker_preview.sass delete mode 100644 app/styles/_components/User/achievements.sass delete mode 100644 app/styles/_components/User/activity_log.sass delete mode 100644 app/styles/_components/User/authenticate.sass delete mode 100644 app/styles/_components/User/picture.sass delete mode 100644 app/styles/_components/User/score_tag.sass delete mode 100644 app/styles/_components/User/user_appellation.sass delete mode 100644 app/styles/_components/User/user_page.sass delete mode 100644 app/styles/_components/User/user_reset_password.sass delete mode 100644 app/styles/_components/UsersActions/entity.sass delete mode 100644 app/styles/_components/UsersActions/history.sass delete mode 100644 app/styles/_components/UsersActions/user_action.sass delete mode 100644 app/styles/_components/Utils/error_page.sass delete mode 100644 app/styles/_components/Utils/flash_messages.sass delete mode 100644 app/styles/_components/Utils/loading_frame.sass delete mode 100644 app/styles/_components/Utils/modal_share.sass delete mode 100644 app/styles/_components/Utils/popover.sass delete mode 100644 app/styles/_components/Utils/reputation_guard_tooltip.sass delete mode 100644 app/styles/_components/Utils/textarea_length_counter.sass delete mode 100644 app/styles/_components/Utils/third_party_service_button.sass delete mode 100644 app/styles/_components/VideoDebate/action_bubble_menu.sass delete mode 100644 app/styles/_components/VideoDebate/comments/_variables.sass delete mode 100644 app/styles/_components/VideoDebate/comments/comment.sass delete mode 100644 app/styles/_components/VideoDebate/comments/comment_form.sass delete mode 100644 app/styles/_components/VideoDebate/comments/comments_list.sass delete mode 100644 app/styles/_components/VideoDebate/history.sass delete mode 100644 app/styles/_components/VideoDebate/presence.sass delete mode 100644 app/styles/_components/VideoDebate/speaker_preview.sass delete mode 100644 app/styles/_components/VideoDebate/video_debate.sass delete mode 100644 app/styles/_components/Videos/card.sass delete mode 100644 app/styles/_components/Videos/index.sass delete mode 100644 app/styles/_components/Videos/player.sass delete mode 100644 app/styles/_components/Videos/videos_pagination.sass delete mode 100644 app/styles/_components/flag_form.sass delete mode 100644 app/styles/_components/form.sass delete mode 100644 app/styles/_components/help.sass delete mode 100644 app/styles/_components/invitation_request_form.sass delete mode 100644 app/styles/_components/modal.sass delete mode 100644 app/styles/_components/statements.sass delete mode 100644 app/styles/_fonts/Merriweather.eot delete mode 100644 app/styles/_fonts/Merriweather.svg delete mode 100644 app/styles/_fonts/Merriweather.ttf delete mode 100644 app/styles/_fonts/Merriweather.woff delete mode 100644 app/styles/_fonts/Merriweather.woff2 delete mode 100644 app/styles/_fonts/icomoon.eot delete mode 100644 app/styles/_fonts/icomoon.svg delete mode 100644 app/styles/_fonts/icomoon.ttf delete mode 100644 app/styles/_fonts/icomoon.woff delete mode 100644 app/styles/_fonts/icomoon.woff2 delete mode 100644 app/styles/_global/buttons.sass delete mode 100644 app/styles/_global/card.sass delete mode 100644 app/styles/_global/global.sass delete mode 100644 app/styles/_global/icons.sass delete mode 100644 app/styles/_global/icons_list.scss delete mode 100644 app/styles/_global/language_adapter.sass delete mode 100644 app/styles/_global/spinner.sass delete mode 100644 app/styles/_global/variables.sass delete mode 100644 app/styles/_helpers/is_blurred.sass delete mode 100644 app/styles/_helpers/quoted.sass delete mode 100644 app/styles/_libraries_overrides/bulma_message.sass delete mode 100644 app/styles/_mixins/font_face.scss delete mode 100644 app/styles/_mixins/progressive_animation_delay.sass delete mode 100644 app/styles/application.sass create mode 100644 app/styles/main.css create mode 100644 components.json create mode 100644 tailwind.config.js create mode 100644 tsconfig.json diff --git a/.babelrc b/.babelrc index b02645ca1..eb6d32d93 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["@babel/preset-env", "@babel/preset-react"], + "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"], "plugins": [ ["babel-plugin-wildcard", { "exts": ["json"], "nostrip": true, "noModifyCase": true }], [ diff --git a/.dockerignore b/.dockerignore index 0634d58ed..990a864bc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,7 +4,6 @@ .vscode .eslintrc.yml .gitignore -.sass-lint.yml .travis.yml node_modules diff --git a/.gitignore b/.gitignore index 8a30e37c5..c329861ac 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.swp *.vi *~ -*.sass-cache # OS or Editor folders .DS_Store diff --git a/.sass-lint.yml b/.sass-lint.yml deleted file mode 100644 index 110a25ab8..000000000 --- a/.sass-lint.yml +++ /dev/null @@ -1,95 +0,0 @@ -options: - formatter: stylish -files: - include: '**/*.s+(a|c)ss' -rules: - # Extends - extends-before-mixins: 1 - extends-before-declarations: 1 - placeholder-in-extend: 1 - - # Mixins - mixins-before-declarations: 1 - - # Line Spacing - one-declaration-per-line: 1 - empty-line-between-blocks: 1 - single-line-per-selector: 1 - - # Disallows - no-attribute-selectors: 0 - no-color-hex: 0 - no-color-keywords: 1 - no-color-literals: 1 - no-combinators: 0 - no-css-comments: 1 - no-debug: 1 - no-disallowed-properties: 0 - no-duplicate-properties: 1 - no-empty-rulesets: 1 - no-extends: 0 - no-ids: 1 - no-important: 1 - no-invalid-hex: 1 - no-mergeable-selectors: 1 - no-misspelled-properties: 1 - no-qualifying-elements: 1 - no-trailing-whitespace: 1 - no-trailing-zero: 1 - no-transition-all: 1 - no-universal-selectors: 0 - no-url-domains: 1 - no-url-protocols: 1 - no-vendor-prefixes: 1 - no-warn: 1 - property-units: 0 - - # Nesting - declarations-before-nesting: 1 - force-attribute-nesting: 1 - force-element-nesting: 1 - force-pseudo-nesting: 1 - - # Name Formats - class-name-format: 1 - function-name-format: 1 - id-name-format: 0 - mixin-name-format: 1 - placeholder-name-format: 1 - variable-name-format: 1 - - # Style Guide - attribute-quotes: 1 - bem-depth: 0 - border-zero: 1 - brace-style: 1 - clean-import-paths: 1 - empty-args: 1 - hex-length: 1 - hex-notation: 1 - indentation: 1 - leading-zero: 0 - max-line-length: 0 - max-file-line-count: 0 - nesting-depth: 1 - property-sort-order: 0 - pseudo-element: 1 - quotes: 1 - shorthand-values: 1 - url-quotes: 1 - variable-for-property: 1 - zero-unit: 1 - - # Inner Spacing - space-after-comma: 1 - space-before-colon: 1 - space-after-colon: 1 - space-before-brace: 1 - space-before-bang: 1 - space-after-bang: 1 - space-between-parens: 1 - space-around-operator: 1 - - # Final Items - trailing-semicolon: 1 - final-newline: 1 diff --git a/README.md b/README.md index 860dc26d4..a1ce2eb25 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ app │   │   └── selectors.js => Re-select selectors to select data in state │   └── ... ├── static => Static assets, directly copied to the public directory -├── styles => Stylesheets in .sass format, all included from application.sass └── router.jsx => Application router and main entry point ``` diff --git a/app/API/no_internet_error.js b/app/API/no_internet_error.js index 9aaf4ae20..137fe4633 100644 --- a/app/API/no_internet_error.js +++ b/app/API/no_internet_error.js @@ -1,14 +1,14 @@ // Used only to show a message when request fail / timeout due to connection problems + import { NO_INTERNET_ERROR } from '../constants' import { flashError } from '../state/flashes/reducer' -import store from '../state/index' export default function noInternetError() { - store.dispatch( - flashError({ - message: NO_INTERNET_ERROR, - timeLeft: 999999999999, - infoText: 'actions.reload', - }), - ) + flashError({ + title: 'TODO', + message: NO_INTERNET_ERROR, + infoText: 'actions.reload', + variant: 'destructive', + duration: 999999999999, + }) } diff --git a/app/App.jsx b/app/App.jsx index 4c51e95f7..f67518c97 100644 --- a/app/App.jsx +++ b/app/App.jsx @@ -1,6 +1,6 @@ // Import polyfills // Import styles -import './styles/application.sass' +import '@/styles/main.css' import { ApolloProvider } from '@apollo/client' // Import libs @@ -8,7 +8,7 @@ import React from 'react' import { I18nextProvider } from 'react-i18next' import { Configure, Index, InstantSearch } from 'react-instantsearch-dom' import { Provider as ReduxProvider } from 'react-redux' -import { polyfill as smoothSrollPolyfill } from 'smoothscroll-polyfill' +import { polyfill as smoothScrollPolyfill } from 'smoothscroll-polyfill' import { ThemeProvider } from 'styled-components' // Import APIs so they can load their configurations @@ -24,7 +24,7 @@ import store from './state' import theme from './styles/theme' // Activate polyfills -smoothSrollPolyfill() +smoothScrollPolyfill() const App = () => ( diff --git a/app/components/App/LanguageSelector.jsx b/app/components/App/LanguageSelector.jsx index 16c63d493..09def923c 100644 --- a/app/components/App/LanguageSelector.jsx +++ b/app/components/App/LanguageSelector.jsx @@ -1,10 +1,17 @@ -import { Box, Flex } from '@rebass/grid' -import classNames from 'classnames' import { Map } from 'immutable' import React from 'react' import { withNamespaces } from 'react-i18next' import { Globe } from 'styled-icons/fa-solid' +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select' +import { cn } from '@/lib/css-utils' + const defaultLocales = new Map({ en: 'English', fr: 'Français', @@ -21,26 +28,25 @@ export default class LanguageSelector extends React.PureComponent { const options = defaultLocales.merge(this.props.additionalOptions || {}).sortBy((v, k) => k) return ( - + ) } renderLocalesMap(localesMap) { return localesMap.entrySeq().map(([key, value]) => ( - + )) } renderIcon() { - const { value, size } = this.props + const { value } = this.props if (value === 'fr') { return '🇫🇷' } else if (value === 'en') { @@ -56,16 +62,15 @@ export default class LanguageSelector extends React.PureComponent { } else if (value === 'ru') { return '🇷🇺' } - return + return } render() { - const sizeClass = this.props.size ? `is-${this.props.size}` : null return ( - - {this.props.withIcon && {this.renderIcon()}} - {this.renderSelect()} - +
+ {this.props.withIcon &&
{this.renderIcon()}
} + {this.renderSelect()} +
) } } diff --git a/app/components/App/Layout.jsx b/app/components/App/Layout.jsx index f631c3965..fe54ba036 100644 --- a/app/components/App/Layout.jsx +++ b/app/components/App/Layout.jsx @@ -3,8 +3,8 @@ import { Helmet } from 'react-helmet' import { connect } from 'react-redux' import { MainModalContainer } from '../Modal/MainModalContainer' +import { Toaster } from '../ui/toaster' import PublicAchievementUnlocker from '../Users/PublicAchievementUnlocker' -import { FlashMessages } from '../Utils' import BackgroundNotifier from './BackgroundNotifier' import CrashReportPage from './CrashReportPage' import Navbar from './Navbar' @@ -51,21 +51,23 @@ export default class Layout extends React.PureComponent { const mainContainerClass = sidebarExpended ? undefined : 'expended' return ( -
- {this.renderMetadata()} - - - - -
- {!this.state.error ? children : } + +
+ {this.renderMetadata()} + + + +
+ {!this.state.error ? children : } +
+ +
- - -
+ + ) } diff --git a/app/components/App/Logo.jsx b/app/components/App/Logo.jsx index e891055fb..41d1ae255 100644 --- a/app/components/App/Logo.jsx +++ b/app/components/App/Logo.jsx @@ -29,10 +29,12 @@ const Image = styled.img` * The main website logo. */ const Logo = ({ borderless, height }) => ( - + C - aptain - + + aptain + + Fact diff --git a/app/components/App/Navbar.jsx b/app/components/App/Navbar.jsx index 3063d91ab..57c4357fe 100644 --- a/app/components/App/Navbar.jsx +++ b/app/components/App/Navbar.jsx @@ -22,6 +22,7 @@ import Container from '../StyledUtils/Container' import { fadeIn } from '../StyledUtils/Keyframes' import StyledLink from '../StyledUtils/StyledLink' import { Span } from '../StyledUtils/Text' +import { Button } from '../ui/button' import ScoreTag from '../Users/ScoreTag' import UserAppellation from '../Users/UserAppellation' import UserMenu from '../Users/UserMenu' @@ -260,29 +261,14 @@ const Navbar = ({ ) : ( - - - {t('menu.login')} - - - {t('menu.extension')} - - - {t('menu.signup')} +
+ + + + + - +
)} )} diff --git a/app/components/App/Sidebar.jsx b/app/components/App/Sidebar.jsx index 87aaf6d54..3cec5cb77 100644 --- a/app/components/App/Sidebar.jsx +++ b/app/components/App/Sidebar.jsx @@ -1,7 +1,7 @@ import { Query } from '@apollo/client/react/components' -import { Flex } from '@rebass/grid' import classNames from 'classnames' import { capitalize, get } from 'lodash' +import { CircleHelp, Flag, Heart, ListVideo, Puzzle, Users } from 'lucide-react' import React from 'react' import { withNamespaces } from 'react-i18next' import { connect } from 'react-redux' @@ -27,7 +27,6 @@ import UserLanguageSelector from '../LoggedInUser/UserLanguageSelector' import { withLoggedInUser } from '../LoggedInUser/UserProvider' import ExternalLinkNewTab from '../Utils/ExternalLinkNewTab' import ProgressBar from '../Utils/ProgressBar' -import RawIcon from '../Utils/RawIcon' import ReputationGuard from '../Utils/ReputationGuard' import Tag from '../Utils/Tag' @@ -42,6 +41,7 @@ const WhiteStar = styled(Star)` const DailyGainText = styled.p` color: #858585; ` + @connect((state) => ({ sidebarExpended: state.UserPreferences.sidebarExpended }), { toggleSidebar, closeSidebar, @@ -62,15 +62,19 @@ export default class Sidebar extends React.PureComponent { } } - MenuLink({ title, iconName, customLink, className, children, ...props }) { - const classes = classNames(className, { 'link-with-icon': !!iconName }) + MenuLink({ title, className, children, ...props }) { + const classes = classNames( + 'flex items-center px-4 py-2 text-gray-700 hover:bg-gray-100 rounded-md', + { 'bg-gray-100': props.isActive }, + className, + ) return ( - {iconName && } - {customLink ? children : {children}} + {children} ) } @@ -92,82 +95,104 @@ export default class Sidebar extends React.PureComponent { render() { const { sidebarExpended, className, t, isAuthenticated } = this.props return ( - -
-

{t('menu.language')}

- +
+

+ {t('menu.language')} +

+ {isAuthenticated ? ( -

{t('menu.yourProfile')}

+

+ {t('menu.yourProfile')} +

{this.renderMenuProfile()}
) : null} -

{t('menu.factChecking')}

+

+ {t('menu.factChecking')} +

{this.renderMenuContent()} -

{t('menu.other')}

-