diff --git a/.circleci/config.yml b/.circleci/config.yml index f758b5492..607f33872 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,7 +73,7 @@ jobs: - run: name: yarn - command: yarn install --cache-folder ~/.cache/yarn + command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn # Store yarn / webpacker cache - save_cache: @@ -104,9 +104,8 @@ jobs: fi curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json - + # Database setup - - run: yarn install --check-files - run: bundle exec rake db:create - run: bundle exec rake db:schema:load @@ -117,7 +116,7 @@ jobs: - run: name: Rubocop command: bundle exec rubocop - + # - run: # name: Brakeman # command: bundle exec brakeman @@ -126,6 +125,21 @@ jobs: name: eslint command: yarn run eslint + # Run frontend tests + - run: + name: Run frontend tests + command: | + mkdir -p ~/tmp/test-results/frontend_specs + ~/tmp/cc-test-reporter before-build + TESTFILES=$(circleci tests glob **/specs/*.spec.js | circleci tests split --split-by=timings) + yarn test:coverage --profile 10 \ + --out ~/tmp/test-results/yarn.xml \ + -- ${TESTFILES} + - run: + name: Code Climate Test Coverage + command: | + ~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json" + # Run rails tests - run: name: Run backend tests @@ -145,20 +159,6 @@ jobs: command: | ~/tmp/cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json" - - run: - name: Run frontend tests - command: | - mkdir -p ~/tmp/test-results/frontend_specs - ~/tmp/cc-test-reporter before-build - TESTFILES=$(circleci tests glob **/specs/*.spec.js | circleci tests split --split-by=timings) - yarn test:coverage --profile 10 \ - --out ~/tmp/test-results/yarn.xml \ - -- ${TESTFILES} - - run: - name: Code Climate Test Coverage - command: | - ~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json" - - persist_to_workspace: root: coverage paths: diff --git a/app/javascript/dashboard/App.vue b/app/javascript/dashboard/App.vue index 839047671..17b8611e7 100644 --- a/app/javascript/dashboard/App.vue +++ b/app/javascript/dashboard/App.vue @@ -3,7 +3,8 @@ v-if="!authUIFlags.isFetching" id="app" class="app-wrapper app-root" - :class="{ 'app-rtl--wrapper': isRTLView }" + :class="{ 'app-rtl--wrapper': isRTLView, dark: theme === 'dark' }" + :dir="isRTLView ? 'rtl' : 'ltr'" > @@ -34,10 +35,12 @@ import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue'; import vueActionCable from './helper/actionCable'; import WootSnackbarBox from './components/SnackbarContainer'; import rtlMixin from 'shared/mixins/rtlMixin'; +import { LocalStorage } from 'shared/helpers/localStorage'; import { registerSubscription, verifyServiceWorkerExistence, } from './helper/pushHelper'; +import { LOCAL_STORAGE_KEYS } from './constants/localStorage'; export default { name: 'App', @@ -58,6 +61,7 @@ export default { return { showAddAccountModal: false, latestChatwootVersion: null, + theme: 'light', }; }, @@ -89,9 +93,34 @@ export default { }, }, mounted() { + this.initializeColorTheme(); + this.listenToThemeChanges(); this.setLocale(window.chatwootConfig.selectedLocale); }, methods: { + initializeColorTheme() { + this.setColorTheme( + window.matchMedia('(prefers-color-scheme: dark)').matches + ); + }, + setColorTheme(isOSOnDarkMode) { + const selectedColorScheme = + LocalStorage.get(LOCAL_STORAGE_KEYS.COLOR_SCHEME) || 'light'; + if ( + (selectedColorScheme === 'auto' && isOSOnDarkMode) || + selectedColorScheme === 'dark' + ) { + this.theme = 'dark'; + document.body.classList.add('dark'); + } else { + this.theme = 'light '; + document.body.classList.remove('dark'); + } + }, + listenToThemeChanges() { + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + mql.onchange = e => this.setColorTheme(e.matches); + }, setLocale(locale) { this.$root.$i18n.locale = locale; }, diff --git a/app/javascript/dashboard/assets/scss/_foundation-custom.scss b/app/javascript/dashboard/assets/scss/_foundation-custom.scss index 605b74483..4cb9fce21 100644 --- a/app/javascript/dashboard/assets/scss/_foundation-custom.scss +++ b/app/javascript/dashboard/assets/scss/_foundation-custom.scss @@ -20,15 +20,6 @@ select { margin-left: var(--space-normal); } -.tooltip { - background-color: var(--black-transparent); - border-radius: $space-smaller; - font-size: $font-size-mini; - max-width: var(--space-giga); - padding: $space-smaller $space-small; - z-index: 999; -} - code { border: 0; font-family: 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', diff --git a/app/javascript/dashboard/assets/scss/_helper-classes.scss b/app/javascript/dashboard/assets/scss/_helper-classes.scss index a8a5a0b93..0b400c4e9 100644 --- a/app/javascript/dashboard/assets/scss/_helper-classes.scss +++ b/app/javascript/dashboard/assets/scss/_helper-classes.scss @@ -1,5 +1,5 @@ .bg-light { - @include background-light; + @apply bg-slate-25 dark:bg-slate-800; } .flex-center { diff --git a/app/javascript/dashboard/assets/scss/_mixins.scss b/app/javascript/dashboard/assets/scss/_mixins.scss index a55f0a8dd..2fbb9fa7c 100644 --- a/app/javascript/dashboard/assets/scss/_mixins.scss +++ b/app/javascript/dashboard/assets/scss/_mixins.scss @@ -22,43 +22,43 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7); } @mixin border-normal() { - border: 1px solid $color-border; + @apply border border-slate-50 dark:border-slate-700; } @mixin border-normal-left() { - border-left: 1px solid $color-border; + @apply border-l border-slate-50 dark:border-slate-700; } @mixin border-normal-top() { - border-top: 1px solid $color-border; + @apply border-t border-slate-50 dark:border-slate-700; } @mixin border-normal-right() { - border-right: 1px solid $color-border; + @apply border-r border-slate-50 dark:border-slate-700; } @mixin border-normal-bottom() { - border-bottom: 1px solid $color-border; + @apply border-b border-slate-50 dark:border-slate-700; } @mixin border-light() { - border: 1px solid $color-border-light; + @apply border border-slate-25 dark:border-slate-700; } @mixin border-light-left() { - border-left: 1px solid $color-border-light; + @apply border-l border-slate-25 dark:border-slate-700; } @mixin border-light-top() { - border-top: 1px solid $color-border-light; + @apply border-t border-slate-25 dark:border-slate-700; } @mixin border-light-right() { - border-right: 1px solid $color-border-light; + @apply border-r border-slate-25 dark:border-slate-700; } @mixin border-light-bottom() { - border-bottom: 1px solid $color-border-light; + @apply border-b border-slate-25 dark:border-slate-700; } // background @@ -67,11 +67,11 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7); } @mixin background-light() { - background: $color-background-light; + @apply bg-slate-50 dark:bg-slate-800; } @mixin background-white() { - background: $color-white; + @apply bg-white dark:bg-slate-900; } // input form diff --git a/app/javascript/dashboard/assets/scss/_rtl.scss b/app/javascript/dashboard/assets/scss/_rtl.scss index b517fc0f2..5f4ed7d12 100644 --- a/app/javascript/dashboard/assets/scss/_rtl.scss +++ b/app/javascript/dashboard/assets/scss/_rtl.scss @@ -3,9 +3,6 @@ // Primary sidebar .primary--sidebar { - border-left: 1px solid var(--s-50); - border-right: 0; - .options-menu.dropdown-pane { right: var(--space-smaller); @@ -20,63 +17,6 @@ } } - // Secondary sidebar - .secondary-sidebar { - .secondary-menu { - border-left: 1px solid var(--s-50); - border-right: 0; - - .nested.vertical.menu { - .badge--icon { - margin-left: var(--space-smaller); - margin-right: unset; - } - - .menu-label { - text-align: right; - } - } - - .secondary-menu--icon { - margin-left: var(--space-smaller); - margin-right: unset; - } - - .account-context--group .account-context--switch-group { - --overlay-shadow: linear-gradient( - to left, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 1) 50% - ); - background-image: var(--overlay-shadow); - } - - // Help center sidebar - .sidebar-header--wrap .header-title--wrap { - margin-left: unset; - margin-right: var(--space-small); - } - } - } - - // Woot button - .button { - .icon--emoji + .button__content { - padding-left: 0; - padding-right: var(--space-small); - } - - .icon--font + .button__content { - padding-left: 0; - padding-right: var(--space-small); - } - - .icon + .button__content { - padding-left: 0; - padding-right: var(--space-small); - } - } - // Settings header .settings-header { .header--icon { diff --git a/app/javascript/dashboard/assets/scss/_utility-helpers.scss b/app/javascript/dashboard/assets/scss/_utility-helpers.scss index 06c963a93..a8025ba66 100644 --- a/app/javascript/dashboard/assets/scss/_utility-helpers.scss +++ b/app/javascript/dashboard/assets/scss/_utility-helpers.scss @@ -43,17 +43,13 @@ } .border-right { - border-right: 1px solid var(--color-border); + @apply border-r border-slate-50 dark:border-slate-700; } .border-left { border-left: 1px solid var(--color-border); } -.bg-white { - background-color: var(--white); -} - .text-ellipsis { overflow: hidden; text-overflow: ellipsis; diff --git a/app/javascript/dashboard/assets/scss/_woot.scss b/app/javascript/dashboard/assets/scss/_woot.scss index 2b9229f69..2bf085024 100644 --- a/app/javascript/dashboard/assets/scss/_woot.scss +++ b/app/javascript/dashboard/assets/scss/_woot.scss @@ -1,3 +1,7 @@ +@import 'tailwindcss/base'; +@import 'tailwindcss/components'; +@import 'tailwindcss/utilities'; + @import 'shared/assets/fonts/plus-jakarta'; @import 'shared/assets/stylesheets/animations'; @import 'shared/assets/stylesheets/colors'; @@ -67,3 +71,8 @@ @import 'plugins/dropdown'; @import '~shared/assets/stylesheets/ionicons'; @import 'utility-helpers'; + + +.tooltip { + @apply bg-slate-900 text-white py-1 px-2 z-40 text-xs rounded-md dark:bg-slate-200 dark:text-slate-900; +} diff --git a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss index 870caf7ee..dfdad84a4 100644 --- a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss +++ b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss @@ -4,10 +4,8 @@ // Conversation header - Light BG .settings-header { - @include background-white; @include flex; @include flex-align($x: justify, $y: middle); - border-bottom: 1px solid var(--s-50); height: $header-height; min-height: $header-height; padding: $space-small $space-normal; @@ -27,7 +25,7 @@ .wizard-box { .item { - @include background-light; + // @include background-light; cursor: pointer; padding: $space-normal $space-normal $space-normal $space-medium; @@ -128,8 +126,8 @@ } .wizard-body { - @include background-white; @include border-light; + @include background-white; @include full-height(); padding: $space-medium; diff --git a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss index 3f36bfa0c..8df496ef6 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss @@ -1,207 +1,201 @@ -$default-button-height: 2.5rem; - .button { - align-items: center; - display: inline-flex; - height: $default-button-height; - margin-bottom: 0; + @apply items-center inline-flex h-10 mb-0; .button__content { - width: 100%; + @apply w-full; + + img, + svg { + @apply inline-block; + } } .spinner { - padding: 0 var(--space-small); + @apply px-2 py-0; } - .icon--emoji+.button__content { - padding-left: var(--space-small); + .icon--emoji + .button__content { + @apply pl-2 rtl:pr-2 rtl:pl-0; } - .icon--font+.button__content { - padding-left: var(--space-small); + .icon--font + .button__content { + @apply pl-2 rtl:pr-2 rtl:pl-0; } // @TODDO - Remove after moving all buttons to woot-button - .icon+.button__content { - padding-left: var(--space-small); - width: auto; + .icon + .button__content { + @apply pl-2 w-auto rtl:pr-2 rtl:pl-0; } &.expanded { - display: flex; - justify-content: center; + @apply flex justify-center text-center; } &.round { - border-radius: $space-larger; + @apply rounded-full; } // @TODO Use with link &.compact { - padding-bottom: 0; - padding-top: 0; + @apply pb-0 pt-0; } &.hollow { - border-color: var(--s-200); - color: var(--w-700); + @apply border border-slate-200 text-woot-700 dark:text-woot-100 hover:bg-woot-50 dark:hover:bg-woot-900; &.secondary { - border-color: var(--s-200); - color: var(--s-700); + @apply text-slate-700 dark:text-slate-100 hover:bg-slate-50 dark:hover:bg-slate-700; } &.success { - border-color: var(--s-200); - color: var(--g-700); + @apply text-green-700 dark:text-green-100 hover:bg-green-50 dark:hover:bg-green-800; } &.alert { - border-color: var(--s-200); - color: var(--r-700); + @apply text-red-700 dark:text-red-100 hover:bg-red-50 dark:hover:bg-red-800; } &.warning { - border-color: var(--s-200); - color: var(--y-700); + @apply text-yellow-700 dark:text-yellow-100 hover:bg-yellow-50 dark:hover:bg-yellow-800; } &:hover { - background: var(--s-75); - border-color: var(--s-100); + @apply bg-slate-75 dark:bg-slate-900 border-slate-100 dark:border-slate-700; &.secondary { - border-color: var(--s-100); + @apply border-slate-100 dark:border-slate-700; } &.success { - border-color: var(--s-100); + @apply border-slate-100 dark:border-slate-700; } &.alert { - border-color: var(--s-100); + @apply border-slate-100 dark:border-slate-700; } &.warning { - border-color: var(--s-100); + @apply border-slate-100 dark:border-slate-700; } } } // Smooth style &.smooth { - @include button-style(var(--w-50), var(--w-100), var(--w-700)); - + @apply bg-woot-50 dark:bg-woot-800 text-woot-700 dark:text-woot-100 hover:text-woot-700 dark:hover:text-woot-700 hover:bg-woot-100 dark:hover:bg-woot-900; &.secondary { - @include button-style(var(--s-50), var(--s-100), var(--s-700)); + @apply bg-slate-50 dark:bg-slate-700 text-slate-700 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800; } &.success { - @include button-style(var(--g-50), var(--g-100), var(--g-700)); + @apply bg-green-50 dark:bg-green-700 text-green-700 dark:text-green-100 hover:bg-green-100 dark:hover:bg-green-800; } &.alert { - @include button-style(var(--r-50), var(--r-100), var(--r-700)); + @apply bg-red-50 dark:bg-red-700 text-red-700 dark:text-red-100 hover:bg-red-100 dark:hover:bg-red-800; } &.warning { - @include button-style(var(--y-100), var(--y-200), var(--y-700)); + @apply bg-yellow-50 dark:bg-yellow-700 text-yellow-700 dark:text-yellow-100 hover:bg-yellow-100 dark:hover:bg-yellow-800; } } &.clear { - color: var(--w-700); + @apply text-woot-500 dark:text-woot-500; &.secondary { - color: var(--s-700); + @apply text-slate-700 dark:text-slate-100; } &.success { - color: var(--g-700); + @apply text-green-700 dark:text-green-100; } &.alert { - color: var(--r-700); + @apply text-red-700 dark:text-red-100; } &.warning { - color: var(--y-700); + @apply text-yellow-700 dark:text-yellow-100; } &:hover { - background: var(--w-50); + @apply hover:bg-woot-50 dark:hover:bg-woot-300; &.secondary { - background: var(--s-50); + @apply hover:bg-slate-50 dark:hover:bg-slate-700; } &.success { - background: var(--g-50); + @apply hover:bg-green-50 dark:hover:bg-green-800; } &.alert { - background: var(--r-50); + @apply hover:bg-red-50 dark:hover:bg-red-800; } &.warning { - background: var(--y-50); + @apply hover:bg-yellow-50 dark:hover:bg-yellow-800; + } + } + + &:active { + &.secondary { + @apply active:bg-slate-100 dark:active:bg-slate-900; + } + } + + &:focus { + &.secondary { + @apply focus:bg-slate-50 dark:focus:bg-slate-700; } } } // Sizes &.tiny { - height: var(--space-medium); + @apply h-6; - .icon+.button__content { - padding-left: var(--space-micro); + .icon + .button__content { + @apply pl-1 rtl:pr-1 rtl:pl-0; } } &.small { - height: var(--space-large); - padding-bottom: var(--space-smaller); - padding-top: var(--space-smaller); + @apply h-8 pb-1 pt-1; - .icon+.button__content { - padding-left: var(--space-smaller); + .icon + .button__content { + @apply pl-1 rtl:pr-1 rtl:pl-0; } } &.large { - height: var(--space-larger); + @apply h-12; } &.button--only-icon { - justify-content: center; - padding-left: 0; - padding-right: 0; - width: $default-button-height; + @apply justify-center pl-0 pr-0 w-10; &.tiny { - width: var(--space-medium); + @apply w-6; } &.small { - width: var(--space-large); + @apply w-8; } &.large { - width: var(--space-larger); + @apply w-12; } } &.link { - height: auto; - margin: 0; - padding: 0; + @apply h-auto m-0 p-0; &:hover { - text-decoration: underline; + @apply underline; } } - } diff --git a/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss b/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss index d88a7048d..184ca4b52 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conv-header.scss @@ -59,11 +59,6 @@ $resolve-button-width: 8.25rem; flex-direction: row; flex-grow: 1; justify-content: flex-end; - margin-top: var(--space-small); - - @include breakpoint(medium up) { - margin-top: 0; - } &.has-open-sidebar { justify-content: flex-end; diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss index f6da1be3f..7193da563 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss @@ -12,9 +12,7 @@ .conversation { @include flex; @include flex-shrink; - border-bottom: 1px solid transparent; border-left: var(--space-micro) solid transparent; - border-top: 1px solid transparent; cursor: pointer; padding: 0 var(--space-normal); position: relative; @@ -22,35 +20,11 @@ &.active { animation: left-shift-animation 0.25s $swift-ease-out-function; background: var(--color-background); - border-bottom-color: var(--color-border-light); border-left-color: var(--color-woot); - border-top-color: var(--color-border-light); - - .conversation--details { - border-top-color: transparent; - } - - + .conversation .conversation--details { - border-top-color: transparent; - } } - &:first-child { - .conversation--details { - border-top-color: transparent; - } - } - - &:last-child { - .conversation--details { - border-bottom-color: var(--color-border-light); - } - } .conversation--details { - @include border-light-bottom; - @include border-light-top; - border-bottom-color: transparent; padding: var(--space-slab) 0; } @@ -82,6 +56,11 @@ text-overflow: ellipsis; white-space: nowrap; width: 16.875rem; + + img, + svg { + display: inline-block; + } } .conversation--meta { diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss index cdf66d741..499064068 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss @@ -390,3 +390,42 @@ margin-bottom: 0; } } + +.conversation-sidebar-wrap { + flex: 0 0; + flex-basis: 100%; + height: auto; + overflow: auto; + z-index: var(--z-index-low); + + @include breakpoint(medium up) { + flex-basis: 17.5rem; + } + + @include breakpoint(large up) { + flex-basis: 18.75rem; + } + + @include breakpoint(xlarge up) { + flex-basis: 19.375rem; + } + + @include breakpoint(xxlarge up) { + flex-basis: 20.625rem; + } + + @include breakpoint(xxxlarge up) { + flex-basis: 25rem; + } +} + + +.activity-wrap { + .message-text--metadata { + .time { + @include breakpoint(xlarge up) { + margin-left: var(--space-small); + } + } + } +} diff --git a/app/javascript/dashboard/assets/scss/widgets/_forms.scss b/app/javascript/dashboard/assets/scss/widgets/_forms.scss index 17c0dc859..1f0311237 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_forms.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_forms.scss @@ -61,3 +61,7 @@ input { border-color: var(--r-400); } } + +label { + @apply dark:text-slate-300; +} diff --git a/app/javascript/dashboard/assets/scss/widgets/_modal.scss b/app/javascript/dashboard/assets/scss/widgets/_modal.scss index 644399b9e..2e970e763 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_modal.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_modal.scss @@ -34,7 +34,6 @@ .modal-container { @include normal-shadow; - background-color: $color-white; border-radius: $space-smaller; max-height: 100%; overflow: auto; diff --git a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss index a51e6047d..b03a55d7b 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_reply-box.scss @@ -1,6 +1,6 @@ .reply-box { transition: box-shadow 0.35s $swift-ease-out-function, - height 2s $swift-ease-out-function; + height 2s $swift-ease-out-function; &.is-focused { box-shadow: var(--shadow); diff --git a/app/javascript/dashboard/assets/scss/widgets/_states.scss b/app/javascript/dashboard/assets/scss/widgets/_states.scss index 0ca0b5c76..ba2905e91 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_states.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_states.scss @@ -1,18 +1,3 @@ -.loading-state { - padding: $space-jumbo $space-smaller; - - .message { - color: $color-gray; - display: block; - text-align: center; - width: 100%; - } - - .spinner { - float: none; - top: -$space-smaller; - } -} // EMPTY STATES .empty-state { diff --git a/app/javascript/dashboard/assets/scss/widgets/_widget_builder.scss b/app/javascript/dashboard/assets/scss/widgets/_widget_builder.scss new file mode 100644 index 000000000..e69de29bb diff --git a/app/javascript/dashboard/assets/scss/widgets/_woot-tables.scss b/app/javascript/dashboard/assets/scss/widgets/_woot-tables.scss index 6f57f9cb5..e3f39f865 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_woot-tables.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_woot-tables.scss @@ -4,15 +4,13 @@ table { thead { th { - font-weight: var(--font-weight-bold); - text-align: left; - text-transform: uppercase; + @apply font-medium text-left uppercase text-slate-900 dark:text-slate-200; } } tbody { tr { - border-bottom: 1px solid var(--color-border-light); + @apply border-b border-slate-50 dark:border-slate-700; } td { diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index e06c5b2e9..6f771eeca 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -126,27 +126,28 @@ class="conversations-list" :class="{ 'is-context-menu-open': isContextMenuOpen }" > - - + + + @@ -155,6 +156,7 @@ v-if="!hasCurrentPageEndReached && !chatListLoading" variant="clear" size="expanded" + class="text-center" @click="loadMoreConversations" > {{ $t('CHAT_LIST.LOAD_MORE_CONVERSATIONS') }} @@ -956,8 +958,6 @@ export default { diff --git a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue index 0face7819..4f8a7f9cb 100644 --- a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue +++ b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue @@ -4,7 +4,7 @@ - - + + - + {{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }} @@ -138,71 +140,3 @@ export default { }, }; - - diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue index 8295adb6d..537db77fd 100644 --- a/app/javascript/dashboard/components/layout/Sidebar.vue +++ b/app/javascript/dashboard/components/layout/Sidebar.vue @@ -1,5 +1,5 @@ - @@ -214,87 +213,3 @@ export default { }, }; - - - - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/AccountContext.vue b/app/javascript/dashboard/components/layout/sidebarComponents/AccountContext.vue index 38761e408..17f6a9060 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/AccountContext.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/AccountContext.vue @@ -1,25 +1,29 @@ {{ $t('SIDEBAR.CURRENTLY_VIEWING_ACCOUNT') }} - + {{ account.name }} - - - {{ $t('SIDEBAR.SWITCH') }} - + + + + {{ $t('SIDEBAR.SWITCH') }} + + @@ -51,51 +55,6 @@ export default { }; diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/Logo.vue b/app/javascript/dashboard/components/layout/sidebarComponents/Logo.vue index 406157fc2..f470bc5b6 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/Logo.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/Logo.vue @@ -1,5 +1,5 @@ - + @@ -30,17 +30,3 @@ export default { }, }; - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue b/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue index 375cd6ffa..9e997cf16 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/NotificationBell.vue @@ -1,15 +1,25 @@ - - + - - {{ unreadCount }} - + + + {{ unreadCount }} + + - - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue b/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue index 4a8171831..862d1c412 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/OptionsMenu.vue @@ -3,11 +3,10 @@ - handleProfileSettingClick(e, navigate)" > @@ -64,7 +63,7 @@ - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/Primary.vue b/app/javascript/dashboard/components/layout/sidebarComponents/Primary.vue index 462a8c61c..9e5d32b69 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/Primary.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/Primary.vue @@ -1,11 +1,14 @@ - - - + + + - - + + - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/PrimaryNavItem.vue b/app/javascript/dashboard/components/layout/sidebarComponents/PrimaryNavItem.vue index 36cc69da2..0ebc1ed3e 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/PrimaryNavItem.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/PrimaryNavItem.vue @@ -3,15 +3,28 @@ - - {{ name }} - {{ count }} + + {{ name }} + + {{ count }} + @@ -45,40 +58,3 @@ export default { }, }; - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue index 22adc05db..f4f395874 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/Secondary.vue @@ -1,7 +1,14 @@ - + - + - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryChildNavItem.vue b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryChildNavItem.vue index cb5c52c76..f0302c44e 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryChildNavItem.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryChildNavItem.vue @@ -5,38 +5,69 @@ custom active-class="active" > - + - - + + + - - {{ label }} - + + {{ label }} + + {{ childItemCount }} - - - {{ count }} - - + + @@ -72,10 +103,6 @@ export default { type: String, default: '', }, - count: { - type: String, - default: '', - }, showChildCount: { type: Boolean, default: false, @@ -89,96 +116,12 @@ export default { showIcon() { return { 'text-truncate': this.shouldTruncate }; }, + isCountZero() { + return this.childItemCount === 0; + }, menuTitle() { return this.shouldTruncate ? this.label : ''; }, }, }; - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue index 74323b082..f933e4d17 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue +++ b/app/javascript/dashboard/components/layout/sidebarComponents/SecondaryNavItem.vue @@ -1,46 +1,57 @@ - - - + + + {{ $t(`SIDEBAR.${menuItem.label}`) }} - + {{ $t(`SIDEBAR.${menuItem.label}`) }} - + {{ `${menuItem.count}` }} {{ $t('SIDEBAR.BETA') }} - + - - newLinkClick(e, navigate)" - > - - + + + newLinkClick(e, navigate)" + > {{ $t(`SIDEBAR.${menuItem.newLinkTag}`) }} - + @@ -108,6 +119,12 @@ export default { isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', globalConfig: 'globalConfig/get', }), + isCountZero() { + return this.menuItem.count === 0; + }, + isActiveView() { + return this.computedClass.includes('active-view'); + }, hasSubMenu() { return !!this.menuItem.children; }, @@ -178,7 +195,7 @@ export default { this.isUnattended || this.isCurrentRoute ) { - return 'is-active'; + return 'bg-woot-25 dark:bg-slate-800 text-woot-500 dark:text-woot-500 hover:text-woot-500 dark:hover:text-woot-500 active-view'; } if (this.hasSubMenu) { if ( @@ -187,12 +204,12 @@ export default { this.isIntegrationsSettings || this.isApplicationsSettings ) { - return 'is-active'; + return 'bg-woot-25 dark:bg-slate-800 text-woot-500 dark:text-woot-500 hover:text-woot-500 dark:hover:text-woot-500 active-view'; } - return ' '; + return 'hover:text-slate-700 dark:hover:text-slate-100'; } - return ''; + return 'hover:text-slate-700 dark:hover:text-slate-100'; }, }, methods: { @@ -233,132 +250,3 @@ export default { }, }; - diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js b/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js index ce1d5fe73..b10ba9a57 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js +++ b/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js @@ -4,7 +4,6 @@ import Vuex from 'vuex'; import VueI18n from 'vue-i18n'; import i18n from 'dashboard/i18n'; - import WootModal from 'dashboard/components/Modal'; import WootModalHeader from 'dashboard/components/ModalHeader'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon'; @@ -38,9 +37,7 @@ describe('accountSelctor', () => { }, ], }; - const accountId = 1; - const globalConfig = { createNewAccountFromDashboard: false }; - let store = null; + let actions = null; let modules = null; @@ -49,44 +46,46 @@ describe('accountSelctor', () => { modules = { auth: { getters: { - getCurrentAccountId: () => accountId, + getCurrentAccountId: () => 1, getCurrentUser: () => currentUser, }, }, globalConfig: { getters: { - 'globalConfig/get': () => globalConfig, + 'globalConfig/get': () => ({ createNewAccountFromDashboard: false }), }, }, }; - store = new Vuex.Store({ - actions, - modules, - }); + let store = new Vuex.Store({ actions, modules }); accountSelector = mount(AccountSelector, { store, localVue, i18n: i18nConfig, - propsData: { - showAccountModal: true, - }, + propsData: { showAccountModal: true }, + stubs: { WootButton: { template: '' } }, }); }); it('title and sub title exist', () => { const headerComponent = accountSelector.findComponent(WootModalHeader); - const topBar = headerComponent.find('.page-top-bar'); - const titleComponent = topBar.find('.page-sub-title'); - expect(titleComponent.text()).toBe('Switch Account'); - const subTitleComponent = topBar.find('p'); - expect(subTitleComponent.text()).toBe( - 'Select an account from the following list' - ); + const title = headerComponent.findComponent({ ref: 'modalHeaderTitle' }); + expect(title.text()).toBe('Switch Account'); + const content = headerComponent.findComponent({ + ref: 'modalHeaderContent', + }); + expect(content.text()).toBe('Select an account from the following list'); }); it('first account item is checked', () => { - const accountFirstItem = accountSelector.find('.account-selector svg'); - expect(accountFirstItem.exists()).toBe(true); + const selectedAccountCheckmark = accountSelector.find( + '#account-1 > button > svg' + ); + expect(selectedAccountCheckmark.exists()).toBe(true); + + const otherAccountCheckmark = accountSelector.find( + '#account-2 > button > svg' + ); + expect(otherAccountCheckmark.exists()).toBe(true); }); }); diff --git a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js index 4e60dbe5b..50d959b33 100644 --- a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js +++ b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js @@ -19,10 +19,7 @@ localVue.component('woot-dropdown-menu', WootDropdownMenu); localVue.component('woot-dropdown-divider', WootDropdownDivider); localVue.component('woot-dropdown-item', WootDropdownItem); -const i18nConfig = new VueI18n({ - locale: 'en', - messages: i18n, -}); +const i18nConfig = new VueI18n({ locale: 'en', messages: i18n }); describe('AvailabilityStatus', () => { const currentAvailability = 'online'; @@ -48,15 +45,13 @@ describe('AvailabilityStatus', () => { }, }; - store = new Vuex.Store({ - actions, - modules, - }); + store = new Vuex.Store({ actions, modules }); availabilityStatus = mount(AvailabilityStatus, { store, localVue, i18n: i18nConfig, + stubs: { WootSwitch: { template: '' } }, }); }); diff --git a/app/javascript/dashboard/components/specs/SidemenuIcon.spec.js b/app/javascript/dashboard/components/specs/SidemenuIcon.spec.js index 726c80de2..fea394572 100644 --- a/app/javascript/dashboard/components/specs/SidemenuIcon.spec.js +++ b/app/javascript/dashboard/components/specs/SidemenuIcon.spec.js @@ -3,7 +3,9 @@ import SidemenuIcon from '../SidemenuIcon'; describe('SidemenuIcon', () => { test('matches snapshot', () => { - const wrapper = shallowMount(SidemenuIcon); + const wrapper = shallowMount(SidemenuIcon, { + stubs: { WootButton: { template: '' } }, + }); expect(wrapper.vm).toBeTruthy(); expect(wrapper.element).toMatchSnapshot(); }); diff --git a/app/javascript/dashboard/components/specs/__snapshots__/SidemenuIcon.spec.js.snap b/app/javascript/dashboard/components/specs/__snapshots__/SidemenuIcon.spec.js.snap index 32e293da6..577dbb3aa 100644 --- a/app/javascript/dashboard/components/specs/__snapshots__/SidemenuIcon.spec.js.snap +++ b/app/javascript/dashboard/components/specs/__snapshots__/SidemenuIcon.spec.js.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`SidemenuIcon matches snapshot 1`] = ` - {{ `${createdAtTime} • ${lastActivityTime}` }} @@ -109,16 +109,3 @@ export default { }, }; - diff --git a/app/javascript/dashboard/components/ui/WootButton.vue b/app/javascript/dashboard/components/ui/WootButton.vue index 254f12d2f..364afbe36 100644 --- a/app/javascript/dashboard/components/ui/WootButton.vue +++ b/app/javascript/dashboard/components/ui/WootButton.vue @@ -18,7 +18,11 @@ :icon="icon" :icon-size="iconSize" /> - + diff --git a/app/javascript/dashboard/components/widgets/LoadingState.vue b/app/javascript/dashboard/components/widgets/LoadingState.vue index 9fdecc2e8..3e07a405d 100644 --- a/app/javascript/dashboard/components/widgets/LoadingState.vue +++ b/app/javascript/dashboard/components/widgets/LoadingState.vue @@ -1,6 +1,11 @@ - - {{ message }} + + + {{ message }} + + diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue index bc7660756..4874d2670 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue @@ -1,6 +1,6 @@ - + diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index b682f6f21..0c46c43e8 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -1144,8 +1144,7 @@ export default { } .reply-box { - border-top: 1px solid var(--color-border); - background: white; + @apply border-r border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-900; &.is-private { background: var(--y-50); diff --git a/app/javascript/dashboard/components/widgets/conversation/bubble/Actions.vue b/app/javascript/dashboard/components/widgets/conversation/bubble/Actions.vue index 750c4a982..466f34b71 100644 --- a/app/javascript/dashboard/components/widgets/conversation/bubble/Actions.vue +++ b/app/javascript/dashboard/components/widgets/conversation/bubble/Actions.vue @@ -254,8 +254,6 @@ export default { diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/Sidebar/SidebarHeader.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/Sidebar/SidebarHeader.vue index d526787bf..aa54394e1 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/Sidebar/SidebarHeader.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/Sidebar/SidebarHeader.vue @@ -1,20 +1,26 @@ - - + + - - + + {{ headerTitle }} - {{ subTitle }} + + {{ subTitle }} + - + - - diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/pages/articles/ArticleSettings.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/pages/articles/ArticleSettings.vue index f437ec176..d8676f2d3 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/pages/articles/ArticleSettings.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/pages/articles/ArticleSettings.vue @@ -1,7 +1,7 @@ - + {{ $t('HELP_CENTER.ARTICLE_SETTINGS.TITLE') }} diff --git a/app/javascript/dashboard/routes/dashboard/notifications/components/NotificationPanel.vue b/app/javascript/dashboard/routes/dashboard/notifications/components/NotificationPanel.vue index 19a4c7818..de2656cee 100644 --- a/app/javascript/dashboard/routes/dashboard/notifications/components/NotificationPanel.vue +++ b/app/javascript/dashboard/routes/dashboard/notifications/components/NotificationPanel.vue @@ -2,10 +2,10 @@ - - + + {{ $t('NOTIFICATIONS_PAGE.UNREAD_NOTIFICATION.TITLE') }} @@ -13,7 +13,7 @@ {{ totalUnreadNotifications }} - + -
+
{{ account.name }}