From aaeea6c9bf0aa2ed280e755a6d5e1ee957396658 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 28 Jan 2026 16:47:04 +0400 Subject: [PATCH 01/10] feat: Display story replies with attachment and context label (#13356) Fixes https://github.com/chatwoot/chatwoot/issues/13354 Fixes https://linear.app/chatwoot/issue/CW-6394/story-responses-are-not-being-shown-in-the-ui When someone replies to your Instagram story, agents in Chatwoot only see the reply text with no story image and no indication that it was a story reply. This makes it impossible to understand what the customer is responding to the message looks like a random text with no context. For example, if a customer replies "Love this!" to your story, the agent just sees "Love this!" with no way to know which story triggered the conversation. This PR fixes the issue by storing the story attachment and adding a context label. CleanShot 2026-01-27 at 19 19
38@2x --- .../instagram/base_message_builder.rb | 19 ++++++++++++++++ .../components-next/message/Message.vue | 1 + .../message/bubbles/InstagramStory.vue | 14 ++++++++++-- .../components-next/message/constants.js | 1 + .../dashboard/i18n/locale/en/settings.json | 3 ++- .../instagram/message_builder_spec.rb | 22 +++++-------------- .../messenger/message_builder_spec.rb | 8 ++++++- 7 files changed, 48 insertions(+), 20 deletions(-) diff --git a/app/builders/messages/instagram/base_message_builder.rb b/app/builders/messages/instagram/base_message_builder.rb index 8b40ba3c9..818c217ca 100644 --- a/app/builders/messages/instagram/base_message_builder.rb +++ b/app/builders/messages/instagram/base_message_builder.rb @@ -112,6 +112,25 @@ class Messages::Instagram::BaseMessageBuilder < Messages::Messenger::MessageBuil return if story_reply_attributes.blank? @message.save_story_info(story_reply_attributes) + create_story_reply_attachment(story_reply_attributes['url']) + end + + def create_story_reply_attachment(story_url) + return if story_url.blank? + + attachment = @message.attachments.new( + file_type: :ig_story, + account_id: @message.account_id, + external_url: story_url + ) + attachment.save! + begin + attach_file(attachment, story_url) + rescue Down::Error, StandardError => e + Rails.logger.warn "Failed to download Instagram story attachment: #{e.message}" + end + @message.content_attributes[:image_type] = 'ig_story_reply' + @message.save! end def build_conversation diff --git a/app/javascript/dashboard/components-next/message/Message.vue b/app/javascript/dashboard/components-next/message/Message.vue index 6fa7ff2b2..c4ae45fef 100644 --- a/app/javascript/dashboard/components-next/message/Message.vue +++ b/app/javascript/dashboard/components-next/message/Message.vue @@ -303,6 +303,7 @@ const componentToRender = computed(() => { const instagramSharedTypes = [ ATTACHMENT_TYPES.STORY_MENTION, ATTACHMENT_TYPES.IG_STORY, + ATTACHMENT_TYPES.IG_STORY_REPLY, ATTACHMENT_TYPES.IG_POST, ]; if (instagramSharedTypes.includes(props.contentAttributes.imageType)) { diff --git a/app/javascript/dashboard/components-next/message/bubbles/InstagramStory.vue b/app/javascript/dashboard/components-next/message/bubbles/InstagramStory.vue index f167d6501..5c3bfc2f6 100644 --- a/app/javascript/dashboard/components-next/message/bubbles/InstagramStory.vue +++ b/app/javascript/dashboard/components-next/message/bubbles/InstagramStory.vue @@ -1,19 +1,26 @@ diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index 359cd0f28..010c8c171 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -61,6 +61,7 @@ "UNSUPPORTED_MESSAGE": "This message is unsupported. To view it, please open it on the original platform.", "UNSUPPORTED_MESSAGE_FACEBOOK": "This message is unsupported. You can view this message on the Facebook Messenger app.", "UNSUPPORTED_MESSAGE_INSTAGRAM": "This message is unsupported. You can view this message on the Instagram app.", + "UNSUPPORTED_MESSAGE_TIKTOK": "This message is unsupported. You can view this message on the TikTok app.", "SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "NO_RESPONSE": "No response", From 6cd1b37981a198dc785aef821150838a2106cb2d Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 28 Jan 2026 19:46:48 +0400 Subject: [PATCH 04/10] feat: Tiktok API version configurable via Super Admin (#13381) Extracted hardcoded TikTok API version (`v1.3`) into a configurable `TIKTOK_API_VERSION` setting, consistent with how Instagram and WhatsApp handle API versions. Fixes https://linear.app/chatwoot/issue/CW-6408/tiktok-api-version-configurable-via-super-admin --- .../super_admin/app_configs_controller.rb | 2 +- app/services/tiktok/auth_client.rb | 14 +++++++++----- app/services/tiktok/client.rb | 12 ++++++++---- config/installation_config.yml | 5 +++++ 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/controllers/super_admin/app_configs_controller.rb b/app/controllers/super_admin/app_configs_controller.rb index e9d27c67a..0462af393 100644 --- a/app/controllers/super_admin/app_configs_controller.rb +++ b/app/controllers/super_admin/app_configs_controller.rb @@ -46,7 +46,7 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController 'linear' => %w[LINEAR_CLIENT_ID LINEAR_CLIENT_SECRET], 'slack' => %w[SLACK_CLIENT_ID SLACK_CLIENT_SECRET], 'instagram' => %w[INSTAGRAM_APP_ID INSTAGRAM_APP_SECRET INSTAGRAM_VERIFY_TOKEN INSTAGRAM_API_VERSION ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT], - 'tiktok' => %w[TIKTOK_APP_ID TIKTOK_APP_SECRET], + 'tiktok' => %w[TIKTOK_APP_ID TIKTOK_APP_SECRET TIKTOK_API_VERSION], 'whatsapp_embedded' => %w[WHATSAPP_APP_ID WHATSAPP_APP_SECRET WHATSAPP_CONFIGURATION_ID WHATSAPP_API_VERSION], 'notion' => %w[NOTION_CLIENT_ID NOTION_CLIENT_SECRET], 'google' => %w[GOOGLE_OAUTH_CLIENT_ID GOOGLE_OAUTH_CLIENT_SECRET GOOGLE_OAUTH_REDIRECT_URI ENABLE_GOOGLE_OAUTH_LOGIN], diff --git a/app/services/tiktok/auth_client.rb b/app/services/tiktok/auth_client.rb index d152d0338..cc2bb47c2 100644 --- a/app/services/tiktok/auth_client.rb +++ b/app/services/tiktok/auth_client.rb @@ -26,8 +26,8 @@ class Tiktok::AuthClient end # https://business-api.tiktok.com/portal/docs?id=1832184159540418 - def obtain_short_term_access_token(auth_code) # rubocop:disable Metrics/MethodLength - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/token/' + def obtain_short_term_access_token(auth_code) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize + endpoint = "#{api_base_url}/tt_user/oauth2/token/" headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/json' } body = { client_id: client_id, @@ -56,7 +56,7 @@ class Tiktok::AuthClient end def renew_short_term_access_token(refresh_token) # rubocop:disable Metrics/MethodLength - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/refresh_token/' + endpoint = "#{api_base_url}/tt_user/oauth2/refresh_token/" headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/json' } body = { client_id: client_id, @@ -82,7 +82,7 @@ class Tiktok::AuthClient end def webhook_callback - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/business/webhook/list/' + endpoint = "#{api_base_url}/business/webhook/list/" headers = { Accept: 'application/json' } params = { app_id: client_id, @@ -95,7 +95,7 @@ class Tiktok::AuthClient end def update_webhook_callback - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/business/webhook/update/' + endpoint = "#{api_base_url}/business/webhook/update/" headers = { Accept: 'application/json', 'Content-Type': 'application/json' } body = { app_id: client_id, @@ -141,5 +141,9 @@ class Tiktok::AuthClient def base_url ENV.fetch('FRONTEND_URL', 'http://localhost:3000') end + + def api_base_url + "https://business-api.tiktok.com/open_api/#{GlobalConfigService.load('TIKTOK_API_VERSION', 'v1.3')}" + end end end diff --git a/app/services/tiktok/client.rb b/app/services/tiktok/client.rb index 90fd6cef0..dfbe8ba1f 100644 --- a/app/services/tiktok/client.rb +++ b/app/services/tiktok/client.rb @@ -3,7 +3,7 @@ class Tiktok::Client pattr_initialize [:business_id!, :access_token!] def business_account_details - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/business/get/' + endpoint = "#{api_base_url}/business/get/" headers = { 'Access-Token': access_token } params = { business_id: business_id, fields: %w[username display_name profile_image].to_s } response = HTTParty.get(endpoint, query: params, headers: headers) @@ -17,7 +17,7 @@ class Tiktok::Client end def file_download_url(conversation_id, message_id, media_id, media_type = 'IMAGE') - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/business/message/media/download/' + endpoint = "#{api_base_url}/business/message/media/download/" headers = { 'Access-Token': access_token, 'Content-Type': 'application/json', Accept: 'application/json' } body = { business_id: business_id, conversation_id: conversation_id, @@ -45,7 +45,7 @@ class Tiktok::Client def send_message(conversation_id, type, payload, referenced_message_id: nil) # https://business-api.tiktok.com/portal/docs?id=1832184403754242 - endpoint ='https://business-api.tiktok.com/open_api/v1.3/business/message/send/' + endpoint = "#{api_base_url}/business/message/send/" headers = { 'Access-Token': access_token, 'Content-Type': 'application/json' } body = { business_id: business_id, @@ -70,7 +70,7 @@ class Tiktok::Client end def upload_media(file, media_type = 'IMAGE') - endpoint = 'https://business-api.tiktok.com/open_api/v1.3/business/message/media/upload/' + endpoint = "#{api_base_url}/business/message/media/upload/" headers = { 'Access-Token': access_token, 'Content-Type': 'multipart/form-data' } file.open do |temp_file| @@ -86,6 +86,10 @@ class Tiktok::Client end end + def api_base_url + "https://business-api.tiktok.com/open_api/#{GlobalConfigService.load('TIKTOK_API_VERSION', 'v1.3')}" + end + def process_json_response(response, error_prefix) unless response.success? Rails.logger.error "#{error_prefix}. Status: #{response.code}, Body: #{response.body}" diff --git a/config/installation_config.yml b/config/installation_config.yml index 33070357d..946b81e8e 100644 --- a/config/installation_config.yml +++ b/config/installation_config.yml @@ -407,6 +407,11 @@ # ------- End of Instagram Channel Related Config ------- # # ------- TikTok Channel Related Config ------- # +- name: TIKTOK_API_VERSION + display_title: 'TikTok API Version' + description: 'Configure this if you want to use a different TikTok API version. Make sure its prefixed with `v`' + value: 'v1.3' + locked: false - name: TIKTOK_APP_ID display_title: 'TikTok App ID' locked: false From 0ca98bc84f58810c4bd6386d5e1acab5902e237e Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Thu, 29 Jan 2026 00:24:01 +0530 Subject: [PATCH 05/10] feat: add lightweight /health endpoint (#13386) The existing /api health check endpoint creates a new Redis connection on every request and checks both Redis and Postgres availability. During peak traffic, this creates unnecessary load and can cause cascading failures when either service is slow - instances get marked unhealthy, traffic shifts to remaining instances, which then also fail health checks. The new /health endpoint: - Returns immediately with 200 {"status":"woot"} - Skips all middleware and authentication - No Redis or Postgres dependency - Suitable for health checks that only need to verify the web server is responding --- app/controllers/health_controller.rb | 7 +++++++ config/initializers/rack_attack.rb | 6 ++++++ config/routes.rb | 1 + spec/controllers/health_controller_spec.rb | 11 +++++++++++ 4 files changed, 25 insertions(+) create mode 100644 app/controllers/health_controller.rb create mode 100644 spec/controllers/health_controller_spec.rb diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb new file mode 100644 index 000000000..fdf969a39 --- /dev/null +++ b/app/controllers/health_controller.rb @@ -0,0 +1,7 @@ +# Inherits from ActionController::Base to skip all middleware, +# authentication, and callbacks. Used for health checks +class HealthController < ActionController::Base # rubocop:disable Rails/ApplicationController + def show + render json: { status: 'woot' } + end +end diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index fe40974f2..1f500243a 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -47,6 +47,12 @@ class Rack::Attack Rack::Attack.safelist('trusted IPs', &:allowed_ip?) + # Safelist health check endpoint so it never touches Redis for throttle tracking. + # This keeps /health fully dependency-free for ALB liveness checks. + Rack::Attack.safelist('health check') do |req| + req.path == '/health' + end + ### Throttle Spammy Clients ### # If any single client IP is making tons of requests, then they're diff --git a/config/routes.rb b/config/routes.rb index 95b77d323..83aed5b79 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,6 +35,7 @@ Rails.application.routes.draw do resource :slack_uploads, only: [:show] end + get '/health', to: 'health#show' get '/api', to: 'api#index' namespace :api, defaults: { format: 'json' } do namespace :v1 do diff --git a/spec/controllers/health_controller_spec.rb b/spec/controllers/health_controller_spec.rb new file mode 100644 index 000000000..7eafdd589 --- /dev/null +++ b/spec/controllers/health_controller_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe 'Health Check', type: :request do + describe 'GET /health' do + it 'returns success status' do + get '/health' + expect(response).to have_http_status(:success) + expect(response.parsed_body['status']).to eq('woot') + end + end +end From 2a69b37958a2ec521a80e62ebcc0e9b7c18eef3e Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 29 Jan 2026 04:06:04 +0530 Subject: [PATCH 06/10] chore: Update theme colors and add new Inter variable fonts (#13347) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request Template ## Description This PR includes the following updates: 1. Updated the design system color tokens by introducing new tokens for surfaces, overlays, buttons, labels, and cards, along with refinements to existing shades. 2. Refreshed both light and dark themes with adjusted background, border, and solid colors. 3. Replaced static Inter font files with the Inter variable font (including italic), supporting weights from 100–900. 4. Added custom font weights (420, 440, 460, 520) along with custom typography classes to enable more fine-grained and consistent typography control. ## Type of change - [x] New feature (non-breaking change which adds functionality) ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Pranav --- app/javascript/dashboard/App.vue | 2 +- .../dashboard/assets/scss/_next-colors.scss | 68 ++++-- .../assets/scss/plugins/_multiselect.scss | 2 +- .../components/ExclusionRules.vue | 2 +- .../Campaigns/CampaignLayout.vue | 2 +- .../LiveChatCampaign/LiveChatCampaignForm.vue | 2 +- .../SMSCampaign/SMSCampaignForm.vue | 2 +- .../WhatsAppCampaign/WhatsAppCampaignForm.vue | 2 +- .../Companies/CompaniesListLayout.vue | 2 +- .../Contacts/ContactsDetailsLayout.vue | 2 +- .../ContactsForm/ContactImportDialog.vue | 2 +- .../Contacts/ContactsListLayout.vue | 2 +- .../Contacts/ContactsSidebar/ContactMerge.vue | 2 +- .../CustomAttributes/OtherAttribute.vue | 2 +- .../components-next/EmptyStateLayout.vue | 8 +- .../HelpCenter/ArticleCard/ArticleCard.vue | 2 +- .../HelpCenter/CategoryCard/CategoryCard.vue | 2 +- .../HelpCenter/HelpCenterLayout.vue | 2 +- .../HelpCenter/LocaleCard/LocaleCard.vue | 2 +- .../Pages/CategoryPage/CategoryForm.vue | 2 +- .../components-next/Inbox/InboxCard.vue | 6 +- .../components-next/button/Button.vue | 10 +- .../components-next/captain/PageLayout.vue | 2 +- .../assistant/AddNewScenariosDialog.vue | 2 +- .../assistant/AssistantForm.vue | 2 +- .../customTool/CustomToolForm.vue | 2 +- .../pageComponents/document/DocumentForm.vue | 2 +- .../pageComponents/inbox/ConnectInboxForm.vue | 2 +- .../pageComponents/response/ResponseForm.vue | 2 +- .../changelog-card/StackedChangelogCard.vue | 2 +- .../components-next/filter/ConditionRow.vue | 4 +- .../components-next/filter/operators.js | 2 +- .../components-next/message/MessageList.vue | 2 +- .../message/bubbles/Template/CSAT.vue | 2 +- .../message/bubbles/Template/CallToAction.vue | 8 +- .../pagination/PaginationFooter.vue | 2 +- .../components-next/sidebar/ChannelLeaf.vue | 6 +- .../sidebar/MobileSidebarLauncher.vue | 2 +- .../components-next/sidebar/Sidebar.vue | 201 +++++++++++++++--- .../sidebar/SidebarAccountSwitcher.vue | 25 ++- .../sidebar/SidebarChangelogButton.vue | 46 ++++ .../sidebar/SidebarChangelogCard.vue | 10 + .../sidebar/SidebarCollapsedPopover.vue | 198 +++++++++++++++++ .../components-next/sidebar/SidebarGroup.vue | 187 ++++++++++++---- .../sidebar/SidebarGroupHeader.vue | 16 +- .../sidebar/SidebarGroupLeaf.vue | 6 +- .../sidebar/SidebarProfileMenu.vue | 20 +- .../sidebar/SidebarSubGroup.vue | 8 +- .../components-next/sidebar/provider.js | 81 ++++++- .../components-next/switch/Switch.vue | 2 +- .../components-next/tabbar/TabBar.vue | 2 +- .../components/Accordion/AccordionItem.vue | 4 +- .../dashboard/components/ChatList.vue | 2 +- .../dashboard/components/ChatListHeader.vue | 2 +- .../components/copilot/CopilotContainer.vue | 2 +- .../ui/DatePicker/components/CalendarWeek.vue | 2 +- .../dashboard/components/ui/Tabs/TabsItem.vue | 14 +- .../components/widgets/ChatTypeTabs.vue | 2 +- .../widgets/conversation/ConversationBox.vue | 5 +- .../widgets/conversation/ConversationCard.vue | 5 +- .../conversation/ConversationHeader.vue | 2 +- .../conversation/ConversationSidebar.vue | 2 +- .../conversation/EmptyState/EmptyState.vue | 2 +- .../widgets/conversation/MessagesView.vue | 2 +- .../conversation/OnboardingFeatureCard.vue | 2 +- .../conversation/linear/CreateOrLinkIssue.vue | 2 +- .../modules/search/components/SearchInput.vue | 2 +- .../modules/search/components/SearchView.vue | 2 +- .../dashboard/routes/dashboard/Dashboard.vue | 4 +- .../pages/CampaignsPageRouteView.vue | 2 +- .../captain/pages/AssistantsIndexPage.vue | 2 +- .../captain/pages/CaptainPageRouteView.vue | 2 +- .../contacts/pages/ContactManageView.vue | 2 +- .../contacts/pages/ContactsIndex.vue | 2 +- .../conversation/ConversationAction.vue | 2 +- .../conversation/ConversationParticipant.vue | 2 +- .../customAttributes/CustomAttributes.vue | 4 +- .../helpcenter/components/UpgradePage.vue | 2 +- .../pages/HelpCenterPageRouteView.vue | 2 +- .../helpcenter/pages/PortalsIndexPage.vue | 2 +- .../dashboard/inbox/InboxEmptyState.vue | 2 +- .../routes/dashboard/inbox/InboxList.vue | 4 +- .../inbox/components/InboxDisplayMenu.vue | 5 +- .../inbox/components/InboxItemHeader.vue | 2 +- .../dashboard/inbox/components/MenuItem.vue | 2 +- .../inbox/helpers/InboxViewHelpers.js | 10 +- .../dashboard/settings/SettingsHeader.vue | 2 +- .../dashboard/settings/SettingsWrapper.vue | 2 +- .../routes/dashboard/settings/Wrapper.vue | 2 +- .../components/BaseSettingsHeader.vue | 4 +- .../dashboard/settings/inbox/Settings.vue | 2 +- .../settings/inbox/components/BusinessDay.vue | 2 +- .../dashboard/settings/macros/MacroNodes.vue | 4 +- .../dashboard/settings/profile/Wrapper.vue | 2 +- .../reports/components/ReportsWrapper.vue | 2 +- .../fonts/Inter/InterVariable-Italic.woff2 | Bin 0 -> 380904 bytes .../assets/fonts/Inter/InterVariable.woff2 | Bin 0 -> 345588 bytes app/javascript/shared/assets/fonts/inter.scss | 50 +---- .../widget/components/PreChat/Form.vue | 2 +- tailwind.config.js | 7 + theme/colors.js | 30 ++- 101 files changed, 927 insertions(+), 265 deletions(-) create mode 100644 app/javascript/dashboard/components-next/sidebar/SidebarChangelogButton.vue create mode 100644 app/javascript/dashboard/components-next/sidebar/SidebarCollapsedPopover.vue create mode 100644 app/javascript/shared/assets/fonts/Inter/InterVariable-Italic.woff2 create mode 100644 app/javascript/shared/assets/fonts/Inter/InterVariable.woff2 diff --git a/app/javascript/dashboard/App.vue b/app/javascript/dashboard/App.vue index a63cb1a90..61d7631e7 100644 --- a/app/javascript/dashboard/App.vue +++ b/app/javascript/dashboard/App.vue @@ -131,7 +131,7 @@ export default {
diff --git a/app/javascript/dashboard/assets/scss/_next-colors.scss b/app/javascript/dashboard/assets/scss/_next-colors.scss index 4d7975a32..784edce6c 100644 --- a/app/javascript/dashboard/assets/scss/_next-colors.scss +++ b/app/javascript/dashboard/assets/scss/_next-colors.scss @@ -107,21 +107,39 @@ --violet-11: 101 85 183; --violet-12: 47 38 95; - --background-color: 253 253 253; - --text-blue: 8 109 224; + --background-color: 247 247 247; + --surface-1: 254 254 254; + --surface-2: 255 255 255; + --surface-active: 255 255 255; + --background-input-box: 0, 0, 0, 0.03; + --text-blue: 1 22 44; + --text-purple: 2 4 49; + --text-amber: 37 24 1; --border-container: 236 236 236; - --border-strong: 235 235 235; + --border-strong: 226 227 231; --border-weak: 234 234 234; + --border-blue-strong: 18 61 117; --solid-1: 255 255 255; --solid-2: 255 255 255; --solid-3: 255 255 255; --solid-active: 255 255 255; - --solid-amber: 252 232 193; + --solid-amber: 255 228 181; --solid-blue: 218 236 255; + --solid-blue-2: 251 253 255; --solid-iris: 230 231 255; + --solid-purple: 230 231 255; + --solid-red: 254 200 201; + --solid-amber-button: 255 221 141; + --card-color: 255 255 255; + --overlay: 0, 0, 0, 0.12; + --overlay-avatar: 255, 255, 255, 0.67; + --button-color: 255 255 255; + --button-hover-color: 255, 255, 255, 0.2; + --label-background: 247 247 247; + --label-border: 0, 0, 0, 0.04; - --alpha-1: 67, 67, 67, 0.06; - --alpha-2: 201, 202, 207, 0.15; + --alpha-1: 215, 215, 215, 0.22; + --alpha-2: 196, 197, 198, 0.22; --alpha-3: 255, 255, 255, 0.96; --black-alpha-1: 0, 0, 0, 0.12; --black-alpha-2: 0, 0, 0, 0.04; @@ -235,25 +253,43 @@ --violet-11: 169 153 236; --violet-12: 226 221 254; - --background-color: 18 18 19; - --border-strong: 52 52 52; - --border-weak: 38 38 42; + --background-color: 28 29 32; + --surface-1: 20 21 23; + --surface-2: 22 23 26; + --surface-active: 53 57 66; + --background-input-box: 255, 255, 255, 0.02; + --text-blue: 213 234 255; + --text-purple: 232 233 254; + --text-amber: 255 247 234; + --border-strong: 46 45 50; + --border-weak: 31 31 37; + --border-blue-strong: 201 226 255; --solid-1: 23 23 26; --solid-2: 29 30 36; --solid-3: 44 45 54; --solid-active: 53 57 66; - --solid-amber: 42 37 30; - --solid-blue: 16 49 91; + --solid-amber: 56 50 41; + --solid-blue: 15 57 102; + --solid-blue-2: 26 29 35; --solid-iris: 38 42 101; - --text-blue: 126 182 255; + --solid-purple: 51 51 107; + --solid-red: 90 33 34; + --solid-amber-button: 255 221 141; + --card-color: 28 30 34; + --overlay: 0, 0, 0, 0.4; + --overlay-avatar: 0, 0, 0, 0.05; + --button-color: 42 43 51; + --button-hover-color: 0, 0, 0, 0.15; + --label-background: 36 38 45; + --label-border: 255, 255, 255, 0.03; - --alpha-1: 36, 36, 36, 0.8; - --alpha-2: 139, 147, 182, 0.15; - --alpha-3: 36, 38, 45, 0.9; + --alpha-1: 35, 36, 42, 0.8; + --alpha-2: 147, 153, 176, 0.12; + --alpha-3: 33, 34, 38, 0.95; --black-alpha-1: 0, 0, 0, 0.3; --black-alpha-2: 0, 0, 0, 0.2; --border-blue: 39, 129, 246, 0.5; - --border-container: 236, 236, 236, 0; + --border-container: 255, 255, 255, 0; --white-alpha: 255, 255, 255, 0.1; } } diff --git a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss index b4154e4d8..9567d66c3 100644 --- a/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss +++ b/app/javascript/dashboard/assets/scss/plugins/_multiselect.scss @@ -7,7 +7,7 @@ @apply bg-n-slate-3; &::after { - @apply text-n-blue-text; + @apply text-n-blue-11; } } } diff --git a/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue b/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue index 351e3240f..965f532f4 100644 --- a/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue +++ b/app/javascript/dashboard/components-next/AssignmentPolicy/components/ExclusionRules.vue @@ -119,7 +119,7 @@ onMounted(() => { ) " :items="filteredTags" - class="[&>button]:!text-n-blue-text [&>div]:min-w-64" + class="[&>button]:!text-n-blue-11 [&>div]:min-w-64" @add="onClickAddTag" />
diff --git a/app/javascript/dashboard/components-next/Campaigns/CampaignLayout.vue b/app/javascript/dashboard/components-next/Campaigns/CampaignLayout.vue index 184e8bd10..01a207797 100644 --- a/app/javascript/dashboard/components-next/Campaigns/CampaignLayout.vue +++ b/app/javascript/dashboard/components-next/Campaigns/CampaignLayout.vue @@ -20,7 +20,7 @@ const handleButtonClick = () => {