diff --git a/index.html b/index.html index 02eb70d2c..9dc7abc5f 100644 --- a/index.html +++ b/index.html @@ -13,10 +13,10 @@
-
-
-
-
+
+
+
+
diff --git a/package.json b/package.json index b49929f42..1aefdc9d2 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,8 @@ "preview": "vite preview", "i18n": "formatjs extract 'src/**/*.{ts,tsx}' --ignore '**/*.d.ts' --out-file build/messages.json && formatjs compile build/messages.json --out-file src/locales/en.json", "test": "vitest", - "lint": "npm run lint:js && npm run lint:sass", + "lint": "npm run lint:js", "lint:js": "eslint --ext .js,.jsx,.cjs,.mjs,.ts,.tsx . --cache", - "lint:sass": "stylelint src/styles/**/*.scss", "prepare": "husky install" }, "license": "AGPL-3.0-or-later", diff --git a/src/components/icon.tsx b/src/components/icon.tsx index c5d4638a3..c463b0833 100644 --- a/src/components/icon.tsx +++ b/src/components/icon.tsx @@ -19,10 +19,10 @@ export interface IIcon extends React.HTMLAttributes { const Icon: React.FC = ({ src, alt, className, ...rest }) => { return (
- } /> + } />
); }; diff --git a/src/components/polls/poll-option.tsx b/src/components/polls/poll-option.tsx index ce99c66e8..036f8101d 100644 --- a/src/components/polls/poll-option.tsx +++ b/src/components/polls/poll-option.tsx @@ -151,7 +151,7 @@ const PollOption: React.FC = (props): JSX.Element | null => { className='size-4 text-primary-600 dark:fill-white dark:text-primary-800' /> ) : ( -
+
)}
diff --git a/src/features/compose/editor/index.tsx b/src/features/compose/editor/index.tsx index 944672ca9..1ba2505b0 100644 --- a/src/features/compose/editor/index.tsx +++ b/src/features/compose/editor/index.tsx @@ -59,7 +59,7 @@ const theme: InitialConfigType['theme'] = { italic: 'italic', strikethrough: 'line-through', underline: 'underline', - underlineStrikethrough: 'underline-line-through', + underlineStrikethrough: 'underline line-through', }, heading: { h1: 'text-2xl font-bold', diff --git a/src/main.tsx b/src/main.tsx index 9155ae1e9..ba0510b10 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -19,7 +19,6 @@ import 'soapbox/features/nostr/keyring.ts'; import './iframe.ts'; import './styles/i18n/arabic.css'; import './styles/i18n/javanese.css'; -import './styles/application.scss'; import './styles/tailwind.css'; import ready from './ready.ts'; diff --git a/src/styles/accessibility.scss b/src/styles/accessibility.scss deleted file mode 100644 index 00d5fe384..000000000 --- a/src/styles/accessibility.scss +++ /dev/null @@ -1,14 +0,0 @@ -$black-emojis: '8ball' 'ant' 'back' 'black_circle' 'black_heart' 'black_large_square' 'black_medium_small_square' 'black_medium_square' 'black_nib' 'black_small_square' 'bomb' 'bowling' 'bust_in_silhouette' 'busts_in_silhouette' 'camera' 'camera_with_flash' 'clubs' 'copyright' 'curly_loop' 'currency_exchange' 'dark_sunglasses' 'eight_pointed_black_star' 'electric_plug' 'end' 'female-guard' 'film_projector' 'fried_egg' 'gorilla' 'guardsman' 'heavy_check_mark' 'heavy_division_sign' 'heavy_dollar_sign' 'heavy_minus_sign' 'heavy_multiplication_x' 'heavy_plus_sign' 'hocho' 'hole' 'joystick' 'kaaba' 'lower_left_ballpoint_pen' 'lower_left_fountain_pen' 'male-guard' 'microphone' 'mortar_board' 'movie_camera' 'musical_score' 'on' 'registered' 'soon' 'spades' 'speaking_head_in_silhouette' 'spider' 'telephone_receiver' 'tm' 'top' 'tophat' 'turkey' 'vhs' 'video_camera' 'video_game' 'water_buffalo' 'waving_black_flag' 'wavy_dash'; - -%white-emoji-outline { - filter: drop-shadow(1px 1px 0 #fff) drop-shadow(-1px 1px 0 #fff) drop-shadow(1px -1px 0 #fff) drop-shadow(-1px -1px 0 #fff); - transform: scale(0.71); -} - -.emojione { - @each $emoji in $black-emojis { - &[title=':#{$emoji}:'] { - @extend %white-emoji-outline; - } - } -} diff --git a/src/styles/application.scss b/src/styles/application.scss deleted file mode 100644 index 64108d619..000000000 --- a/src/styles/application.scss +++ /dev/null @@ -1,9 +0,0 @@ -@use 'loading'; -@use 'ui'; -@use 'emoji-picker'; -@use 'accessibility'; - -// COMPONENTS -@use 'components/compose-form'; -@use 'components/status'; -@use 'components/icon'; diff --git a/src/styles/components/compose-form.scss b/src/styles/components/compose-form.scss deleted file mode 100644 index 37a986d39..000000000 --- a/src/styles/components/compose-form.scss +++ /dev/null @@ -1,167 +0,0 @@ -.compose-form { - &__warning { - @apply text-xs mb-2.5 px-2.5 py-2 shadow-md rounded bg-accent-300 text-white; - - strong { - @apply font-medium; - } - - a { - font-weight: 500; - text-decoration: underline; - - &:hover, - &:active, - &:focus { - text-decoration: none; - } - } - } - - &__modifiers { - @apply text-gray-900 text-sm; - font-family: inherit; - } - - &__upload-wrapper { overflow: hidden; } - - &__uploads-wrapper { - display: flex; - flex-direction: row; - flex-wrap: wrap; - - &.contains-media { - padding: 5px; - } - } - - &__upload { - flex: 1 1 0; - min-width: 40%; - margin: 5px; - position: relative; - border-radius: 4px; - overflow: hidden; - - &__actions { - @apply p-2 bg-gradient-to-b from-gray-900/80 via-gray-900/50 to-transparent flex items-start gap-2 justify-end opacity-0 transition-opacity duration-100 ease-linear; - - &.active { - @apply opacity-100; - } - - .icon-button { - @apply text-gray-200 hover:text-white text-sm font-medium p-2.5 space-x-1 rtl:space-x-reverse flex items-center; - } - } - - &-description { - @apply bg-gradient-to-b from-transparent via-gray-900/50 to-gray-900/80 absolute z-[2px] bottom-0 left-0 right-0 p-2.5 opacity-0 transition-opacity duration-100 ease-linear; - - &.active { - @apply opacity-100; - } - - textarea { - @apply bg-transparent text-white border-solid border border-white/25 p-2.5 rounded-md text-sm w-full m-0; - - &::placeholder { - @apply text-white/60; - } - } - } - - &-preview { - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: -1; - - video { - width: 100%; - height: 100%; - object-fit: cover; - } - } - } - - &__upload-thumbnail { - background-position: center; - background-size: contain; - background-repeat: no-repeat; - height: 160px; - width: 100%; - overflow: hidden; - position: relative; - - &.video { - background-image: url('../assets/images/video-placeholder.png'); - background-size: cover; - } - - &.audio { - background-image: url('../assets/images/audio-placeholder.png'); - background-size: cover; - } - } -} - -.privacy-dropdown { - &.active { - &.top .privacy-dropdown__value { - @apply rounded-t-md; - } - - .privacy-dropdown__dropdown { - @apply block shadow-md; - } - } - - &__dropdown { - @apply absolute bg-white dark:bg-gray-900 z-[1000] rounded-md shadow-lg ml-10 text-sm overflow-hidden black:bg-black black:border black:border-gray-800; - - &.top { - transform-origin: 50% 100%; - } - - &.bottom { - transform-origin: 50% 0; - } - } - - &__option { - @apply flex p-2.5 text-sm text-gray-700 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer black:hover:bg-gray-900; - - &.active { - @apply bg-gray-100 dark:bg-gray-800 black:bg-gray-900; - } - - &:hover, - &.active { - .privacy-dropdown__option__content, - .privacy-dropdown__option__content strong { - @apply text-black dark:text-white; - } - } - - &.active { - @apply hover:bg-gray-200 dark:hover:bg-gray-700; - } - - &__icon { - @apply flex items-center justify-center mr-2.5 rtl:mr-0 rtl:ml-2.5; - } - - &__content { - @apply flex-auto text-primary-600 dark:text-primary-400; - - strong { - @apply block font-medium text-black dark:text-white; - } - } - } -} diff --git a/src/styles/components/icon.scss b/src/styles/components/icon.scss deleted file mode 100644 index 01ab7f4f3..000000000 --- a/src/styles/components/icon.scss +++ /dev/null @@ -1,21 +0,0 @@ -.svg-icon { - width: 16px; - height: 16px; - display: flex; - align-items: center; - justify-content: center; - transition: 0.2s; - - svg { - // Apparently this won't skew the image as long as it has a viewbox - width: 100%; - height: 100%; - transition: 0.2s; - } -} - -.icon-button > div { - display: flex; - align-items: center; - justify-content: center; -} diff --git a/src/styles/components/status.scss b/src/styles/components/status.scss deleted file mode 100644 index 660f5127e..000000000 --- a/src/styles/components/status.scss +++ /dev/null @@ -1,146 +0,0 @@ -.status { - @apply min-h-[54px] cursor-default; - opacity: 1; - animation: fade 150ms linear; - - @supports (-ms-overflow-style: -ms-autohiding-scrollbar) { - // Add margin to avoid Edge auto-hiding scrollbar appearing over content. - // On Edge 16 this is 16px and Edge <=15 it's 12px, so aim for 16px. - padding-right: 26px; // 10px + 16px - } - - @keyframes fade { - 0% { opacity: 0; } - 100% { opacity: 1; } - } -} - -[column-type='filled'] .status--wrapper, -[column-type='filled'] .status-placeholder { - @apply bg-transparent dark:bg-transparent rounded-none shadow-none; -} - -.status-check-box { - @apply flex items-center justify-between; - - .status-check-box__status { - @apply py-2; - - .media-gallery { - max-width: 250px; - } - - .status__content { - @apply p-0 text-gray-700 dark:text-gray-500 text-sm whitespace-normal; - } - - .video-player, - .audio-player { - margin-top: 8px; - max-width: 250px; - } - - .media-gallery__item-thumbnail { - cursor: default; - } - } -} - -.status-check-box-toggle { - align-items: center; - display: flex; - flex: 0 0 auto; - justify-content: center; - padding: 10px; -} - -.focusable:focus, -.focusable-within:focus-within { - outline: 0; /* Required b/c HotKeys lib sets this outline */ - @apply ring-2 ring-primary-300; -} - -.status-card { - @apply flex text-sm border border-solid border-gray-200 dark:border-gray-800 rounded-lg text-gray-800 dark:text-gray-200 no-underline overflow-hidden; -} - -a.status-card { - @apply cursor-pointer hover:bg-gray-100 dark:hover:bg-primary-800/30 hover:no-underline; -} - -.status-card-video, -.status-card-audio { - iframe { - width: 100% !important; - height: 100% !important; - } -} - -.status-card__image { - flex: 0 0 40%; - position: relative; - overflow: hidden; - - & > .svg-icon { - width: 40px; - height: 40px; - position: absolute; - transform-origin: 50% 50%; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - - svg { - stroke-width: 1px; - } - } -} - -.status-card.horizontal { - display: block; -} - -.status-card.compact { - @apply border-gray-200 dark:border-gray-800; -} - -.status-card__image-image { - @apply block w-full h-full object-cover bg-cover bg-center; -} - -.status-card--link { - @apply flex flex-col md:flex-row; -} - -.material-status { - padding-bottom: 10px; - - &__status { - padding: 15px 0 10px; - box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.1); - border-radius: 10px; - } - - .status { - padding: 8px 10px; - - &__content { - padding-top: 10px; - } - } -} - -.attachment-thumbs { - position: relative; - - &__clickable-region { - cursor: pointer; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - right: 0; - bottom: 0; - } -} diff --git a/src/styles/emoji-picker.scss b/src/styles/emoji-picker.scss deleted file mode 100644 index 31747eff7..000000000 --- a/src/styles/emoji-picker.scss +++ /dev/null @@ -1,14 +0,0 @@ -em-emoji-picker { - --rgb-background: 255 255 255; - --rgb-accent: var(--color-primary-600); - --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); - --shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.dark em-emoji-picker { - --rgb-background: var(--color-primary-900); -} - -.black em-emoji-picker { - --rgb-background: var(--color-gray-900); -} diff --git a/src/styles/loading.scss b/src/styles/loading.scss deleted file mode 100644 index 56e586ae9..000000000 --- a/src/styles/loading.scss +++ /dev/null @@ -1,176 +0,0 @@ -.loading-indicator-wrapper { - @apply h-screen w-screen flex justify-center items-center; -} - -.loading-indicator { - @apply text-gray-50 text-xs uppercase flex flex-col items-center justify-center overflow-visible; -} - -.loading-indicator__container { - @apply w-10 h-10 relative; -} - -.loading-indicator__figure { - @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-12 h-12 rounded-full bg-transparent; - border: 0 solid; - border-width: 6px; - border-color: #e5e7eb; -} - -.no-reduce-motion .loading-indicator span { - animation: loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1); -} - -.no-reduce-motion .loading-indicator__figure { - animation: loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1); -} - -.loading-indicator-wrapper .loading-indicator { - @apply h-screen w-screen items-center; - - &__figure { - @apply border-gray-200; - } -} - -@keyframes loader-figure { - 0% { - @apply bg-gray-200 w-0 h-0; - } - - 29% { - @apply bg-gray-200; - } - - 30% { - @apply w-12 h-12 bg-transparent opacity-100; - border-width: 6px; - } - - 100% { - @apply w-12 h-12 border-0 opacity-0 bg-transparent; - } -} - -@keyframes loader-label { - 0% { opacity: 0.25; } - 30% { opacity: 1; } - 100% { opacity: 0.25; } -} - -@keyframes heartbeat { - 0% { - transform: scale(1); - animation-timing-function: ease-out; - } - - 10% { - transform: scale(0.91); - animation-timing-function: ease-in; - } - - 17% { - transform: scale(0.98); - animation-timing-function: ease-out; - } - - 33% { - transform: scale(0.87); - animation-timing-function: ease-in; - } - - 45% { - transform: scale(1); - animation-timing-function: ease-out; - } -} - -.no-reduce-motion .pulse-loading { - transform-origin: center center; - animation: heartbeat 1.5s ease-in-out infinite both; -} - -@keyframes shake-bottom { - 0%, - 100% { - transform: rotate(0deg); - transform-origin: 50% 100%; - } - - 10% { - transform: rotate(2deg); - } - - 20%, - 40%, - 60% { - transform: rotate(-4deg); - } - - 30%, - 50%, - 70% { - transform: rotate(4deg); - } - - 80% { - transform: rotate(-2deg); - } - - 90% { - transform: rotate(2deg); - } -} - -.no-reduce-motion .shake-bottom { - transform-origin: 50% 100%; - animation: shake-bottom 0.8s cubic-bezier(0.455, 0.03, 0.515, 0.955) 2s 2 both; -} - -.load-more { - @apply block w-full m-0 p-4 border-0 box-border text-gray-900 bg-transparent; - - .svg-icon { - @apply mx-auto; - } -} - -.regeneration-indicator { - @apply text-gray-900; - text-align: center; - font-size: 16px; - font-weight: 500; - cursor: default; - display: flex; - flex: 1 1 auto; - align-items: center; - justify-content: center; - padding: 20px; - border-radius: 10px; - - @media screen and (width <= 580px) { - border-radius: 0; - } - - & > div { - width: 100%; - background: transparent; - padding-top: 0; - } - - &__label { - strong { - @apply block mb-2.5 text-gray-900; - } - - span { - font-size: 15px; - font-weight: 400; - } - } -} - -.ptr, -.ptr__children { - overflow: visible !important; -} diff --git a/src/styles/tailwind.css b/src/styles/tailwind.css index d7742d727..5981ddc9e 100644 --- a/src/styles/tailwind.css +++ b/src/styles/tailwind.css @@ -95,7 +95,7 @@ .error-column > span { @apply max-w-[400px]; - } + } .error-column { .svg-icon { @@ -111,9 +111,10 @@ a { @apply text-primary-600 dark:text-primary-400 no-underline hover:underline; } - } + .ellipsis::after { content: '…'; } + .mention { @apply text-primary-600 dark:text-accent-blue hover:underline; } @@ -205,4 +206,67 @@ ); } + .setting-text { + @apply block w-full mb-2.5 border-0 border-b-2 border-solid box-border text-gray-400 bg-transparent; + font-family: inherit; + padding: 7px 0; + + @media screen and (width <= 600px) { + font-size: 16px; + } + } + + ::-webkit-scrollbar-thumb { + border-radius: 0; + } } + +@layer components { + .loading-indicator span { + @apply animate-loader-label; + } + + .ui { + display: block; + width: 100%; + padding: 0 0 calc(60px + env(safe-area-inset-bottom) + 86px); + + .page { + display: flex; + flex-direction: column; + width: 100%; + } + } + + .react-swipeable-view-container { + & { + height: 100%; + } + } + + .react-swipeable-view-container > * { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + } + + .react-datepicker-popper { + z-index: 9999 !important; + } + + em-emoji-picker { + --rgb-background: 255 255 255; + --rgb-accent: var(--color-primary-600); + --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); + --shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + } + + .dark em-emoji-picker { + --rgb-background: var(--color-primary-900); + } + + .black em-emoji-picker { + --rgb-background: var(--color-gray-900); + } +} \ No newline at end of file diff --git a/src/styles/ui.scss b/src/styles/ui.scss deleted file mode 100644 index 3683497c1..000000000 --- a/src/styles/ui.scss +++ /dev/null @@ -1,126 +0,0 @@ -.icon-button { - @apply text-black dark:text-white; - display: inline-flex; - align-items: center; - padding: 0; - border: 0; - background: transparent; - cursor: pointer; - transition: 100ms ease-in; - opacity: 0.4; - - &__text { - padding-left: 2px; - } - - &:hover, - &:active, - &:focus { - opacity: 0.6; - transition: color 200ms ease-out; - } - - &.disabled { - opacity: 0.2; - cursor: default; - } - - &::-moz-focus-inner { - border: 0; - } - - &::-moz-focus-inner, - &:focus, - &:active { - outline: 0 !important; - } -} - -.react-datepicker-popper { - z-index: 9999 !important; -} - -.ellipsis::after { content: '…'; } - -.image-loader { - position: relative; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - - .image-loader__preview-canvas { - @apply max-w-full max-h-[80%]; - background: url('../assets/images/void.png') repeat; - object-fit: contain; - } - - &.image-loader--amorphous .image-loader__preview-canvas { - display: none; - } -} - -.zoomable-image { - @apply relative w-full h-full flex items-center justify-center; - - img { - @apply w-auto h-auto max-w-full max-h-[80%] object-contain shadow-2xl; - } -} - -.react-swipeable-view-container { - & { - height: 100%; - } -} - -.react-swipeable-view-container > * { - display: flex; - align-items: center; - justify-content: center; - height: 100%; -} - -.ui { - display: block; - width: 100%; - padding: 0 0 calc(60px + env(safe-area-inset-bottom) + 86px); - - .page { - display: flex; - flex-direction: column; - width: 100%; - } -} - -.slist__append { - flex: 1 1 auto; - position: relative; - padding: 30px 15px; -} - -.setting-text { - @apply block w-full mb-2.5 border-0 border-b-2 border-solid box-border text-gray-400 bg-transparent; - font-family: inherit; - padding: 7px 0; - - @media screen and (width <= 600px) { - font-size: 16px; - } -} - -::-webkit-scrollbar-thumb { - border-radius: 0; -} - -@keyframes flicker { - 0% { opacity: 1; } - 30% { opacity: 0.75; } - 100% { opacity: 1; } -} - -.underline-line-through { - text-decoration: underline line-through; -} diff --git a/tailwind.config.ts b/tailwind.config.ts index 8e197193e..57bb3709d 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -78,6 +78,8 @@ const config: Config = { 'greentext': true, }), animation: { + 'loader-figure': 'loader-figure 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1)', + 'loader-label': 'loader-label 1.15s infinite cubic-bezier(0.215, 0.61, 0.355, 1)', fade: 'fade 150ms linear', 'sonar-scale-4': 'sonar-scale-4 3s linear infinite', 'sonar-scale-3': 'sonar-scale-3 3s 0.5s linear infinite', @@ -87,6 +89,38 @@ const config: Config = { 'leave': 'leave 150ms ease-in forwards', }, keyframes: { + 'loader-figure': { + '0%': { + backgroundColor: 'rgb(229, 231, 235)', + width: '0px', + height: '0px', + }, + + '29%': { + backgroundColor: 'rgb(229, 231, 235)', + }, + + '30%': { + width: '3rem', + height: '3rem', + backgroundColor: 'transparent', + opacity: '1', + borderWidth: '6px', + }, + + '100%': { + width: '3rem', + height: '3rem', + borderWidth: '0', + opacity: '0', + backgroundColor: 'transparent', + }, + }, + 'loader-label': { + '0%': { opacity: '0.25' }, + '30%': { opacity: '1' }, + '100%': { opacity: '0.25' }, + }, fade: { '0%': { opacity: '0' }, '100%': { opacity: '1' },