Merge branch 'release/3.7.0'
This commit is contained in:
45
.github/workflows/deploy_check.yml
vendored
Normal file
45
.github/workflows/deploy_check.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
## github action to check deployment success
|
||||
## curl the deployment url and check for 200 status
|
||||
## deployment url will be of the form chatwoot-pr-<pr_number>.herokuapp.com
|
||||
name: Deploy Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
deployment_check:
|
||||
name: Check Deployment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install jq
|
||||
run: sudo apt-get install -y jq
|
||||
- name: Print Deployment URL
|
||||
run: echo "https://chatwoot-pr-${{ github.event.pull_request.number }}.herokuapp.com"
|
||||
- name: Check Deployment Status
|
||||
run: |
|
||||
max_attempts=10
|
||||
attempt=1
|
||||
status_code=0
|
||||
echo "Waiting for review app to be deployed/redeployed, trying in 10 minutes..."
|
||||
sleep 600
|
||||
while [ $attempt -le $max_attempts ]; do
|
||||
response=$(curl -s -o /dev/null -w "%{http_code}" https://chatwoot-pr-${{ github.event.pull_request.number }}.herokuapp.com/api)
|
||||
status_code=$(echo $response | head -n 1)
|
||||
if [ $status_code -eq 200 ]; then
|
||||
body=$(curl -s https://chatwoot-pr-${{ github.event.pull_request.number }}.herokuapp.com/api)
|
||||
if echo "$body" | jq -e '.version and .timestamp and .queue_services == "ok" and .data_services == "ok"' > /dev/null; then
|
||||
echo "Deployment successful"
|
||||
exit 0
|
||||
else
|
||||
echo "Deployment status unknown, retrying in 3 minutes..."
|
||||
sleep 180
|
||||
fi
|
||||
else
|
||||
echo "Waiting for review app to be ready, retrying in 3 minutes..."
|
||||
sleep 180
|
||||
attempt=$((attempt + 1))
|
||||
fi
|
||||
done
|
||||
echo "Deployment failed after $max_attempts attempts"
|
||||
exit 1
|
||||
fi
|
||||
1
.github/workflows/run_response_bot_spec.yml
vendored
1
.github/workflows/run_response_bot_spec.yml
vendored
@@ -73,6 +73,7 @@ jobs:
|
||||
spec/enterprise/controllers/api/v1/accounts/response_sources_controller_spec.rb \
|
||||
spec/enterprise/services/enterprise/message_templates/response_bot_service_spec.rb \
|
||||
spec/enterprise/controllers/enterprise/api/v1/accounts/inboxes_controller_spec.rb:47 \
|
||||
spec/enterprise/jobs/enterprise/account/conversations_resolution_scheduler_job_spec.rb \
|
||||
--profile=10 \
|
||||
--format documentation
|
||||
|
||||
|
||||
12
.rubocop.yml
12
.rubocop.yml
@@ -2,6 +2,8 @@ require:
|
||||
- rubocop-performance
|
||||
- rubocop-rails
|
||||
- rubocop-rspec
|
||||
- ./rubocop/use_from_email.rb
|
||||
- ./rubocop/custom_cop_location.rb
|
||||
|
||||
Layout/LineLength:
|
||||
Max: 150
|
||||
@@ -140,6 +142,16 @@ RSpec/MultipleExpectations:
|
||||
RSpec/MultipleMemoizedHelpers:
|
||||
Max: 14
|
||||
|
||||
# custom rules
|
||||
UseFromEmail:
|
||||
Enabled: true
|
||||
Exclude:
|
||||
- 'app/models/user.rb'
|
||||
- 'app/models/contact.rb'
|
||||
|
||||
CustomCopLocation:
|
||||
Enabled: true
|
||||
|
||||
AllCops:
|
||||
NewCops: enable
|
||||
Exclude:
|
||||
|
||||
4
Gemfile
4
Gemfile
@@ -3,8 +3,8 @@ source 'https://rubygems.org'
|
||||
ruby '3.2.2'
|
||||
|
||||
##-- base gems for rails --##
|
||||
gem 'rack-cors', require: 'rack/cors'
|
||||
gem 'rails', '~> 7.0.8.0'
|
||||
gem 'rack-cors', '2.0.0', require: 'rack/cors'
|
||||
gem 'rails', '~> 7.0.8.1'
|
||||
# Reduces boot times through caching; required in config/boot.rb
|
||||
gem 'bootsnap', require: false
|
||||
|
||||
|
||||
114
Gemfile.lock
114
Gemfile.lock
@@ -33,70 +33,70 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actioncable (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
activejob (= 7.0.8)
|
||||
activerecord (= 7.0.8)
|
||||
activestorage (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actionmailbox (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
activejob (= 7.0.8.1)
|
||||
activerecord (= 7.0.8.1)
|
||||
activestorage (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
actionview (= 7.0.8)
|
||||
activejob (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actionmailer (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
actionview (= 7.0.8.1)
|
||||
activejob (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.8)
|
||||
actionview (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actionpack (7.0.8.1)
|
||||
actionview (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
activerecord (= 7.0.8)
|
||||
activestorage (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actiontext (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
activerecord (= 7.0.8.1)
|
||||
activestorage (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
actionview (7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
active_record_query_trace (1.8)
|
||||
activejob (7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
activejob (7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
activerecord (7.0.8)
|
||||
activemodel (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
activemodel (7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
activerecord (7.0.8.1)
|
||||
activemodel (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
activerecord-import (1.4.1)
|
||||
activerecord (>= 4.2)
|
||||
activestorage (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
activejob (= 7.0.8)
|
||||
activerecord (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
activestorage (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
activejob (= 7.0.8.1)
|
||||
activerecord (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (7.0.8)
|
||||
activesupport (7.0.8.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -559,12 +559,12 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.3)
|
||||
rack (2.2.8)
|
||||
rack (2.2.8.1)
|
||||
rack-attack (6.7.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-contrib (2.4.0)
|
||||
rack (< 4)
|
||||
rack-cors (2.0.1)
|
||||
rack-cors (2.0.0)
|
||||
rack (>= 2.0.0)
|
||||
rack-mini-profiler (3.2.0)
|
||||
rack (>= 1.2.0)
|
||||
@@ -575,20 +575,20 @@ GEM
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rack-timeout (0.6.3)
|
||||
rails (7.0.8)
|
||||
actioncable (= 7.0.8)
|
||||
actionmailbox (= 7.0.8)
|
||||
actionmailer (= 7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
actiontext (= 7.0.8)
|
||||
actionview (= 7.0.8)
|
||||
activejob (= 7.0.8)
|
||||
activemodel (= 7.0.8)
|
||||
activerecord (= 7.0.8)
|
||||
activestorage (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
rails (7.0.8.1)
|
||||
actioncable (= 7.0.8.1)
|
||||
actionmailbox (= 7.0.8.1)
|
||||
actionmailer (= 7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
actiontext (= 7.0.8.1)
|
||||
actionview (= 7.0.8.1)
|
||||
activejob (= 7.0.8.1)
|
||||
activemodel (= 7.0.8.1)
|
||||
activerecord (= 7.0.8.1)
|
||||
activestorage (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.0.8)
|
||||
railties (= 7.0.8.1)
|
||||
rails-dom-testing (2.2.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
@@ -596,9 +596,9 @@ GEM
|
||||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
railties (7.0.8)
|
||||
actionpack (= 7.0.8)
|
||||
activesupport (= 7.0.8)
|
||||
railties (7.0.8.1)
|
||||
actionpack (= 7.0.8.1)
|
||||
activesupport (= 7.0.8.1)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -918,10 +918,10 @@ DEPENDENCIES
|
||||
puma
|
||||
pundit
|
||||
rack-attack (>= 6.7.0)
|
||||
rack-cors
|
||||
rack-cors (= 2.0.0)
|
||||
rack-mini-profiler (>= 3.2.0)
|
||||
rack-timeout
|
||||
rails (~> 7.0.8.0)
|
||||
rails (~> 7.0.8.1)
|
||||
redis
|
||||
redis-namespace
|
||||
responders (>= 3.1.1)
|
||||
|
||||
@@ -23,7 +23,6 @@ Customer engagement suite, an open-source alternative to Intercom, Zendesk, Sale
|
||||
<img src="https://img.shields.io/github/commit-activity/m/chatwoot/chatwoot" alt="Commits-per-month">
|
||||
<a title="Crowdin" target="_self" href="https://chatwoot.crowdin.com/chatwoot"><img src="https://badges.crowdin.net/e/37ced7eba411064bd792feb3b7a28b16/localized.svg"></a>
|
||||
<a href="https://discord.gg/cJXdrwS"><img src="https://img.shields.io/discord/647412545203994635" alt="Discord"></a>
|
||||
<a href="https://huntr.dev/bounties/disclose"><img src="https://cdn.huntr.dev/huntr_security_badge_mono.svg" alt="Huntr"></a>
|
||||
<a href="https://status.chatwoot.com"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchatwoot%2Fstatus%2Fmaster%2Fapi%2Fchatwoot%2Fuptime.json" alt="uptime"></a>
|
||||
<a href="https://status.chatwoot.com"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchatwoot%2Fstatus%2Fmaster%2Fapi%2Fchatwoot%2Fresponse-time.json" alt="response time"></a>
|
||||
<a href="https://artifacthub.io/packages/helm/chatwoot/chatwoot"><img src="https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/artifact-hub" alt="Artifact HUB"></a>
|
||||
|
||||
5
app.json
5
app.json
@@ -72,6 +72,11 @@
|
||||
"scripts": {
|
||||
"test": "bundle exec rake test"
|
||||
}
|
||||
},
|
||||
"review": {
|
||||
"scripts": {
|
||||
"postdeploy": "bundle exec rails db:seed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class ContactIdentifyAction
|
||||
def existing_email_contact
|
||||
return if params[:email].blank?
|
||||
|
||||
@existing_email_contact ||= account.contacts.find_by(email: params[:email])
|
||||
@existing_email_contact ||= account.contacts.from_email(params[:email])
|
||||
end
|
||||
|
||||
def existing_phone_number_contact
|
||||
|
||||
@@ -27,7 +27,7 @@ class AgentBuilder
|
||||
# Finds a user by email or creates a new one with a temporary password.
|
||||
# @return [User] the found or created user.
|
||||
def find_or_create_user
|
||||
user = User.find_by(email: email)
|
||||
user = User.from_email(email)
|
||||
return user if user
|
||||
|
||||
temp_password = "1!aA#{SecureRandom.alphanumeric(12)}"
|
||||
|
||||
@@ -75,7 +75,7 @@ class ContactInboxWithContactBuilder
|
||||
def find_contact_by_email(email)
|
||||
return if email.blank?
|
||||
|
||||
account.contacts.find_by(email: email.downcase)
|
||||
account.contacts.from_email(email)
|
||||
end
|
||||
|
||||
def find_contact_by_phone_number(phone_number)
|
||||
|
||||
@@ -54,6 +54,13 @@ class V2::ReportBuilder
|
||||
}
|
||||
end
|
||||
|
||||
def bot_summary
|
||||
{
|
||||
bot_resolutions_count: bot_resolutions.count,
|
||||
bot_handoffs_count: bot_handoffs.count
|
||||
}
|
||||
end
|
||||
|
||||
def conversation_metrics
|
||||
if params[:type].equal?(:account)
|
||||
live_conversations
|
||||
@@ -71,6 +78,8 @@ class V2::ReportBuilder
|
||||
avg_first_response_time
|
||||
avg_resolution_time reply_time
|
||||
resolutions_count
|
||||
bot_resolutions_count
|
||||
bot_handoffs_count
|
||||
reply_time].include?(params[:metric])
|
||||
end
|
||||
|
||||
@@ -123,6 +132,7 @@ class V2::ReportBuilder
|
||||
unattended: @open_conversations.unattended.count
|
||||
}
|
||||
metric[:unassigned] = @open_conversations.unassigned.count if params[:type].equal?(:account)
|
||||
metric[:pending] = @open_conversations.pending.count if params[:type].equal?(:account)
|
||||
metric
|
||||
end
|
||||
end
|
||||
|
||||
54
app/builders/v2/reports/bot_metrics_builder.rb
Normal file
54
app/builders/v2/reports/bot_metrics_builder.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
class V2::Reports::BotMetricsBuilder
|
||||
include DateRangeHelper
|
||||
attr_reader :account, :params
|
||||
|
||||
def initialize(account, params)
|
||||
@account = account
|
||||
@params = params
|
||||
end
|
||||
|
||||
def metrics
|
||||
{
|
||||
conversation_count: bot_conversations.count,
|
||||
message_count: bot_messages.count,
|
||||
resolution_rate: bot_resolution_rate.to_i,
|
||||
handoff_rate: bot_handoff_rate.to_i
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def bot_activated_inbox_ids
|
||||
@bot_activated_inbox_ids ||= account.inboxes.filter(&:active_bot?).map(&:id)
|
||||
end
|
||||
|
||||
def bot_conversations
|
||||
@bot_conversations ||= account.conversations.where(inbox_id: bot_activated_inbox_ids).where(created_at: range)
|
||||
end
|
||||
|
||||
def bot_messages
|
||||
@bot_messages ||= account.messages.outgoing.where(conversation_id: bot_conversations.ids).where(created_at: range)
|
||||
end
|
||||
|
||||
def bot_resolutions_count
|
||||
account.reporting_events.joins(:conversation).select(:conversation_id).where(account_id: account.id, name: :conversation_bot_resolved,
|
||||
created_at: range).distinct.count
|
||||
end
|
||||
|
||||
def bot_handoffs_count
|
||||
account.reporting_events.joins(:conversation).select(:conversation_id).where(account_id: account.id, name: :conversation_bot_handoff,
|
||||
created_at: range).distinct.count
|
||||
end
|
||||
|
||||
def bot_resolution_rate
|
||||
return 0 if bot_conversations.count.zero?
|
||||
|
||||
bot_resolutions_count.to_f / bot_conversations.count * 100
|
||||
end
|
||||
|
||||
def bot_handoff_rate
|
||||
return 0 if bot_conversations.count.zero?
|
||||
|
||||
bot_handoffs_count.to_f / bot_conversations.count * 100
|
||||
end
|
||||
end
|
||||
@@ -49,6 +49,11 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController
|
||||
Rails.logger.info "[Agent#bulk_create] ignoring email #{email}, errors: #{e.record.errors}"
|
||||
end
|
||||
end
|
||||
|
||||
# This endpoint is used to bulk create agents during onboarding
|
||||
# onboarding_step key in present in Current account custom attributes, since this is a one time operation
|
||||
Current.account.custom_attributes.delete('onboarding_step')
|
||||
Current.account.save!
|
||||
head :ok
|
||||
end
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
|
||||
def export
|
||||
column_names = params['column_names']
|
||||
Account::ContactsExportJob.perform_later(Current.account.id, column_names)
|
||||
Account::ContactsExportJob.perform_later(Current.account.id, column_names, Current.user.email)
|
||||
head :ok, message: I18n.t('errors.contacts.export.success')
|
||||
end
|
||||
|
||||
@@ -148,7 +148,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params.permit(:name, :identifier, :email, :phone_number, :avatar, :avatar_url, additional_attributes: {}, custom_attributes: {})
|
||||
params.permit(:name, :identifier, :email, :phone_number, :avatar, :blocked, :avatar_url, additional_attributes: {}, custom_attributes: {})
|
||||
end
|
||||
|
||||
def contact_custom_attributes
|
||||
|
||||
@@ -36,6 +36,10 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@conversation.update!(permitted_update_params)
|
||||
end
|
||||
|
||||
def filter
|
||||
result = ::Conversations::FilterService.new(params.permit!, current_user).perform
|
||||
@conversations = result[:conversations]
|
||||
@@ -110,6 +114,11 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
|
||||
private
|
||||
|
||||
def permitted_update_params
|
||||
# TODO: Move the other conversation attributes to this method and remove specific endpoints for each attribute
|
||||
params.permit(:priority)
|
||||
end
|
||||
|
||||
def update_last_seen_on_conversation(last_seen_at, update_assignee)
|
||||
# rubocop:disable Rails/SkipsModelValidations
|
||||
@conversation.update_column(:agent_last_seen_at, last_seen_at)
|
||||
@@ -176,3 +185,5 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
@conversation.assignee_id? && Current.user == @conversation.assignee
|
||||
end
|
||||
end
|
||||
|
||||
Api::V1::Accounts::ConversationsController.prepend_mod_with('Api::V1::Accounts::ConversationsController')
|
||||
|
||||
@@ -54,7 +54,8 @@ class Api::V1::Accounts::NotificationsController < Api::V1::Accounts::BaseContro
|
||||
end
|
||||
|
||||
def snooze
|
||||
@notification.update(snoozed_until: parse_date_time(params[:snoozed_until].to_s)) if params[:snoozed_until]
|
||||
updated_meta = (@notification.meta || {}).merge('last_snoozed_at' => nil)
|
||||
@notification.update(snoozed_until: parse_date_time(params[:snoozed_until].to_s), meta: updated_meta) if params[:snoozed_until]
|
||||
render json: @notification
|
||||
end
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||
def update
|
||||
@account.assign_attributes(account_params.slice(:name, :locale, :domain, :support_email, :auto_resolve_duration))
|
||||
@account.custom_attributes.merge!(custom_attributes_params)
|
||||
@account.custom_attributes['onboarding_step'] = 'invite_team' if @account.custom_attributes['onboarding_step'] == 'account_update'
|
||||
@account.save!
|
||||
end
|
||||
|
||||
|
||||
@@ -14,6 +14,12 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
||||
render json: summary_metrics
|
||||
end
|
||||
|
||||
def bot_summary
|
||||
summary = V2::ReportBuilder.new(Current.account, current_summary_params).bot_summary
|
||||
summary[:previous] = V2::ReportBuilder.new(Current.account, previous_summary_params).bot_summary
|
||||
render json: summary
|
||||
end
|
||||
|
||||
def agents
|
||||
@report_data = generate_agents_report
|
||||
generate_csv('agents_report', 'api/v2/accounts/reports/agents')
|
||||
@@ -48,6 +54,11 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
||||
render json: conversation_metrics
|
||||
end
|
||||
|
||||
def bot_metrics
|
||||
bot_metrics = V2::Reports::BotMetricsBuilder.new(Current.account, params).metrics
|
||||
render json: bot_metrics
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_csv(filename, template)
|
||||
|
||||
@@ -22,6 +22,7 @@ class Api::V2::AccountsController < Api::BaseController
|
||||
).perform
|
||||
|
||||
fetch_account_and_user_info
|
||||
update_account_info if @account.present?
|
||||
|
||||
if @user
|
||||
send_auth_headers(@user)
|
||||
@@ -33,6 +34,18 @@ class Api::V2::AccountsController < Api::BaseController
|
||||
|
||||
private
|
||||
|
||||
def account_attributes
|
||||
{
|
||||
custom_attributes: @account.custom_attributes.merge({ 'onboarding_step' => 'profile_update' })
|
||||
}
|
||||
end
|
||||
|
||||
def update_account_info
|
||||
@account.update!(
|
||||
account_attributes
|
||||
)
|
||||
end
|
||||
|
||||
def fetch_account_and_user_info; end
|
||||
|
||||
def fetch_account
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module AccessTokenAuthHelper
|
||||
BOT_ACCESSIBLE_ENDPOINTS = {
|
||||
'api/v1/accounts/conversations' => %w[toggle_status toggle_priority create],
|
||||
'api/v1/accounts/conversations' => %w[toggle_status toggle_priority create update],
|
||||
'api/v1/accounts/conversations/messages' => ['create'],
|
||||
'api/v1/accounts/conversations/assignments' => ['create']
|
||||
}.freeze
|
||||
|
||||
@@ -55,7 +55,7 @@ class DashboardController < ActionController::Base
|
||||
VAPID_PUBLIC_KEY: VapidService.public_key,
|
||||
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false'),
|
||||
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', ''),
|
||||
FACEBOOK_API_VERSION: 'v14.0',
|
||||
FACEBOOK_API_VERSION: GlobalConfigService.load('FACEBOOK_API_VERSION', 'v17.0'),
|
||||
IS_ENTERPRISE: ChatwootApp.enterprise?,
|
||||
AZURE_APP_ID: ENV.fetch('AZURE_APP_ID', ''),
|
||||
GIT_SHA: GIT_HASH
|
||||
|
||||
@@ -5,7 +5,7 @@ class DeviseOverrides::PasswordsController < Devise::PasswordsController
|
||||
skip_before_action :authenticate_user!, raise: false
|
||||
|
||||
def create
|
||||
@user = User.find_by(email: params[:email])
|
||||
@user = User.from_email(params[:email])
|
||||
if @user
|
||||
@user.send_reset_password_instructions
|
||||
build_response(I18n.t('messages.reset_password_success'), 200)
|
||||
|
||||
@@ -33,7 +33,7 @@ class DeviseOverrides::SessionsController < DeviseTokenAuth::SessionsController
|
||||
def process_sso_auth_token
|
||||
return if params[:email].blank?
|
||||
|
||||
user = User.find_by(email: params[:email])
|
||||
user = User.from_email(params[:email])
|
||||
@resource = user if user&.valid_sso_auth_token?(params[:sso_auth_token])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ class Platform::Api::V1::UsersController < PlatformController
|
||||
def show; end
|
||||
|
||||
def create
|
||||
@resource = (User.find_by(email: user_params[:email]) || User.new(user_params))
|
||||
@resource = (User.from_email(user_params[:email]) || User.new(user_params))
|
||||
@resource.skip_confirmation!
|
||||
@resource.save!
|
||||
@platform_app.platform_app_permissibles.find_or_create_by!(permissible: @resource)
|
||||
|
||||
@@ -1,15 +1,31 @@
|
||||
class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::InboxesController
|
||||
include Events::Types
|
||||
before_action :set_conversation, only: [:toggle_typing, :update_last_seen]
|
||||
before_action :set_conversation, only: [:toggle_typing, :update_last_seen, :show, :toggle_status]
|
||||
|
||||
def index
|
||||
@conversations = @contact_inbox.hmac_verified? ? @contact.conversations : @contact_inbox.conversations
|
||||
end
|
||||
|
||||
def show; end
|
||||
|
||||
def create
|
||||
@conversation = create_conversation
|
||||
end
|
||||
|
||||
def toggle_status
|
||||
# Check if the conversation is already resolved to prevent redundant operations
|
||||
return if @conversation.resolved?
|
||||
|
||||
# Assign the conversation's contact as the resolver
|
||||
# This step attributes the resolution action to the contact involved in the conversation
|
||||
# If this assignment is not made, the system implicitly becomes the resolver by default
|
||||
Current.contact = @conversation.contact
|
||||
|
||||
# Update the conversation's status to 'resolved' to reflect its closure
|
||||
@conversation.status = :resolved
|
||||
@conversation.save!
|
||||
end
|
||||
|
||||
def toggle_typing
|
||||
case params[:typing_status]
|
||||
when 'on'
|
||||
@@ -30,7 +46,11 @@ class Public::Api::V1::Inboxes::ConversationsController < Public::Api::V1::Inbox
|
||||
private
|
||||
|
||||
def set_conversation
|
||||
@conversation = @contact_inbox.contact.conversations.find_by!(display_id: params[:id])
|
||||
@conversation = if @contact_inbox.hmac_verified?
|
||||
@contact_inbox.contact.conversations.find_by!(display_id: params[:id])
|
||||
else
|
||||
@contact_inbox.conversations.find_by!(display_id: params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
def create_conversation
|
||||
|
||||
@@ -34,7 +34,7 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController
|
||||
def allowed_configs
|
||||
@allowed_configs = case @config
|
||||
when 'facebook'
|
||||
%w[FB_APP_ID FB_VERIFY_TOKEN FB_APP_SECRET IG_VERIFY_TOKEN ENABLE_MESSENGER_CHANNEL_HUMAN_AGENT]
|
||||
%w[FB_APP_ID FB_VERIFY_TOKEN FB_APP_SECRET IG_VERIFY_TOKEN FACEBOOK_API_VERSION ENABLE_MESSENGER_CHANNEL_HUMAN_AGENT]
|
||||
when 'email'
|
||||
['MAILER_INBOUND_EMAIL_DOMAIN']
|
||||
else
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
# If you want to add pagination or other controller-level concerns,
|
||||
# you're free to overwrite the RESTful controller actions.
|
||||
class SuperAdmin::ApplicationController < Administrate::ApplicationController
|
||||
include ActionView::Helpers::TagHelper
|
||||
include ActionView::Context
|
||||
|
||||
helper_method :render_vue_component
|
||||
# authenticiation done via devise : SuperAdmin Model
|
||||
before_action :authenticate_super_admin!
|
||||
|
||||
@@ -23,6 +27,17 @@ class SuperAdmin::ApplicationController < Administrate::ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def render_vue_component(component_name, props = {})
|
||||
html_options = {
|
||||
id: 'app',
|
||||
data: {
|
||||
component_name: component_name,
|
||||
props: props.to_json
|
||||
}
|
||||
}
|
||||
content_tag(:div, '', html_options)
|
||||
end
|
||||
|
||||
def invalid_action_perfomed
|
||||
# rubocop:disable Rails/I18nLocaleTexts
|
||||
flash[:error] = 'Invalid action performed'
|
||||
|
||||
83
app/helpers/contact_helper.rb
Normal file
83
app/helpers/contact_helper.rb
Normal file
@@ -0,0 +1,83 @@
|
||||
module ContactHelper
|
||||
def parse_name(full_name)
|
||||
# If the input is nil or not a string, return a hash with all values set to nil
|
||||
return default_name_hash if invalid_name?(full_name)
|
||||
|
||||
# If the input is a number, return a hash with the number as the first name
|
||||
return numeric_name_hash(full_name) if valid_number?(full_name)
|
||||
|
||||
full_name = full_name.squish
|
||||
|
||||
# If full name consists of only one word, consider it as the first name
|
||||
return single_word_name_hash(full_name) if single_word?(full_name)
|
||||
|
||||
parts = split_name(full_name)
|
||||
parts = handle_conjunction(parts)
|
||||
build_name_hash(parts)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_name_hash
|
||||
{ first_name: nil, last_name: nil, middle_name: nil, prefix: nil, suffix: nil }
|
||||
end
|
||||
|
||||
def invalid_name?(full_name)
|
||||
!full_name.is_a?(String) || full_name.empty?
|
||||
end
|
||||
|
||||
def numeric_name_hash(full_name)
|
||||
{ first_name: full_name, last_name: nil, middle_name: nil, prefix: nil, suffix: nil }
|
||||
end
|
||||
|
||||
def valid_number?(full_name)
|
||||
full_name.gsub(/\s+/, '').match?(/\A\+?\d+\z/)
|
||||
end
|
||||
|
||||
def single_word_name_hash(full_name)
|
||||
{ first_name: full_name, last_name: nil, middle_name: nil, prefix: nil, suffix: nil }
|
||||
end
|
||||
|
||||
def single_word?(full_name)
|
||||
full_name.split.size == 1
|
||||
end
|
||||
|
||||
def split_name(full_name)
|
||||
full_name.split
|
||||
end
|
||||
|
||||
def handle_conjunction(parts)
|
||||
conjunctions = ['and', '&']
|
||||
parts.each_index do |i|
|
||||
next unless conjunctions.include?(parts[i]) && i.positive?
|
||||
|
||||
parts[i - 1] = [parts[i - 1], parts[i + 1]].join(' ')
|
||||
parts.delete_at(i)
|
||||
parts.delete_at(i)
|
||||
end
|
||||
parts
|
||||
end
|
||||
|
||||
def build_name_hash(parts)
|
||||
suffix = parts.pop if parts.last.match?(/(\w+\.|[IVXLM]+|[A-Z]+)$/)
|
||||
last_name = parts.pop
|
||||
prefix = parts.shift if parts.first.match?(/^\w+\./)
|
||||
first_name = parts.shift
|
||||
middle_name = parts.join(' ')
|
||||
|
||||
hash = {
|
||||
first_name: first_name,
|
||||
last_name: last_name,
|
||||
prefix: prefix,
|
||||
middle_name: middle_name,
|
||||
suffix: suffix
|
||||
}
|
||||
|
||||
# Reverse name if "," was used in Last, First notation.
|
||||
if hash[:first_name] =~ /,$/
|
||||
hash[:first_name] = hash[:last_name]
|
||||
hash[:last_name] = Regexp.last_match.pre_match
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
||||
@@ -32,6 +32,14 @@ module ReportHelper
|
||||
(get_grouped_values resolutions).count
|
||||
end
|
||||
|
||||
def bot_resolutions_count
|
||||
(get_grouped_values bot_resolutions).count
|
||||
end
|
||||
|
||||
def bot_handoffs_count
|
||||
(get_grouped_values bot_handoffs).count
|
||||
end
|
||||
|
||||
def conversations
|
||||
scope.conversations.where(account_id: account.id, created_at: range)
|
||||
end
|
||||
@@ -49,6 +57,16 @@ module ReportHelper
|
||||
conversations: { status: :resolved }, created_at: range).distinct
|
||||
end
|
||||
|
||||
def bot_resolutions
|
||||
scope.reporting_events.joins(:conversation).select(:conversation_id).where(account_id: account.id, name: :conversation_bot_resolved,
|
||||
conversations: { status: :resolved }, created_at: range).distinct
|
||||
end
|
||||
|
||||
def bot_handoffs
|
||||
scope.reporting_events.joins(:conversation).select(:conversation_id).where(account_id: account.id, name: :conversation_bot_handoff,
|
||||
created_at: range).distinct
|
||||
end
|
||||
|
||||
def avg_first_response_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'first_response', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
>
|
||||
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
|
||||
<template v-if="currentAccountId">
|
||||
<pending-email-verification-banner />
|
||||
<payment-pending-banner />
|
||||
<pending-email-verification-banner v-if="hideOnOnboardingView" />
|
||||
<payment-pending-banner v-if="hideOnOnboardingView" />
|
||||
<upgrade-banner />
|
||||
</template>
|
||||
<transition name="fade" mode="out-in">
|
||||
@@ -38,6 +38,7 @@ import vueActionCable from './helper/actionCable';
|
||||
import WootSnackbarBox from './components/SnackbarContainer.vue';
|
||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||
import { setColorTheme } from './helper/themeHelper';
|
||||
import { isOnOnboardingView } from 'v3/helpers/RouteHelper';
|
||||
import {
|
||||
registerSubscription,
|
||||
verifyServiceWorkerExistence,
|
||||
@@ -79,6 +80,9 @@ export default {
|
||||
const { accounts = [] } = this.currentUser || {};
|
||||
return accounts.length > 0;
|
||||
},
|
||||
hideOnOnboardingView() {
|
||||
return !isOnOnboardingView(this.$route);
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
||||
@@ -84,6 +84,24 @@ class ReportsAPI extends ApiClient {
|
||||
params: { since, until, business_hours: businessHours },
|
||||
});
|
||||
}
|
||||
|
||||
getBotMetrics({ from, to } = {}) {
|
||||
return axios.get(`${this.url}/bot_metrics`, {
|
||||
params: { since: from, until: to },
|
||||
});
|
||||
}
|
||||
|
||||
getBotSummary({ from, to, groupBy, businessHours } = {}) {
|
||||
return axios.get(`${this.url}/bot_summary`, {
|
||||
params: {
|
||||
since: from,
|
||||
until: to,
|
||||
type: 'account',
|
||||
group_by: groupBy,
|
||||
business_hours: businessHours,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new ReportsAPI();
|
||||
|
||||
9
app/javascript/dashboard/api/sla.js
Normal file
9
app/javascript/dashboard/api/sla.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import ApiClient from './ApiClient';
|
||||
|
||||
class SlaAPI extends ApiClient {
|
||||
constructor() {
|
||||
super('sla_policies', { accountScoped: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default new SlaAPI();
|
||||
@@ -111,6 +111,40 @@ describe('#Reports API', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('#getBotMetrics', () => {
|
||||
reportsAPI.getBotMetrics({ from: 1621103400, to: 1621621800 });
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v2/reports/bot_metrics',
|
||||
{
|
||||
params: {
|
||||
since: 1621103400,
|
||||
until: 1621621800,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#getBotSummary', () => {
|
||||
reportsAPI.getBotSummary({
|
||||
from: 1621103400,
|
||||
to: 1621621800,
|
||||
groupBy: 'date',
|
||||
businessHours: true,
|
||||
});
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v2/reports/bot_summary',
|
||||
{
|
||||
params: {
|
||||
since: 1621103400,
|
||||
until: 1621621800,
|
||||
type: 'account',
|
||||
group_by: 'date',
|
||||
business_hours: true,
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('#getConversationMetric', () => {
|
||||
reportsAPI.getConversationMetric('account');
|
||||
expect(axiosMock.get).toHaveBeenCalledWith(
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
.button {
|
||||
font-family: $body-font-family;
|
||||
font-weight: $font-weight-medium;
|
||||
|
||||
&.round {
|
||||
border-radius: 1000px;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin-bottom: var(--space-small);
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
code {
|
||||
border: 0;
|
||||
font-family: 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas',
|
||||
'"Liberation Mono"', '"Courier New"', 'monospace';
|
||||
font-size: $font-size-mini;
|
||||
|
||||
&.hljs {
|
||||
background: $color-background;
|
||||
border-radius: var(--border-radius-large);
|
||||
padding: $space-two;
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100;
|
||||
}
|
||||
}
|
||||
|
||||
.text-truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.text-capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// remove when grid gutters are fixed
|
||||
.columns.with-right-space {
|
||||
padding-right: var(--space-normal);
|
||||
}
|
||||
|
||||
.badge {
|
||||
border-radius: var(--border-radius-normal);
|
||||
}
|
||||
|
||||
.padding-right-small {
|
||||
padding-right: var(--space-one);
|
||||
}
|
||||
@@ -1,623 +0,0 @@
|
||||
// Foundation for Sites Settings
|
||||
// -----------------------------
|
||||
//
|
||||
// Table of Contents:
|
||||
//
|
||||
// 1. Global
|
||||
// 2. Breakpoints
|
||||
// 3. The Grid
|
||||
// 4. Base Typography
|
||||
// 5. Typography Helpers
|
||||
// 6. Abide
|
||||
// 7. Accordion
|
||||
// 8. Accordion Menu
|
||||
// 9. Badge
|
||||
// 10. Breadcrumbs
|
||||
// 11. Button
|
||||
// 12. Button Group
|
||||
// 13. Callout
|
||||
// 14. Card
|
||||
// 15. Close Button
|
||||
// 16. Drilldown
|
||||
// 17. Dropdown
|
||||
// 18. Dropdown Menu
|
||||
// 19. Forms
|
||||
// 20. Label
|
||||
// 21. Media Object
|
||||
// 22. Menu
|
||||
// 23. Meter
|
||||
// 24. Off-canvas
|
||||
// 25. Orbit
|
||||
// 26. Pagination
|
||||
// 27. Progress Bar
|
||||
// 28. Responsive Embed
|
||||
// 29. Reveal
|
||||
// 30. Slider
|
||||
// 31. Switch
|
||||
// 32. Table
|
||||
// 33. Tabs
|
||||
// 34. Thumbnail
|
||||
// 35. Title Bar
|
||||
// 36. Tooltip
|
||||
// 37. Top Bar
|
||||
|
||||
@import '~foundation-sites/scss/util/util';
|
||||
// 1. Global
|
||||
// ---------
|
||||
|
||||
// Disable contrast warnings in Foundation.
|
||||
$contrast-warnings: false;
|
||||
|
||||
$global-font-size: 16px;
|
||||
$global-width: 100%;
|
||||
$global-lineheight: 1.5;
|
||||
$foundation-palette: (primary: $color-woot,
|
||||
secondary: #5d7592,
|
||||
success: #44ce4b,
|
||||
warning: #ffc532,
|
||||
alert: #ff382d);
|
||||
$light-gray: #c0ccda;
|
||||
$medium-gray: #8492a6;
|
||||
$dark-gray: $color-gray;
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
$body-background: $white;
|
||||
$body-font-color: $color-body;
|
||||
$body-font-family: 'PlusJakarta',
|
||||
-apple-system,
|
||||
system-ui,
|
||||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
Roboto,
|
||||
"Helvetica Neue",
|
||||
Tahoma,
|
||||
Arial,
|
||||
sans-serif;
|
||||
$body-antialiased: true;
|
||||
$global-margin: $space-small;
|
||||
$global-padding: $space-small;
|
||||
$global-weight-normal: normal;
|
||||
$global-weight-bold: bold;
|
||||
$global-radius: 0;
|
||||
$global-text-direction: ltr;
|
||||
$global-flexbox: false;
|
||||
$print-transparent-backgrounds: true;
|
||||
|
||||
@include add-foundation-colors;
|
||||
|
||||
// 2. Breakpoints
|
||||
// --------------
|
||||
|
||||
$breakpoints: (small: 0,
|
||||
medium: 640px,
|
||||
large: 1024px,
|
||||
xlarge: 1200px,
|
||||
xxlarge: 1400px,
|
||||
xxxlarge: 1600px,
|
||||
);
|
||||
$print-breakpoint: large;
|
||||
$breakpoint-classes: (small medium large);
|
||||
|
||||
// 3. The Grid
|
||||
// -----------
|
||||
|
||||
$grid-row-width: $global-width;
|
||||
$grid-column-count: 12;
|
||||
$grid-column-gutter: (small: $zero,
|
||||
medium: $zero);
|
||||
$grid-column-align-edge: true;
|
||||
$block-grid-max: 8;
|
||||
|
||||
// 4. Base Typography
|
||||
// ------------------
|
||||
|
||||
$header-font-family: $body-font-family;
|
||||
$header-font-weight: $font-weight-medium;
|
||||
$header-font-style: normal;
|
||||
$font-family-monospace: $body-font-family;
|
||||
$header-color: $color-heading;
|
||||
$header-lineheight: 1.4;
|
||||
$header-margin-bottom: 0.3125rem;
|
||||
$header-styles: (small: ("h1": ("font-size": 24),
|
||||
"h2": ("font-size": 20),
|
||||
"h3": ("font-size": 19),
|
||||
"h4": ("font-size": 18),
|
||||
"h5": ("font-size": 17),
|
||||
"h6": ("font-size": 16)),
|
||||
medium: ("h1": ("font-size": 48),
|
||||
"h2": ("font-size": 40),
|
||||
"h3": ("font-size": 31),
|
||||
"h4": ("font-size": 25),
|
||||
"h5": ("font-size": 20),
|
||||
"h6": ("font-size": 16)));
|
||||
$header-text-rendering: optimizeLegibility;
|
||||
$small-font-size: 80%;
|
||||
$header-small-font-color: $medium-gray;
|
||||
$paragraph-lineheight: 1.65;
|
||||
$paragraph-margin-bottom: var(--space-small);
|
||||
$paragraph-text-rendering: optimizeLegibility;
|
||||
$code-color: $black;
|
||||
$code-font-family: $font-family-monospace;
|
||||
$code-font-weight: $global-weight-normal;
|
||||
$code-background: $light-gray;
|
||||
$code-border: 1px solid $medium-gray;
|
||||
$code-padding: rem-calc(2 5 1);
|
||||
$anchor-color: $primary-color;
|
||||
$anchor-color-hover: scale-color($anchor-color, $lightness: -14%);
|
||||
$anchor-text-decoration: none;
|
||||
$anchor-text-decoration-hover: none;
|
||||
$hr-width: $global-width;
|
||||
$hr-border: 1px solid $medium-gray;
|
||||
$hr-margin: rem-calc(20) auto;
|
||||
$list-lineheight: $paragraph-lineheight;
|
||||
$list-margin-bottom: $paragraph-margin-bottom;
|
||||
$list-style-type: disc;
|
||||
$list-style-position: outside;
|
||||
$list-side-margin: 0.78125rem;
|
||||
$list-nested-side-margin: 0.78125rem;
|
||||
$defnlist-margin-bottom: 0.6875rem;
|
||||
$defnlist-term-weight: $global-weight-bold;
|
||||
$defnlist-term-margin-bottom: 0.1875rem;
|
||||
$blockquote-color: $dark-gray;
|
||||
$blockquote-padding: rem-calc(9 20 0 19);
|
||||
$blockquote-border: 1px solid $medium-gray;
|
||||
$cite-font-size: rem-calc(13);
|
||||
$cite-color: $dark-gray;
|
||||
$cite-pseudo-content: '\2014 \0020';
|
||||
$keystroke-font: $font-family-monospace;
|
||||
$keystroke-color: $black;
|
||||
$keystroke-background: $light-gray;
|
||||
$keystroke-padding: rem-calc(2 4 0);
|
||||
$keystroke-radius: $global-radius;
|
||||
$abbr-underline: 1px dotted $black;
|
||||
|
||||
// 5. Typography Helpers
|
||||
// ---------------------
|
||||
|
||||
$lead-font-size: $global-font-size * 1.25;
|
||||
$lead-lineheight: 1.6;
|
||||
$subheader-lineheight: 1.4;
|
||||
$subheader-color: $dark-gray;
|
||||
$subheader-font-weight: $global-weight-normal;
|
||||
$subheader-margin-top: 0.125rem;
|
||||
$subheader-margin-bottom: 0.3125rem;
|
||||
$stat-font-size: 1.5625rem;
|
||||
|
||||
// 6. Abide
|
||||
// --------
|
||||
|
||||
$abide-inputs: true;
|
||||
$abide-labels: true;
|
||||
$input-background-invalid: get-color(alert);
|
||||
$form-label-color-invalid: get-color(alert);
|
||||
$input-error-color: get-color(alert);
|
||||
$input-error-font-size: rem-calc(12);
|
||||
$input-error-font-weight: $global-weight-bold;
|
||||
|
||||
// 7. Accordion
|
||||
// ------------
|
||||
|
||||
$accordion-background: $white;
|
||||
$accordion-plusminus: true;
|
||||
$accordion-title-font-size: rem-calc(12);
|
||||
$accordion-item-color: $primary-color;
|
||||
$accordion-item-background-hover: $light-gray;
|
||||
$accordion-item-padding: 0.78125rem 0.625rem;
|
||||
$accordion-content-background: $white;
|
||||
$accordion-content-border: 1px solid $light-gray;
|
||||
$accordion-content-color: $body-font-color;
|
||||
$accordion-content-padding: 0.625rem;
|
||||
|
||||
// 8. Accordion Menu
|
||||
// -----------------
|
||||
|
||||
$accordionmenu-arrows: true;
|
||||
$accordionmenu-arrow-color: $primary-color;
|
||||
$accordionmenu-arrow-size: 6px;
|
||||
|
||||
// 9. Badge
|
||||
// --------
|
||||
|
||||
$badge-background: $primary-color;
|
||||
$badge-color: $white;
|
||||
$badge-color-alt: $black;
|
||||
$badge-palette: $foundation-palette;
|
||||
$badge-padding: var(--space-smaller);
|
||||
$badge-minwidth: 2.1em;
|
||||
$badge-font-size: var(--font-size-nano);
|
||||
|
||||
// 10. Breadcrumbs
|
||||
// ---------------
|
||||
|
||||
$breadcrumbs-margin: 0 0 $global-margin 0;
|
||||
$breadcrumbs-item-font-size: rem-calc(11);
|
||||
$breadcrumbs-item-color: $primary-color;
|
||||
$breadcrumbs-item-color-current: $black;
|
||||
$breadcrumbs-item-color-disabled: $medium-gray;
|
||||
$breadcrumbs-item-margin: 0.46875rem;
|
||||
$breadcrumbs-item-uppercase: true;
|
||||
$breadcrumbs-item-slash: true;
|
||||
|
||||
// 11. Button
|
||||
// ----------
|
||||
|
||||
$button-padding: var(--space-smaller) 1em;
|
||||
$button-margin: 0 0 $global-margin 0;
|
||||
$button-fill: solid;
|
||||
$button-background: $primary-color;
|
||||
$button-background-hover: scale-color($button-background, $lightness: -15%);
|
||||
$button-color: $white;
|
||||
$button-color-alt: $white;
|
||||
$button-radius: var(--border-radius-normal);
|
||||
$button-sizes: (tiny: var(--font-size-micro),
|
||||
small: var(--font-size-mini),
|
||||
default: var(--font-size-small),
|
||||
large: var(--font-size-medium));
|
||||
$button-palette: $foundation-palette;
|
||||
$button-opacity-disabled: 0.4;
|
||||
$button-background-hover-lightness: -20%;
|
||||
$button-hollow-hover-lightness: -50%;
|
||||
$button-transition: background-color 0.25s ease-out,
|
||||
color 0.25s ease-out;
|
||||
|
||||
// 12. Button Group
|
||||
// ----------------
|
||||
|
||||
$buttongroup-margin: 0;
|
||||
$buttongroup-spacing: 0;
|
||||
$buttongroup-child-selector: '.button';
|
||||
$buttongroup-expand-max: 6;
|
||||
$buttongroup-radius-on-each: false;
|
||||
|
||||
// 13. Callout
|
||||
// -----------
|
||||
|
||||
$callout-background: $white;
|
||||
$callout-background-fade: 85%;
|
||||
$callout-border: 1px solid rgba($black, 0.25);
|
||||
$callout-margin: 0 0 0.625rem 0;
|
||||
$callout-padding: 0.625rem;
|
||||
$callout-font-color: $body-font-color;
|
||||
$callout-font-color-alt: $body-background;
|
||||
$callout-radius: $global-radius;
|
||||
$callout-link-tint: 30%;
|
||||
|
||||
// 14. Card
|
||||
// --------
|
||||
|
||||
$card-background: $white;
|
||||
$card-font-color: $body-font-color;
|
||||
$card-divider-background: $light-gray;
|
||||
$card-border: 1px solid var(--color-border);
|
||||
$card-shadow: var(--shadow-small);
|
||||
$card-border-radius: var(--border-radius-normal);
|
||||
$card-padding: var(--space-small);
|
||||
$card-margin: $global-margin;
|
||||
|
||||
// 15. Close Button
|
||||
// ----------------
|
||||
|
||||
$closebutton-position: right top;
|
||||
$closebutton-offset-horizontal: (small: 0.66rem,
|
||||
medium: 1rem);
|
||||
$closebutton-offset-vertical: (small: 0.33em,
|
||||
medium: 0.5rem);
|
||||
$closebutton-size: (small: 1.5em,
|
||||
medium: 2em);
|
||||
$closebutton-lineheight: 1;
|
||||
$closebutton-color: $dark-gray;
|
||||
$closebutton-color-hover: $black;
|
||||
|
||||
// 16. Drilldown
|
||||
// -------------
|
||||
|
||||
$drilldown-transition: transform 0.15s linear;
|
||||
$drilldown-arrows: true;
|
||||
$drilldown-arrow-color: $primary-color;
|
||||
$drilldown-arrow-size: 6px;
|
||||
$drilldown-background: $white;
|
||||
|
||||
// 17. Dropdown
|
||||
// ------------
|
||||
|
||||
$dropdown-padding: 0.625rem;
|
||||
$dropdown-background: $body-background;
|
||||
$dropdown-border: 1px solid $medium-gray;
|
||||
$dropdown-font-size: 0.625rem;
|
||||
$dropdown-width: 300px;
|
||||
$dropdown-radius: $global-radius;
|
||||
$dropdown-sizes: (tiny: 100px,
|
||||
small: 200px,
|
||||
large: 400px);
|
||||
|
||||
// 18. Dropdown Menu
|
||||
// -----------------
|
||||
|
||||
$dropdownmenu-arrows: true;
|
||||
$dropdownmenu-arrow-color: $anchor-color;
|
||||
$dropdownmenu-arrow-size: 6px;
|
||||
$dropdownmenu-min-width: 200px;
|
||||
$dropdownmenu-background: $white;
|
||||
$dropdownmenu-border: 1px solid $medium-gray;
|
||||
|
||||
// 19. Forms
|
||||
// ---------
|
||||
|
||||
$fieldset-border: 1px solid $light-gray;
|
||||
$fieldset-padding: $space-two;
|
||||
$fieldset-margin: $space-one $zero;
|
||||
$legend-padding: rem-calc(0 3);
|
||||
$form-spacing: $space-normal;
|
||||
$helptext-color: $color-body;
|
||||
$helptext-font-size: $font-size-small;
|
||||
$helptext-font-style: italic;
|
||||
$input-prefix-color: $color-body;
|
||||
$input-prefix-background: var(--b-100);
|
||||
$input-prefix-border: 1px solid $color-border;
|
||||
$input-prefix-padding: 0.625rem;
|
||||
$form-label-color: $color-body;
|
||||
$form-label-font-size: rem-calc(14);
|
||||
$form-label-font-weight: $font-weight-medium;
|
||||
$form-label-line-height: 1.8;
|
||||
$select-background: $white;
|
||||
$select-triangle-color: $dark-gray;
|
||||
$select-radius: var(--border-radius-normal);
|
||||
$input-color: $color-body;
|
||||
$input-placeholder-color: $light-gray;
|
||||
$input-font-family: inherit;
|
||||
$input-font-size: $font-size-default;
|
||||
$input-font-weight: $global-weight-normal;
|
||||
$input-background: $white;
|
||||
$input-background-focus: $white;
|
||||
$input-background-disabled: $light-gray;
|
||||
$input-border: 1px solid var(--s-200);
|
||||
$input-border-focus: 1px solid lighten($primary-color, 15%);
|
||||
$input-shadow: 0;
|
||||
$input-shadow-focus: 0;
|
||||
$input-cursor-disabled: not-allowed;
|
||||
$input-transition: border-color 0.25s ease-in-out;
|
||||
$input-number-spinners: true;
|
||||
$input-radius: var(--border-radius-normal);
|
||||
$form-button-radius: var(--border-radius-normal);
|
||||
|
||||
// 20. Label
|
||||
// ---------
|
||||
|
||||
$label-background: $white;
|
||||
$label-color: $black;
|
||||
$label-color-alt: $black;
|
||||
$label-palette: $foundation-palette;
|
||||
$label-font-size: $font-size-mini;
|
||||
$label-padding: $space-smaller $space-small;
|
||||
$label-radius: var(--border-radius-small);
|
||||
|
||||
// 21. Media Object
|
||||
// ----------------
|
||||
|
||||
$mediaobject-margin-bottom: $global-margin;
|
||||
$mediaobject-section-padding: $global-padding;
|
||||
$mediaobject-image-width-stacked: 100%;
|
||||
|
||||
// 22. Menu
|
||||
// --------
|
||||
|
||||
$menu-margin: 0;
|
||||
$menu-margin-nested: $space-medium;
|
||||
$menu-item-padding: $space-slab;
|
||||
$menu-item-color-active: $white;
|
||||
$menu-item-background-active: $color-background;
|
||||
$menu-icon-spacing: 0.15625rem;
|
||||
$menu-item-background-hover: $light-gray;
|
||||
$menu-border: $light-gray;
|
||||
|
||||
// 23. Meter
|
||||
// ---------
|
||||
|
||||
$meter-height: 0.625rem;
|
||||
$meter-radius: $global-radius;
|
||||
$meter-background: $medium-gray;
|
||||
$meter-fill-good: $success-color;
|
||||
$meter-fill-medium: $warning-color;
|
||||
$meter-fill-bad: $alert-color;
|
||||
|
||||
// 24. Off-canvas
|
||||
// --------------
|
||||
|
||||
$offcanvas-sizes: (small: 14.375,
|
||||
medium: 14.375,
|
||||
);
|
||||
$offcanvas-vertical-sizes: (small: 14.375,
|
||||
medium: 14.375,
|
||||
);
|
||||
$offcanvas-background: $light-gray;
|
||||
$offcanvas-shadow: 0 0 10px rgba($black, 0.7);
|
||||
$offcanvas-push-zindex: 1;
|
||||
$offcanvas-overlap-zindex: 10;
|
||||
$offcanvas-reveal-zindex: 1;
|
||||
$offcanvas-transition-length: 0.5s;
|
||||
$offcanvas-transition-timing: ease;
|
||||
$offcanvas-fixed-reveal: true;
|
||||
$offcanvas-exit-background: rgba($white, 0.25);
|
||||
$maincontent-class: 'off-canvas-content';
|
||||
|
||||
// 25. Orbit
|
||||
// ---------
|
||||
|
||||
$orbit-bullet-background: $medium-gray;
|
||||
$orbit-bullet-background-active: $dark-gray;
|
||||
$orbit-bullet-diameter: 0.75rem;
|
||||
$orbit-bullet-margin: 0.0625rem;
|
||||
$orbit-bullet-margin-top: 0.5rem;
|
||||
$orbit-bullet-margin-bottom: 0.5rem;
|
||||
$orbit-caption-background: rgba($black, 0.5);
|
||||
$orbit-caption-padding: 0.625rem;
|
||||
$orbit-control-background-hover: rgba($black, 0.5);
|
||||
$orbit-control-padding: 0.625rem;
|
||||
$orbit-control-zindex: 10;
|
||||
|
||||
// 26. Pagination
|
||||
// --------------
|
||||
|
||||
$pagination-font-size: rem-calc(14);
|
||||
$pagination-margin-bottom: $global-margin;
|
||||
$pagination-item-color: $black;
|
||||
$pagination-item-padding: rem-calc(3 10);
|
||||
$pagination-item-spacing: rem-calc(1);
|
||||
$pagination-radius: $global-radius;
|
||||
$pagination-item-background-hover: $light-gray;
|
||||
$pagination-item-background-current: $primary-color;
|
||||
$pagination-item-color-current: $white;
|
||||
$pagination-item-color-disabled: $medium-gray;
|
||||
$pagination-ellipsis-color: $black;
|
||||
$pagination-mobile-items: false;
|
||||
$pagination-mobile-current-item: false;
|
||||
$pagination-arrows: true;
|
||||
|
||||
// 27. Progress Bar
|
||||
// ----------------
|
||||
|
||||
$progress-height: 0.625rem;
|
||||
$progress-background: $medium-gray;
|
||||
$progress-margin-bottom: $global-margin;
|
||||
$progress-meter-background: $primary-color;
|
||||
$progress-radius: $global-radius;
|
||||
|
||||
// 28. Responsive Embed
|
||||
// --------------------
|
||||
|
||||
$responsive-embed-margin-bottom: rem-calc(16);
|
||||
$responsive-embed-ratios: (default: 4 by 3,
|
||||
widescreen: 16 by 9);
|
||||
|
||||
// 29. Reveal
|
||||
// ----------
|
||||
|
||||
$reveal-background: $white;
|
||||
$reveal-width: 600px;
|
||||
$reveal-max-width: $global-width;
|
||||
$reveal-padding: $global-padding;
|
||||
$reveal-border: 1px solid $medium-gray;
|
||||
$reveal-radius: $global-radius;
|
||||
$reveal-zindex: 1005;
|
||||
$reveal-overlay-background: rgba($black, 0.45);
|
||||
|
||||
// 30. Slider
|
||||
// ----------
|
||||
|
||||
$slider-width-vertical: 0.3125rem;
|
||||
$slider-transition: all 0.2s ease-in-out;
|
||||
$slider-height: 0.3125rem;
|
||||
$slider-background: $light-gray;
|
||||
$slider-fill-background: $medium-gray;
|
||||
$slider-handle-height: 0.875rem;
|
||||
$slider-handle-width: 0.875rem;
|
||||
$slider-handle-background: $primary-color;
|
||||
$slider-opacity-disabled: 0.25;
|
||||
$slider-radius: $global-radius;
|
||||
|
||||
// 31. Switch
|
||||
// ----------
|
||||
|
||||
$switch-background: $light-gray;
|
||||
$switch-background-active: $primary-color;
|
||||
$switch-height: $space-two;
|
||||
$switch-height-tiny: $space-slab;
|
||||
$switch-height-small: $space-normal;
|
||||
$switch-height-large: $space-large;
|
||||
$switch-radius: $space-large;
|
||||
$switch-margin: $global-margin;
|
||||
$switch-paddle-background: $white;
|
||||
$switch-paddle-offset: $space-micro;
|
||||
$switch-paddle-radius: $space-large;
|
||||
$switch-paddle-transition: all 0.15s ease-out;
|
||||
|
||||
// 32. Table
|
||||
// ---------
|
||||
|
||||
$table-background: transparent;
|
||||
$table-color-scale: 5%;
|
||||
$table-border: 1px solid transparent;
|
||||
$table-padding: rem-calc(8 10 10);
|
||||
$table-hover-scale: 2%;
|
||||
$table-row-hover: darken($table-background, $table-hover-scale);
|
||||
$table-row-stripe-hover: darken($table-background,
|
||||
$table-color-scale + $table-hover-scale);
|
||||
$table-is-striped: false;
|
||||
$table-striped-background: smart-scale($table-background, $table-color-scale);
|
||||
$table-stripe: even;
|
||||
$table-head-background: smart-scale($table-background, $table-color-scale / 2);
|
||||
$table-head-row-hover: darken($table-head-background, $table-hover-scale);
|
||||
$table-foot-background: smart-scale($table-background, $table-color-scale);
|
||||
$table-foot-row-hover: darken($table-foot-background, $table-hover-scale);
|
||||
$table-head-font-color: $body-font-color;
|
||||
$table-foot-font-color: $body-font-color;
|
||||
$show-header-for-stacked: false;
|
||||
|
||||
// 33. Tabs
|
||||
// --------
|
||||
|
||||
$tab-margin: 0;
|
||||
|
||||
$tab-background: transparent;
|
||||
$tab-background-active: transparent;
|
||||
$tab-item-font-size: $font-size-small;
|
||||
$tab-item-background-hover: transparent;
|
||||
$tab-item-padding: $space-one $zero;
|
||||
$tab-color: $primary-color;
|
||||
$tab-active-color: $primary-color;
|
||||
$tab-expand-max: 6;
|
||||
$tab-content-background: transparent;
|
||||
$tab-content-border: transparent;
|
||||
$tab-content-color: foreground($tab-background, $primary-color);
|
||||
$tab-content-padding: 0.625rem;
|
||||
|
||||
// 34. Thumbnail
|
||||
// -------------
|
||||
|
||||
$thumbnail-border: solid 4px $white;
|
||||
$thumbnail-margin-bottom: $global-margin;
|
||||
$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2);
|
||||
$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5);
|
||||
$thumbnail-transition: box-shadow 200ms ease-out;
|
||||
$thumbnail-radius: $global-radius;
|
||||
|
||||
// 35. Title Bar
|
||||
// -------------
|
||||
|
||||
$titlebar-background: $black;
|
||||
$titlebar-color: $white;
|
||||
$titlebar-padding: 0.3125rem;
|
||||
$titlebar-text-font-weight: bold;
|
||||
$titlebar-icon-color: $white;
|
||||
$titlebar-icon-color-hover: $medium-gray;
|
||||
$titlebar-icon-spacing: 0.15625rem;
|
||||
|
||||
// 36. Tooltip
|
||||
// -----------
|
||||
|
||||
$has-tip-font-weight: $global-weight-bold;
|
||||
$has-tip-border-bottom: dotted 1px $dark-gray;
|
||||
$tooltip-background-color: $black;
|
||||
$tooltip-color: $white;
|
||||
$tooltip-padding: 0.46875rem;
|
||||
$tooltip-font-size: $font-size-mini;
|
||||
$tooltip-pip-width: 0.46875rem;
|
||||
$tooltip-pip-height: $tooltip-pip-width * 0.866;
|
||||
$tooltip-radius: $global-radius;
|
||||
|
||||
// 37. Top Bar
|
||||
// -----------
|
||||
|
||||
$topbar-padding: 0.3125;
|
||||
$topbar-background: $light-gray;
|
||||
$topbar-submenu-background: $topbar-background;
|
||||
$topbar-title-spacing: 0.3125 0.625rem 0.3125 0;
|
||||
$topbar-input-width: 200px;
|
||||
$topbar-unstack-breakpoint: medium;
|
||||
|
||||
|
||||
// Internal variable that contains the flex justifying options
|
||||
$-zf-flex-justify: -zf-flex-justify($global-text-direction);
|
||||
|
||||
$menu-items-padding: $space-one;
|
||||
$xy-grid: false;
|
||||
@@ -1,64 +1,22 @@
|
||||
.bg-light {
|
||||
@apply bg-slate-25 dark:bg-slate-800;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
@include flex-align(center, middle);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.bottom-space-fix {
|
||||
margin-bottom: auto;
|
||||
}
|
||||
|
||||
.full-height {
|
||||
@include full-height();
|
||||
}
|
||||
|
||||
// loader class
|
||||
.spinner {
|
||||
@include color-spinner();
|
||||
display: inline-block;
|
||||
height: $space-medium;
|
||||
padding: $zero $space-medium;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
width: $space-medium;
|
||||
@apply inline-block h-6 py-0 px-6 relative align-middle w-6;
|
||||
|
||||
&.message {
|
||||
@include normal-shadow;
|
||||
background: $color-white;
|
||||
border-radius: $space-large;
|
||||
left: 0;
|
||||
margin: $space-slab auto;
|
||||
padding: $space-normal;
|
||||
top: 0;
|
||||
@apply bg-white dark:bg-slate-800 rounded-full left-0 my-3 mx-auto p-4 top-0;
|
||||
|
||||
&::before {
|
||||
margin-left: -$space-slab;
|
||||
margin-top: -$space-slab;
|
||||
@apply -ml-3 -mt-3;
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: $space-normal;
|
||||
width: $space-normal;
|
||||
@apply h-4 w-4;
|
||||
|
||||
&::before {
|
||||
height: $space-normal;
|
||||
margin-top: -$space-small;
|
||||
width: $space-normal;
|
||||
@apply h-4 -mt-2 w-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.justify-space-between {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
// scss-lint:disable SpaceAfterPropertyColon
|
||||
// @import 'shared/assets/fonts/inter';
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family:
|
||||
'PlusJakarta',
|
||||
Inter,
|
||||
-apple-system,
|
||||
system-ui,
|
||||
BlinkMacSystemFont,
|
||||
'Segoe UI',
|
||||
Roboto,
|
||||
'Helvetica Neue',
|
||||
Arial,
|
||||
sans-serif !important;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
height: 100%;
|
||||
|
||||
@@ -131,37 +131,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.search-header--wrap {
|
||||
.search--input {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.layout-switch__container {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
// Basic filter dropdown
|
||||
.basic-filter {
|
||||
left: 0;
|
||||
right: unset;
|
||||
}
|
||||
|
||||
// Card label
|
||||
.label-container {
|
||||
.label {
|
||||
margin-left: var(--space-smaller);
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary sidebar toggle button
|
||||
.toggle-sidebar {
|
||||
margin-left: 0;
|
||||
margin-right: var(--space-minus-small);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
// Bulk actions
|
||||
.bulk-action__container {
|
||||
.triangle {
|
||||
@@ -202,22 +177,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Notification panel
|
||||
.notification-wrap {
|
||||
left: 0;
|
||||
right: var(--space-jumbo);
|
||||
|
||||
.action-button {
|
||||
margin-left: var(--space-small);
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.notification-content--wrap {
|
||||
margin-left: 0;
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
// Help center
|
||||
.article-container .row--article-block {
|
||||
td:last-child {
|
||||
@@ -324,10 +283,6 @@
|
||||
|
||||
// Other changes
|
||||
|
||||
.account-selector--wrap {
|
||||
direction: initial;
|
||||
}
|
||||
|
||||
.colorpicker--chrome {
|
||||
direction: initial;
|
||||
}
|
||||
@@ -347,9 +302,4 @@
|
||||
.contact--form .input-group {
|
||||
direction: initial;
|
||||
}
|
||||
|
||||
// scss-lint:disable QualifyingElement
|
||||
.dropdown-menu--header > span.title {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
.page-title {
|
||||
font-size: $font-size-big;
|
||||
}
|
||||
|
||||
.page-sub-title {
|
||||
font-size: $font-size-large;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.block-title {
|
||||
font-size: $font-size-medium;
|
||||
}
|
||||
|
||||
.sub-block-title {
|
||||
font-size: $font-size-default;
|
||||
}
|
||||
|
||||
.text-block-title {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: var(--s-300);
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-size-small;
|
||||
word-spacing: .12em;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
.margin-bottom-small {
|
||||
margin-bottom: var(--space-small);
|
||||
}
|
||||
|
||||
.margin-right-smaller {
|
||||
margin-right: var(--space-smaller);
|
||||
}
|
||||
|
||||
.margin-left-minus-slab {
|
||||
margin-left: var(--space-minus-slab);
|
||||
}
|
||||
|
||||
.margin-right-minus-slab {
|
||||
margin-right: var(--space-minus-slab);
|
||||
}
|
||||
|
||||
.fs-small {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.fs-default {
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
|
||||
.fw-medium {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.p-normal {
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
.overflow-scroll {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.overflow-hidden {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.border-right {
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
.border-left {
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-end {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.flex-align-center {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
@@ -15,63 +15,28 @@
|
||||
@import 'variables';
|
||||
|
||||
@import 'mixins';
|
||||
@import 'foundation-settings';
|
||||
@import 'helper-classes';
|
||||
@import 'formulate';
|
||||
@import 'date-picker';
|
||||
|
||||
@import 'foundation-sites/scss/foundation';
|
||||
|
||||
@include foundation-everything($flex: true);
|
||||
|
||||
@include foundation-prototype-text-utilities;
|
||||
@include foundation-prototype-text-transformation;
|
||||
@include foundation-prototype-text-decoration;
|
||||
@include foundation-prototype-font-styling;
|
||||
@include foundation-prototype-list-style-type;
|
||||
@include foundation-prototype-rounded;
|
||||
@include foundation-prototype-bordered;
|
||||
@include foundation-prototype-shadow;
|
||||
@include foundation-prototype-separator;
|
||||
@include foundation-prototype-overflow;
|
||||
@include foundation-prototype-display;
|
||||
@include foundation-prototype-position;
|
||||
@include foundation-prototype-border-box;
|
||||
@include foundation-prototype-border-none;
|
||||
@include foundation-prototype-sizing;
|
||||
@include foundation-prototype-spacing;
|
||||
|
||||
@import 'typography';
|
||||
@import 'layout';
|
||||
@import 'animations';
|
||||
@import 'foundation-custom';
|
||||
@import 'rtl';
|
||||
|
||||
@import 'widgets/base';
|
||||
@import 'widgets/buttons';
|
||||
@import 'widgets/conv-header';
|
||||
@import 'widgets/conversation-card';
|
||||
@import 'widgets/conversation-view';
|
||||
@import 'widgets/forms';
|
||||
@import 'widgets/login';
|
||||
@import 'widgets/modal';
|
||||
@import 'widgets/reply-box';
|
||||
@import 'widgets/report';
|
||||
@import 'widgets/search-box';
|
||||
@import 'widgets/sidemenu';
|
||||
@import 'widgets/snackbar';
|
||||
@import 'widgets/states';
|
||||
@import 'widgets/status-bar';
|
||||
@import 'widgets/tabs';
|
||||
@import 'widgets/woot-tables';
|
||||
|
||||
@import 'views/settings/inbox';
|
||||
@import 'views/settings/integrations';
|
||||
|
||||
@import 'plugins/multiselect';
|
||||
@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;
|
||||
}
|
||||
|
||||
.hide {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
@@ -1,46 +1,7 @@
|
||||
.dropdown-pane {
|
||||
@include elegant-card;
|
||||
@include border-light;
|
||||
box-sizing: content-box;
|
||||
padding: var(--space-small);
|
||||
width: fit-content;
|
||||
z-index: var(--z-index-very-high);
|
||||
@apply border rounded-lg hidden relative invisible shadow-lg border-slate-25 dark:border-slate-700 box-content p-2 w-fit z-[9999];
|
||||
|
||||
&.dropdown-pane--open {
|
||||
@apply bg-white dark:bg-slate-800;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&.dropdowm--bottom {
|
||||
&::before {
|
||||
@include arrow(top, var(--color-border-light), 14px);
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: -14px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@include arrow(top, $color-white, var(--space-slab));
|
||||
position: absolute;
|
||||
right: var(--space-small);
|
||||
top: -12px;
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdowm--top {
|
||||
&::before {
|
||||
@include arrow(bottom, var(--color-border-light), 14px);
|
||||
bottom: -14px;
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@include arrow(bottom, $color-white, var(--space-slab));
|
||||
bottom: -12px;
|
||||
position: absolute;
|
||||
right: var(--space-small);
|
||||
}
|
||||
@apply bg-white absolute dark:bg-slate-800 block visible;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +97,10 @@
|
||||
|
||||
.multiselect__tags {
|
||||
@apply bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-600 m-0 min-h-[2.875rem] pt-0;
|
||||
|
||||
input {
|
||||
@apply border-0 border-none;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect__tags-wrap {
|
||||
@@ -149,7 +153,6 @@
|
||||
}
|
||||
|
||||
.multiselect-wrap--small {
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input,
|
||||
.multiselect {
|
||||
@@ -180,7 +183,6 @@
|
||||
.multiselect--disabled .multiselect__select {
|
||||
@apply bg-transparent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.multiselect-wrap--medium {
|
||||
|
||||
@@ -13,20 +13,14 @@
|
||||
@import '~shared/assets/stylesheets/ionicons';
|
||||
|
||||
@import 'mixins';
|
||||
@import 'foundation-settings';
|
||||
@import 'helper-classes';
|
||||
@import 'foundation-sites/scss/foundation';
|
||||
|
||||
@include foundation-prototype-spacing;
|
||||
@include foundation-everything($flex: true);
|
||||
|
||||
@import 'typography';
|
||||
@import 'layout';
|
||||
@import 'animations';
|
||||
|
||||
@import 'foundation-custom';
|
||||
@import 'widgets/buttons';
|
||||
@import 'widgets/forms';
|
||||
@import 'widgets/base';
|
||||
|
||||
@import 'plugins/multiselect';
|
||||
|
||||
@@ -36,7 +30,6 @@
|
||||
@import 'tailwindcss/utilities';
|
||||
@import 'widget/assets/scss/utilities';
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
font-family: 'PlusJakarta', sans-serif;
|
||||
|
||||
@@ -1,112 +1 @@
|
||||
.settings {
|
||||
@apply overflow-auto;
|
||||
}
|
||||
|
||||
.wizard-box {
|
||||
.item {
|
||||
@apply cursor-pointer py-4 pr-4 pl-6 relative;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
@apply bg-slate-75 dark:bg-slate-600 content-[''] h-full absolute top-5 w-0.5;
|
||||
}
|
||||
|
||||
&::before {
|
||||
@apply h-4 top-0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
&::before {
|
||||
@apply h-0;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&::after {
|
||||
@apply h-0;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
h3 {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
}
|
||||
|
||||
&.over {
|
||||
&::after {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
|
||||
& + .item {
|
||||
&::before {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-slate-800 dark:text-slate-100 text-base pl-6;
|
||||
}
|
||||
|
||||
.completed {
|
||||
@apply text-green-500 dark:text-green-500 ml-1;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-slate-600 dark:text-slate-300 text-sm m-0 pl-6;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-slate-75 dark:bg-slate-600 rounded-2xl font-medium w-4 left-4 leading-4 z-[999] absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
|
||||
i {
|
||||
@apply text-xxs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-body {
|
||||
@apply border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6;
|
||||
|
||||
&.height-auto {
|
||||
@apply h-auto;
|
||||
}
|
||||
}
|
||||
|
||||
.settings--content {
|
||||
@apply my-2 mx-8;
|
||||
|
||||
.title {
|
||||
@apply font-medium;
|
||||
}
|
||||
|
||||
.code {
|
||||
@apply bg-slate-50 dark:bg-slate-800 overflow-auto p-2.5 whitespace-nowrap;
|
||||
|
||||
code {
|
||||
@apply bg-transparent border-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-init {
|
||||
@apply pt-[30%] text-center;
|
||||
|
||||
p {
|
||||
@apply p-6;
|
||||
}
|
||||
|
||||
> a > img {
|
||||
@apply w-60;
|
||||
}
|
||||
}
|
||||
// to be removed
|
||||
|
||||
146
app/javascript/dashboard/assets/scss/widgets/_base.scss
Normal file
146
app/javascript/dashboard/assets/scss/widgets/_base.scss
Normal file
@@ -0,0 +1,146 @@
|
||||
// scss-lint:disable QualifyingElement
|
||||
|
||||
// Base typography
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
@apply font-medium text-slate-800 dark:text-slate-50;
|
||||
}
|
||||
|
||||
p {
|
||||
text-rendering: optimizeLegibility;
|
||||
word-spacing: 0.12em;
|
||||
|
||||
@apply mb-2 leading-[1.65] text-sm;
|
||||
|
||||
a {
|
||||
@apply text-woot-500 dark:text-woot-500 cursor-pointer;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply clear-both max-w-full h-0 my-5 mx-0 border-slate-300 dark:border-slate-600;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol,
|
||||
dl {
|
||||
@apply mb-2 list-disc list-outside leading-[1.65];
|
||||
}
|
||||
|
||||
// Form elements
|
||||
label {
|
||||
@apply text-slate-800 dark:text-slate-200 block m-0 leading-7 text-sm font-medium;
|
||||
|
||||
&.error {
|
||||
input {
|
||||
@apply mb-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.input-wrap,
|
||||
.help-text {
|
||||
@apply text-slate-800 dark:text-slate-100 text-sm font-medium;
|
||||
|
||||
.help-text {
|
||||
@apply font-normal text-slate-600 dark:text-slate-400;
|
||||
}
|
||||
}
|
||||
|
||||
// Focus outline removal
|
||||
.button,
|
||||
textarea,
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
// Inputs
|
||||
input[type='text'],
|
||||
input[type='number'],
|
||||
input[type='password'],
|
||||
input[type='date'],
|
||||
input[type='email'],
|
||||
input[type='url'] {
|
||||
@apply block box-border w-full transition-colors focus:border-woot-500 dark:focus:border-woot-600 duration-[0.25s] ease-[ease-in-out] h-10 appearance-none mx-0 mt-0 mb-4 p-2 rounded-md text-base font-normal bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border border-solid border-slate-200 dark:border-slate-600;
|
||||
|
||||
&[disabled] {
|
||||
@apply bg-slate-200 dark:bg-slate-700 text-slate-400 dark:text-slate-400 border-slate-200 dark:border-slate-600 cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
@apply bg-white dark:bg-slate-800 leading-[1.15] mb-4;
|
||||
}
|
||||
|
||||
// Select
|
||||
select {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='32' height='24' viewBox='0 0 32 24'><polygon points='0,0 32,0 16,24' style='fill: rgb%28110, 111, 115%29'></polygon></svg>");
|
||||
background-position: right -1rem center;
|
||||
background-size: 9px 6px;
|
||||
@apply h-10 mx-0 mt-0 mb-4 bg-origin-content focus-visible:outline-none bg-no-repeat py-2 pr-6 pl-2 rounded-md w-full text-base font-normal appearance-none transition-colors focus:border-woot-500 dark:focus:border-woot-600 duration-[0.25s] ease-[ease-in-out] bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 border border-solid border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
// Textarea
|
||||
textarea {
|
||||
@apply block box-border w-full transition-colors focus:border-woot-500 dark:focus:border-woot-600 duration-[0.25s] ease-[ease-in-out] h-16 appearance-none mx-0 mt-0 mb-4 p-2 rounded-md text-base font-normal bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border border-solid border-slate-200 dark:border-slate-600;
|
||||
|
||||
&[disabled] {
|
||||
@apply bg-slate-200 dark:bg-slate-700 text-slate-400 dark:text-slate-400 border-slate-200 dark:border-slate-600 cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
// Error handling
|
||||
.has-multi-select-error {
|
||||
div.multiselect {
|
||||
@apply mb-1;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
input,
|
||||
input:not([type]),
|
||||
textarea,
|
||||
select,
|
||||
.multiselect > .multiselect__tags,
|
||||
.multiselect:not(.no-margin) {
|
||||
@apply border border-solid border-red-400 dark:border-red-400 mb-1;
|
||||
}
|
||||
|
||||
.message {
|
||||
@apply text-red-400 dark:text-red-400 block text-sm mb-2.5 w-full;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group.small {
|
||||
input {
|
||||
@apply text-sm h-8;
|
||||
}
|
||||
|
||||
.error {
|
||||
@apply border-red-400 dark:border-red-400;
|
||||
}
|
||||
}
|
||||
|
||||
// Code styling
|
||||
code {
|
||||
font-family: 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas',
|
||||
'"Liberation Mono"', '"Courier New"', 'monospace';
|
||||
@apply text-xs border-0;
|
||||
|
||||
&.hljs {
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-50 rounded-lg p-5;
|
||||
|
||||
.hljs-number,
|
||||
.hljs-string {
|
||||
@apply text-red-800 dark:text-red-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,40 @@
|
||||
// scss-lint:disable SpaceAfterPropertyColon
|
||||
// scss-lint:disable MergeableSelector
|
||||
button {
|
||||
font-family: inherit;
|
||||
transition:
|
||||
background-color 0.25s ease-out,
|
||||
color 0.25s ease-out;
|
||||
@apply inline-block items-center mb-0 text-center align-middle cursor-pointer text-sm mt-0 mx-0 py-1 px-2.5 border border-solid border-transparent dark:border-transparent rounded-[0.3125rem];
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
@apply opacity-40 cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.button-group {
|
||||
@apply mb-0 flex flex-nowrap items-stretch;
|
||||
|
||||
.button {
|
||||
flex: 0 0 auto;
|
||||
@apply m-0 text-sm rounded-none first:rounded-tl-[0.3125rem] first:rounded-bl-[0.3125rem] last:rounded-tr-[0.3125rem] last:rounded-br-[0.3125rem] rtl:space-x-reverse;
|
||||
}
|
||||
|
||||
.button--only-icon {
|
||||
@apply w-10 justify-center pl-0 pr-0;
|
||||
}
|
||||
}
|
||||
|
||||
.back-button {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply items-center inline-flex h-10 mb-0 gap-2;
|
||||
@apply items-center bg-woot-500 dark:bg-woot-500 px-2.5 text-white dark:text-white inline-flex h-10 mb-0 gap-2 font-medium;
|
||||
|
||||
.button__content {
|
||||
@apply w-full;
|
||||
@apply w-full whitespace-nowrap overflow-hidden text-ellipsis;
|
||||
|
||||
img,
|
||||
svg {
|
||||
@@ -10,12 +42,61 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-woot-600 dark:bg-woot-600;
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
@apply opacity-40 cursor-not-allowed;
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply bg-[#44ce4b] dark:bg-[#44ce4b] text-white dark:text-white;
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
@apply bg-slate-700 dark:bg-slate-600 text-white dark:text-white;
|
||||
}
|
||||
|
||||
&.primary {
|
||||
@apply bg-woot-500 dark:bg-woot-500 text-white dark:text-white;
|
||||
}
|
||||
|
||||
&.clear {
|
||||
@apply text-woot-500 dark:text-woot-500 bg-transparent dark:bg-transparent;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@apply bg-red-500 dark:bg-red-500 text-white dark:text-white;
|
||||
|
||||
&.clear {
|
||||
@apply bg-transparent dark:bg-transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply bg-[#ffc532] dark:bg-[#ffc532] text-white dark:text-white;
|
||||
|
||||
&.clear {
|
||||
@apply bg-transparent dark:bg-transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.tiny {
|
||||
@apply h-6 text-[10px];
|
||||
}
|
||||
|
||||
&.small {
|
||||
@apply h-8 text-xs;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
@apply px-2 py-0;
|
||||
}
|
||||
|
||||
// @TODDO - Remove after moving all buttons to woot-button
|
||||
.icon + .button__content {
|
||||
.icon+.button__content {
|
||||
@apply w-auto;
|
||||
}
|
||||
|
||||
@@ -34,7 +115,7 @@
|
||||
}
|
||||
|
||||
&.hollow {
|
||||
@apply border border-woot-500 dark:border-woot-500 text-woot-500 dark:text-woot-500 hover:bg-woot-50 dark:hover:bg-woot-900;
|
||||
@apply border border-woot-500 bg-transparent dark:bg-transparent dark:border-woot-500 text-woot-500 dark:text-woot-500 hover:bg-woot-50 dark:hover:bg-woot-900;
|
||||
|
||||
&.secondary {
|
||||
@apply text-slate-700 border-slate-200 dark:border-slate-600 dark:text-slate-100 hover:bg-slate-50 dark:hover:bg-slate-700;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
// File to be removed
|
||||
@@ -1,16 +0,0 @@
|
||||
@keyframes left-shift-animation {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateX(1px);
|
||||
}
|
||||
}
|
||||
|
||||
.conversation {
|
||||
&.active {
|
||||
animation: left-shift-animation 0.25s $swift-ease-out-function;
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@
|
||||
@apply rounded-r-lg rounded-l mr-auto break-words;
|
||||
|
||||
&:not(.is-unsupported) {
|
||||
@apply border border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-700 text-black-900 dark:text-slate-50
|
||||
@apply border border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-700 text-black-900 dark:text-slate-50;
|
||||
}
|
||||
|
||||
&.is-image {
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
|
||||
.file {
|
||||
.text-block-title {
|
||||
.attachment-name {
|
||||
@apply text-slate-700 dark:text-woot-300;
|
||||
}
|
||||
|
||||
@@ -222,20 +222,6 @@
|
||||
@apply flex relative flex-col;
|
||||
}
|
||||
|
||||
.typing-indicator-wrap {
|
||||
@apply items-center flex h-0 absolute w-full -top-8;
|
||||
|
||||
.typing-indicator {
|
||||
@include elegant-card;
|
||||
@include round-corner;
|
||||
@apply py-2 pr-4 pl-5 bg-white dark:bg-slate-700 text-slate-800 dark:text-slate-100 text-xs font-semibold my-2.5 mx-auto;
|
||||
|
||||
.gif {
|
||||
@apply ml-2 w-6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.left .bubble .text-content {
|
||||
h1,
|
||||
h2,
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
// scss-lint:disable QualifyingElement
|
||||
|
||||
label {
|
||||
@apply text-slate-800 dark:text-slate-200;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
|
||||
&[disabled] {
|
||||
@apply bg-slate-200 dark:bg-slate-700 text-slate-400 dark:text-slate-400 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
@apply bg-white dark:bg-slate-800;
|
||||
}
|
||||
|
||||
select {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
.error {
|
||||
input[type='color'],
|
||||
input[type='date'],
|
||||
input[type='datetime'],
|
||||
input[type='datetime-local'],
|
||||
input[type='email'],
|
||||
input[type='month'],
|
||||
input[type='number'],
|
||||
input[type='password'],
|
||||
input[type='search'],
|
||||
input[type='tel'],
|
||||
input[type='text'],
|
||||
input[type='time'],
|
||||
input[type='url'],
|
||||
input[type='week'],
|
||||
input:not([type]),
|
||||
textarea,
|
||||
select,
|
||||
.multiselect > .multiselect__tags {
|
||||
@apply border border-solid border-red-400 dark:border-red-400;
|
||||
}
|
||||
|
||||
.message {
|
||||
@apply text-red-400 dark:text-red-400 block text-sm mb-2.5 w-full;
|
||||
}
|
||||
}
|
||||
|
||||
.button,
|
||||
textarea,
|
||||
input {
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.input-wrap {
|
||||
@apply text-slate-800 dark:text-slate-100 text-sm font-medium;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
@apply font-normal text-slate-600 dark:text-slate-400;
|
||||
}
|
||||
|
||||
.input-group.small {
|
||||
input {
|
||||
@apply text-sm h-8;
|
||||
}
|
||||
|
||||
.error {
|
||||
@apply border-red-400 dark:border-red-400;
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
.auth-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// Outside login wrapper
|
||||
.login {
|
||||
@include full-height;
|
||||
overflow-y: auto;
|
||||
padding-top: $space-larger * 1.2;
|
||||
|
||||
.login__hero {
|
||||
margin-bottom: $space-larger;
|
||||
|
||||
.hero__logo {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.hero__title {
|
||||
font-weight: $font-weight-light;
|
||||
margin-top: $space-larger;
|
||||
}
|
||||
|
||||
.hero__sub {
|
||||
color: $medium-gray;
|
||||
font-size: $font-size-medium;
|
||||
}
|
||||
}
|
||||
|
||||
// Login box
|
||||
.login-box {
|
||||
@include background-white;
|
||||
@include border-normal;
|
||||
@include elegant-card;
|
||||
|
||||
border-radius: $space-smaller;
|
||||
padding: $space-large;
|
||||
|
||||
label {
|
||||
color: $color-gray;
|
||||
font-size: $font-size-default;
|
||||
|
||||
input {
|
||||
font-size: $font-size-default;
|
||||
height: $space-larger;
|
||||
padding: $space-slab;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
height: $space-larger;
|
||||
}
|
||||
}
|
||||
|
||||
.sigin__footer {
|
||||
font-size: $font-size-default;
|
||||
padding: $space-medium;
|
||||
|
||||
> a {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
.modal-mask {
|
||||
// @include flex;
|
||||
// @include flex-align(center, middle);
|
||||
@apply flex items-center justify-center bg-modal-backdrop-light dark:bg-modal-backdrop-dark z-[9990] h-full left-0 fixed top-0 w-full;
|
||||
}
|
||||
|
||||
.page-top-bar {
|
||||
@apply px-8 pt-9 pb-0;
|
||||
|
||||
img {
|
||||
@apply max-h-[3.75rem];
|
||||
}
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@apply shadow-md rounded-sm max-h-full overflow-auto relative w-[37.5rem];
|
||||
|
||||
&.medium {
|
||||
@apply max-w-[80%] w-[56.25rem];
|
||||
}
|
||||
|
||||
.content-box {
|
||||
@apply h-auto p-0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-slate-800 dark:text-slate-100 text-lg font-semibold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-sm m-0 p-0 text-slate-600 mt-2 text-sm dark:text-slate-300;
|
||||
}
|
||||
|
||||
.content {
|
||||
@apply p-8;
|
||||
}
|
||||
|
||||
form,
|
||||
.modal-content {
|
||||
@apply pt-4 pb-8 px-8 self-center;
|
||||
|
||||
a {
|
||||
@apply p-4;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
// @include flex;
|
||||
// @include flex-align($x: flex-end, $y: middle);
|
||||
@apply flex justify-end items-center py-2 px-0 gap-2;
|
||||
|
||||
&.justify-content-end {
|
||||
@apply justify-end;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-item {
|
||||
@apply p-8;
|
||||
|
||||
button {
|
||||
@apply m-0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-enter,
|
||||
.modal-leave {
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
.modal-enter .modal-container,
|
||||
.modal-leave .modal-container {
|
||||
transform: scale(1.1);
|
||||
// @apply transform scale-110;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
.reply-box {
|
||||
transition: box-shadow 0.35s $swift-ease-out-function,
|
||||
height 2s $swift-ease-out-function;
|
||||
|
||||
&.is-focused {
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.reply-box__top {
|
||||
.icon {
|
||||
color: $medium-gray;
|
||||
cursor: pointer;
|
||||
font-size: $font-size-medium;
|
||||
margin-right: $space-small;
|
||||
|
||||
&.active {
|
||||
color: $color-woot;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment {
|
||||
cursor: pointer;
|
||||
margin-right: $space-one;
|
||||
padding: 0 $space-small;
|
||||
}
|
||||
|
||||
.video-js {
|
||||
background: transparent;
|
||||
// Override min-height : 50px in foundation
|
||||
//
|
||||
max-height: $space-mega * 2.4;
|
||||
min-height: 3rem;
|
||||
padding: var(--space-normal) 0 0;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
> textarea {
|
||||
@include ghost-input();
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
max-height: $space-mega * 2.4;
|
||||
// Override min-height : 50px in foundation
|
||||
min-height: 3rem;
|
||||
padding: var(--space-normal) 0 0;
|
||||
resize: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-private {
|
||||
@apply bg-yellow-100 dark:bg-yellow-800;
|
||||
|
||||
.reply-box__top {
|
||||
@apply bg-yellow-100 dark:bg-yellow-800;
|
||||
|
||||
> input {
|
||||
@apply bg-yellow-100 dark:bg-yellow-800;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
.report-card {
|
||||
@include custom-border-top(3px, transparent);
|
||||
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: var(--space-normal);
|
||||
|
||||
&.active {
|
||||
@include custom-border-top(3px, var(--color-woot));
|
||||
@include background-white;
|
||||
.heading,
|
||||
.metric {
|
||||
color: var(--color-woot);
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
align-items: center;
|
||||
color: var(--color-heading);
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
color: var(--b-400);
|
||||
margin-left: var(--space-micro);
|
||||
}
|
||||
|
||||
.metric-wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.metric {
|
||||
font-size: var(--font-size-big);
|
||||
font-weight: var(--font-weight-feather);
|
||||
margin-top: var(--space-smaller);
|
||||
}
|
||||
|
||||
.metric-trend {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.metric-up {
|
||||
color: $success-color;
|
||||
}
|
||||
|
||||
.metric-down {
|
||||
color: $alert-color;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
.reports-option__rounded--item {
|
||||
border-radius: 100%;
|
||||
height: var(--space-two);
|
||||
width: var(--space-two);
|
||||
}
|
||||
|
||||
.reports-option__item {
|
||||
flex-shrink: 0;
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
|
||||
.reports-option__label--swatch {
|
||||
border: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.reports-option__wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.reports-option__title {
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
|
||||
|
||||
.switch {
|
||||
margin-bottom: var(--space-zero);
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
.search {
|
||||
@include flex;
|
||||
@include flex-align($x: left, $y: middle);
|
||||
@include flex-shrink;
|
||||
|
||||
padding: $space-one $space-normal;
|
||||
transition: all 0.3s var(--ease-in-out-quad);
|
||||
|
||||
> .icon {
|
||||
color: $medium-gray;
|
||||
font-size: $font-size-medium;
|
||||
}
|
||||
|
||||
> input {
|
||||
@include ghost-input();
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
.side-menu {
|
||||
i {
|
||||
margin-right: var(--space-smaller);
|
||||
min-width: var(--space-two);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
z-index: 1024 - 1;
|
||||
|
||||
//logo
|
||||
.logo {
|
||||
img {
|
||||
max-height: 108px;
|
||||
padding: $woot-logo-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.nested {
|
||||
a {
|
||||
font-size: var(--font-size-small);
|
||||
margin-bottom: var(--space-micro);
|
||||
margin-top: var(--space-micro);
|
||||
|
||||
.inbox-icon {
|
||||
display: inline-block;
|
||||
margin-right: var(--space-micro);
|
||||
min-width: var(--space-normal);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bottom-nav
|
||||
.bottom-nav {
|
||||
@include flex;
|
||||
@include space-between-column;
|
||||
@include border-normal-top;
|
||||
flex-direction: column;
|
||||
padding: var(--space-one) var(--space-normal) var(--space-one)
|
||||
var(--space-one);
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-background-light);
|
||||
}
|
||||
|
||||
.dropdown-pane {
|
||||
bottom: 3.75rem;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.active {
|
||||
border-bottom: 2px solid $medium-gray;
|
||||
}
|
||||
}
|
||||
|
||||
.hamburger--menu {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin-right: var(--space-normal);
|
||||
}
|
||||
|
||||
.header--icon {
|
||||
display: block;
|
||||
margin: 0 var(--space-small) 0 var(--space-smaller);
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-title {
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
.ui-snackbar-container {
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
max-width: 25rem;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
top: $space-normal;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.ui-snackbar {
|
||||
@include shadow;
|
||||
background-color: $woot-snackbar-bg;
|
||||
border-radius: $space-smaller;
|
||||
display: inline-flex;
|
||||
margin-bottom: $space-small;
|
||||
max-width: 25rem;
|
||||
min-height: 1.875rem;
|
||||
min-width: 15rem;
|
||||
padding: $space-slab $space-medium;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ui-snackbar-text {
|
||||
color: $color-white;
|
||||
font-size: $font-size-small;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.ui-snackbar-action {
|
||||
margin-left: auto;
|
||||
padding-left: 1.875rem;
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: 0;
|
||||
color: $woot-snackbar-button;
|
||||
font-size: $font-size-small;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
// To be removed
|
||||
@@ -1,46 +0,0 @@
|
||||
.status-bar {
|
||||
@include flex;
|
||||
@include flex-align($x: center, $y: middle);
|
||||
background: lighten($warning-color, 36%);
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: $space-normal $space-smaller;
|
||||
|
||||
.message {
|
||||
font-weight: $font-weight-medium;
|
||||
margin-bottom: $zero;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: $space-smaller $zero $zero;
|
||||
padding: $space-small $space-normal;
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background: lighten($alert-color, 30%);
|
||||
|
||||
.button {
|
||||
// Default and disabled states
|
||||
&,
|
||||
&.disabled,
|
||||
&[disabled],
|
||||
&.disabled:hover,
|
||||
&[disabled]:hover,
|
||||
&.disabled:focus,
|
||||
&[disabled]:focus {
|
||||
background-color: $alert-color;
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: darken($alert-color, 7%);
|
||||
color: $color-white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: lighten($warning-color, 36%);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.tabs {
|
||||
@apply border-r-0 border-l-0 border-t-0 flex min-w-[6.25rem] py-0 px-4;
|
||||
@apply border-r-0 border-l-0 border-t-0 flex min-w-[6.25rem] py-0 px-4 list-none mb-0;
|
||||
}
|
||||
|
||||
.tabs--with-scroll {
|
||||
@@ -31,7 +31,7 @@
|
||||
}
|
||||
|
||||
.tabs-title {
|
||||
@apply flex-shrink-0 my-0 mx-2 ;
|
||||
@apply flex-shrink-0 my-0 mx-2;
|
||||
|
||||
.badge {
|
||||
@apply bg-slate-50 dark:bg-slate-800 rounded-md text-slate-600 dark:text-slate-100 h-5 flex items-center justify-center text-xxs font-semibold my-0 mx-1 px-1 py-0;
|
||||
@@ -53,7 +53,7 @@
|
||||
}
|
||||
|
||||
a {
|
||||
@apply flex items-center flex-row border-b border-transparent text-slate-500 dark:text-slate-200 text-sm top-[1px] relative;
|
||||
@apply flex items-center flex-row border-b py-2.5 select-none cursor-pointer border-transparent text-slate-500 dark:text-slate-200 text-sm top-[1px] relative;
|
||||
transition: border-color 0.15s $swift-ease-out-function;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
table {
|
||||
@apply border-spacing-0 text-sm;
|
||||
@apply border-spacing-0 text-sm w-full;
|
||||
|
||||
thead {
|
||||
th {
|
||||
@apply font-semibold tracking-[1px] text-left uppercase text-slate-900 dark:text-slate-200;
|
||||
@apply font-semibold tracking-[1px] text-left px-2.5 uppercase text-slate-900 dark:text-slate-200;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="-mt-px text-sm">
|
||||
<button
|
||||
class="flex items-center select-none w-full bg-slate-50 dark:bg-slate-800 border border-l-0 border-r-0 border-solid m-0 border-slate-100 dark:border-slate-700/50 cursor-grab justify-between py-2 px-4 drag-handle"
|
||||
class="flex items-center select-none w-full rounded-none bg-slate-50 dark:bg-slate-800 border border-l-0 border-r-0 border-solid m-0 border-slate-100 dark:border-slate-700/50 cursor-grab justify-between py-2 px-4 drag-handle"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<div class="flex justify-between mb-0.5">
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<button
|
||||
class="sm:w-[50%] md:w-[34%] lg:w-[25%] channel"
|
||||
class="sm:w-[50%] md:w-1/3 lg:w-1/4 bg-white dark:bg-slate-900 cursor-pointer flex flex-col transition-all duration-200 ease-in -m-px py-4 px-0 items-center border border-solid border-slate-25 dark:border-slate-800 hover:border-woot-500 dark:hover:border-woot-500 hover:shadow-md hover:z-50 disabled:opacity-60"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<img :src="src" :alt="title" />
|
||||
<h3 class="channel__title">
|
||||
<img :src="src" :alt="title" class="w-[50%] my-4 mx-auto" />
|
||||
<h3
|
||||
class="text-slate-800 dark:text-slate-100 text-base text-center capitalize"
|
||||
>
|
||||
{{ title }}
|
||||
</h3>
|
||||
</button>
|
||||
@@ -31,32 +33,8 @@ export default {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
&.channel:hover {
|
||||
&:hover {
|
||||
@apply border-transparent shadow-none cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.channel {
|
||||
@apply bg-white dark:bg-slate-900 cursor-pointer flex flex-col transition-all duration-200 ease-in -m-px py-4 px-0 items-center border border-solid border-slate-25 dark:border-slate-800;
|
||||
|
||||
&:hover {
|
||||
@apply border-woot-500 dark:border-woot-500 shadow-md z-50;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
@apply opacity-60;
|
||||
}
|
||||
|
||||
img {
|
||||
@apply w-[50%] my-4 mx-auto;
|
||||
}
|
||||
|
||||
.channel__title {
|
||||
@apply text-slate-800 dark:text-slate-100 text-base text-center capitalize;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-slate-600 dark:text-slate-300 w-full text-sm;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
>
|
||||
<div class="flex max-w-[85%] justify-center items-center">
|
||||
<h1
|
||||
class="text-xl break-words overflow-hidden whitespace-nowrap text-ellipsis text-black-900 dark:text-slate-100 mb-0"
|
||||
class="text-xl break-words overflow-hidden whitespace-nowrap font-medium text-ellipsis text-black-900 dark:text-slate-100 mb-0"
|
||||
:title="pageTitle"
|
||||
>
|
||||
{{ pageTitle }}
|
||||
@@ -143,7 +143,10 @@
|
||||
<div v-if="chatListLoading" class="text-center">
|
||||
<span class="spinner mt-4 mb-4" />
|
||||
</div>
|
||||
<p v-if="showEndOfListMessage" class="text-center text-muted p-4">
|
||||
<p
|
||||
v-if="showEndOfListMessage"
|
||||
class="text-center text-slate-400 dark:text-slate-300 p-4"
|
||||
>
|
||||
{{ $t('CHAT_LIST.EOF') }}
|
||||
</p>
|
||||
<intersection-observer
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="py-3 px-4">
|
||||
<div class="flex items-center mb-1">
|
||||
<h4 class="text-block-title flex items-center m-0 w-full error">
|
||||
<h4 class="text-sm flex items-center m-0 w-full error">
|
||||
<div v-if="isAttributeTypeCheckbox" class="checkbox-wrap">
|
||||
<input
|
||||
v-model="editedValue"
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<span
|
||||
class="attribute-name"
|
||||
class="attribute-name w-full text-slate-800 dark:text-slate-100 font-medium text-sm mb-0"
|
||||
:class="{ error: $v.editedValue.$error }"
|
||||
>
|
||||
{{ label }}
|
||||
@@ -32,19 +32,24 @@
|
||||
</div>
|
||||
<div v-if="notAttributeTypeCheckboxAndList">
|
||||
<div v-show="isEditing">
|
||||
<div class="input-group small">
|
||||
<div class="mb-2 w-full flex items-center">
|
||||
<input
|
||||
ref="inputfield"
|
||||
v-model="editedValue"
|
||||
:type="inputType"
|
||||
class="input-group-field"
|
||||
class="!h-8 ltr:rounded-r-none rtl:rounded-l-none !mb-0 !text-sm"
|
||||
autofocus="true"
|
||||
:class="{ error: $v.editedValue.$error }"
|
||||
@blur="$v.editedValue.$touch"
|
||||
@keyup.enter="onUpdate"
|
||||
/>
|
||||
<div class="input-group-button">
|
||||
<woot-button size="small" icon="checkmark" @click="onUpdate" />
|
||||
<div>
|
||||
<woot-button
|
||||
size="small"
|
||||
icon="checkmark"
|
||||
class="rounded-l-none rtl:rounded-r-none"
|
||||
@click="onUpdate"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
@@ -306,7 +311,6 @@ export default {
|
||||
@apply my-0 mr-2 ml-0;
|
||||
}
|
||||
.attribute-name {
|
||||
@apply w-full text-slate-800 dark:text-slate-100;
|
||||
&.error {
|
||||
@apply text-red-400 dark:text-red-500;
|
||||
}
|
||||
|
||||
@@ -62,9 +62,9 @@ export default {
|
||||
computed: {
|
||||
modalContainerClassName() {
|
||||
let className =
|
||||
'modal-container bg-white dark:bg-slate-800 skip-context-menu';
|
||||
'modal-container rtl:text-right shadow-md rounded-sm max-h-full overflow-auto relative w-[37.5rem] bg-white dark:bg-slate-800 skip-context-menu';
|
||||
if (this.fullWidth) {
|
||||
return `${className} modal-container--full-width`;
|
||||
return `${className} items-center rounded-none flex h-full justify-center w-full`;
|
||||
}
|
||||
|
||||
return `${className} ${this.size}`;
|
||||
@@ -109,26 +109,43 @@ export default {
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.modal-container--full-width {
|
||||
align-items: center;
|
||||
border-radius: 0;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.modal-mask.right-aligned {
|
||||
justify-content: flex-end;
|
||||
|
||||
<style lang="scss">
|
||||
.modal-mask {
|
||||
@apply flex items-center justify-center bg-modal-backdrop-light dark:bg-modal-backdrop-dark z-[9990] h-full left-0 fixed top-0 w-full;
|
||||
.modal-container {
|
||||
border-radius: 0;
|
||||
height: 100%;
|
||||
width: 30rem;
|
||||
&.medium {
|
||||
@apply max-w-[80%] w-[56.25rem];
|
||||
}
|
||||
// .content-box {
|
||||
// @apply h-auto p-0;
|
||||
// }
|
||||
.content {
|
||||
@apply p-8;
|
||||
}
|
||||
form,
|
||||
.modal-content {
|
||||
@apply pt-4 pb-8 px-8 self-center;
|
||||
a {
|
||||
@apply p-4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.modal-big {
|
||||
width: 60%;
|
||||
@apply w-full;
|
||||
}
|
||||
.modal-mask.right-aligned {
|
||||
@apply justify-end;
|
||||
.modal-container {
|
||||
@apply rounded-none h-full w-[30rem];
|
||||
}
|
||||
}
|
||||
.modal-enter,
|
||||
.modal-leave {
|
||||
@apply opacity-0;
|
||||
}
|
||||
.modal-enter .modal-container,
|
||||
.modal-leave .modal-container {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<img v-if="headerImage" :src="headerImage" alt="No image" />
|
||||
<h2
|
||||
ref="modalHeaderTitle"
|
||||
class="text-slate-800 text-lg dark:text-slate-100"
|
||||
class="text-slate-800 text-lg font-semibold dark:text-slate-50"
|
||||
>
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<template>
|
||||
<div
|
||||
class="ml-0 mr-0 flex pt-0 pr-4 pb-4 pl-0"
|
||||
class="ml-0 mr-0 flex py-8 w-full xl:w-3/4 flex-col xl:flex-row"
|
||||
:class="{
|
||||
'pt-4 border-b border-solid border-slate-50 dark:border-slate-700/30':
|
||||
'border-b border-solid border-slate-50 dark:border-slate-700/30':
|
||||
showBorder,
|
||||
}"
|
||||
>
|
||||
<div class="w-[30%] min-w-0 max-w-[30%] pr-12">
|
||||
<div class="w-full xl:w-1/4 min-w-0 xl:max-w-[30%] pr-12">
|
||||
<p
|
||||
v-if="title"
|
||||
class="text-base text-woot-500 dark:text-woot-500 mb-0 font-medium"
|
||||
>
|
||||
{{ title }}
|
||||
</p>
|
||||
<p class="text-sm mb-2">
|
||||
<p
|
||||
class="text-sm mb-2 text-slate-700 dark:text-slate-300 leading-5 tracking-normal mt-2"
|
||||
>
|
||||
<slot v-if="subTitle" name="subTitle">
|
||||
{{ subTitle }}
|
||||
</slot>
|
||||
@@ -23,7 +25,7 @@
|
||||
{{ note }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-[50%] min-w-0 max-w-[50%]">
|
||||
<div class="w-full xl:w-1/2 min-w-0 xl:max-w-[50%]">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="ui-snackbar">
|
||||
<div class="ui-snackbar-text">
|
||||
<div
|
||||
class="shadow-sm bg-slate-800 dark:bg-slate-700 rounded-[4px] items-center gap-3 inline-flex mb-2 max-w-[25rem] min-h-[1.875rem] min-w-[15rem] px-6 py-3 text-left"
|
||||
>
|
||||
<div class="text-white dark:text-white text-sm font-medium">
|
||||
{{ message }}
|
||||
</div>
|
||||
<div v-if="action" class="ui-snackbar-action">
|
||||
<router-link v-if="action.type == 'link'" :to="action.to">
|
||||
<div v-if="action">
|
||||
<router-link
|
||||
v-if="action.type == 'link'"
|
||||
:to="action.to"
|
||||
class="text-woot-500 dark:text-woot-500 cursor-pointer font-medium hover:text-woot-600 dark:hover:text-woot-600 select-none"
|
||||
>
|
||||
{{ action.message }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<transition-group name="toast-fade" tag="div" class="ui-snackbar-container">
|
||||
<transition-group
|
||||
name="toast-fade"
|
||||
tag="div"
|
||||
class="left-0 my-0 mx-auto max-w-[25rem] overflow-hidden absolute right-0 text-center top-4 z-[9999]"
|
||||
>
|
||||
<woot-snackbar
|
||||
v-for="snackMessage in snackMessages"
|
||||
:key="snackMessage.key"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
v-on-clickaway="closeDropdown"
|
||||
class="dropdown-pane dropdown-pane--open"
|
||||
>
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-menu class="mb-0">
|
||||
<woot-dropdown-item v-if="!isPending">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
|
||||
@@ -18,7 +18,6 @@ import Label from './ui/Label';
|
||||
import LoadingState from './widgets/LoadingState';
|
||||
import Modal from './Modal';
|
||||
import ModalHeader from './ModalHeader';
|
||||
import ReportStatsCard from './widgets/ReportStatsCard';
|
||||
import SidemenuIcon from './SidemenuIcon';
|
||||
import Spinner from 'shared/components/Spinner';
|
||||
import SubmitButton from './buttons/FormSubmitButton';
|
||||
@@ -46,7 +45,6 @@ const WootUIKit = {
|
||||
LoadingState,
|
||||
Modal,
|
||||
ModalHeader,
|
||||
ReportStatsCard,
|
||||
SidemenuIcon,
|
||||
Spinner,
|
||||
SubmitButton,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { frontendURL } from '../../../../helper/URLHelper';
|
||||
|
||||
const campaigns = accountId => ({
|
||||
parentNav: 'campaigns',
|
||||
routes: ['settings_account_campaigns', 'one_off'],
|
||||
routes: ['ongoing_campaigns', 'one_off'],
|
||||
menuItems: [
|
||||
{
|
||||
icon: 'arrow-swap',
|
||||
@@ -10,7 +10,7 @@ const campaigns = accountId => ({
|
||||
key: 'ongoingCampaigns',
|
||||
hasSubMenu: false,
|
||||
toState: frontendURL(`accounts/${accountId}/campaigns/ongoing`),
|
||||
toStateName: 'settings_account_campaigns',
|
||||
toStateName: 'ongoing_campaigns',
|
||||
},
|
||||
{
|
||||
key: 'oneOffCampaigns',
|
||||
|
||||
@@ -2,6 +2,15 @@ import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
|
||||
const primaryMenuItems = accountId => [
|
||||
{
|
||||
icon: 'mail-inbox',
|
||||
key: 'inboxView',
|
||||
label: 'INBOX_VIEW',
|
||||
featureFlag: FEATURE_FLAGS.INBOX_VIEW,
|
||||
toState: frontendURL(`accounts/${accountId}/inbox-view`),
|
||||
toStateName: 'inbox_view',
|
||||
roles: ['administrator', 'agent'],
|
||||
},
|
||||
{
|
||||
icon: 'chat',
|
||||
key: 'conversations',
|
||||
@@ -34,7 +43,7 @@ const primaryMenuItems = accountId => [
|
||||
label: 'CAMPAIGNS',
|
||||
featureFlag: FEATURE_FLAGS.CAMPAIGNS,
|
||||
toState: frontendURL(`accounts/${accountId}/campaigns`),
|
||||
toStateName: 'settings_account_campaigns',
|
||||
toStateName: 'ongoing_campaigns',
|
||||
roles: ['administrator'],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
|
||||
const reports = accountId => ({
|
||||
@@ -6,6 +7,7 @@ const reports = accountId => ({
|
||||
'account_overview_reports',
|
||||
'conversation_reports',
|
||||
'csat_reports',
|
||||
'bot_reports',
|
||||
'agent_reports',
|
||||
'label_reports',
|
||||
'inbox_reports',
|
||||
@@ -33,6 +35,14 @@ const reports = accountId => ({
|
||||
toState: frontendURL(`accounts/${accountId}/reports/csat`),
|
||||
toStateName: 'csat_reports',
|
||||
},
|
||||
{
|
||||
icon: 'bot',
|
||||
label: 'REPORTS_BOT',
|
||||
hasSubMenu: false,
|
||||
featureFlag: FEATURE_FLAGS.RESPONSE_BOT,
|
||||
toState: frontendURL(`accounts/${accountId}/reports/bot`),
|
||||
toStateName: 'bot_reports',
|
||||
},
|
||||
{
|
||||
icon: 'people',
|
||||
label: 'REPORTS_AGENT',
|
||||
|
||||
@@ -39,6 +39,7 @@ const settings = accountId => ({
|
||||
'settings_teams_finish',
|
||||
'settings_teams_list',
|
||||
'settings_teams_new',
|
||||
'sla_list',
|
||||
],
|
||||
menuItems: [
|
||||
{
|
||||
@@ -158,6 +159,15 @@ const settings = accountId => ({
|
||||
featureFlag: FEATURE_FLAGS.AUDIT_LOGS,
|
||||
beta: true,
|
||||
},
|
||||
{
|
||||
icon: 'document-list-clock',
|
||||
label: 'SLA',
|
||||
hasSubMenu: false,
|
||||
toState: frontendURL(`accounts/${accountId}/settings/sla/list`),
|
||||
toStateName: 'sla_list',
|
||||
featureFlag: FEATURE_FLAGS.SLA,
|
||||
beta: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
<div
|
||||
v-if="globalConfig.createNewAccountFromDashboard"
|
||||
class="modal-footer delete-item"
|
||||
class="flex justify-end items-center p-8 gap-2"
|
||||
>
|
||||
<button
|
||||
class="button success large expanded nice"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<woot-button
|
||||
v-tooltip.right="$t(`SIDEBAR.PROFILE_SETTINGS`)"
|
||||
variant="link"
|
||||
class="current-user"
|
||||
class="items-center flex rounded-full"
|
||||
@click="handleClick"
|
||||
>
|
||||
<thumbnail
|
||||
@@ -38,12 +38,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.current-user {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--white);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="mb-4">
|
||||
<button
|
||||
class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-700 dark:hover:text-slate-100 hover:text-slate-600 relative"
|
||||
class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 p-0 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-700 dark:hover:text-slate-100 hover:text-slate-600 relative"
|
||||
:class="{
|
||||
'bg-woot-50 dark:bg-slate-800 text-woot-500 hover:bg-woot-50':
|
||||
isNotificationPanelActive,
|
||||
@@ -16,7 +16,7 @@
|
||||
/>
|
||||
<span
|
||||
v-if="unreadCount"
|
||||
class="text-black-900 bg-yellow-300 absolute -top-0.5 -right-1 p-1 text-xxs min-w-[1rem] rounded-full"
|
||||
class="text-black-900 bg-yellow-300 absolute -top-0.5 -right-1 text-xxs min-w-[1rem] rounded-full"
|
||||
>
|
||||
{{ unreadCount }}
|
||||
</span>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</span>
|
||||
<span
|
||||
v-if="showChildCount"
|
||||
class="bg-slate-50 dark:bg-slate-700 rounded text-xxs font-medium mx-1 py-0 px-1"
|
||||
class="bg-slate-50 dark:bg-slate-700 rounded-full min-w-[18px] justify-center items-center flex text-xxs font-medium mx-1 py-0 px-1"
|
||||
:class="
|
||||
isCountZero
|
||||
? `text-slate-300 dark:text-slate-500`
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
<template>
|
||||
<div :class="labelClass" :style="labelStyle" :title="description">
|
||||
<div
|
||||
class="ltr:mr-1 rtl:ml-1 mb-1"
|
||||
:class="labelClass"
|
||||
:style="labelStyle"
|
||||
:title="description"
|
||||
>
|
||||
<span v-if="icon" class="label-action--button">
|
||||
<fluent-icon :icon="icon" size="12" class="label--icon cursor-pointer" />
|
||||
</span>
|
||||
<span
|
||||
v-if="['smooth', 'dashed'].includes(variant) && title && !icon"
|
||||
:style="{ background: color }"
|
||||
class="label-color-dot"
|
||||
class="label-color-dot flex-shrink-0"
|
||||
/>
|
||||
<span v-if="!href">{{ title }}</span>
|
||||
<span v-if="!href" class="whitespace-nowrap text-ellipsis overflow-hidden">
|
||||
{{ title }}
|
||||
</span>
|
||||
<a v-else :href="href" :style="anchorStyle">{{ title }}</a>
|
||||
<button
|
||||
v-if="showClose"
|
||||
class="label-close--button"
|
||||
class="label-close--button p-0"
|
||||
:style="{ color: textColor }"
|
||||
@click="onClick"
|
||||
>
|
||||
@@ -104,7 +111,7 @@ export default {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.label {
|
||||
@apply inline-flex items-center font-medium gap-1 mr-1 rtl:ml-1 rtl:mr-0 mb-1 p-1 bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100 border border-solid border-slate-75 dark:border-slate-600 h-6;
|
||||
@apply inline-flex items-center font-medium text-xs rounded-[4px] gap-1 p-1 bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100 border border-solid border-slate-75 dark:border-slate-600 h-6;
|
||||
|
||||
&.small {
|
||||
@apply text-xs py-0.5 px-1 leading-tight h-5;
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<template>
|
||||
<div class="preview-card--wrap" :class="{ 'active-card': active }">
|
||||
<div class="header--wrap" :class="{ active: active }">
|
||||
<div
|
||||
class="flex flex-col min-w-[15rem] max-h-[21.25rem] max-w-[23.75rem] rounded-md border border-solid border-slate-75 dark:border-slate-600"
|
||||
:class="{
|
||||
'bg-woot-25 dark:bg-slate-700 border border-solid border-woot-300 dark:border-woot-400':
|
||||
active,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="flex justify-between items-center px-2 w-full h-10 bg-slate-50 dark:bg-slate-900 rounded-t-[5px] border-b border-solid border-slate-50 dark:border-slate-600"
|
||||
:class="{
|
||||
'bg-woot-50 border-b border-solid border-woot-75 dark:border-woot-700':
|
||||
active,
|
||||
}"
|
||||
>
|
||||
<div class="items-center flex font-medium p-1 text-sm">{{ heading }}</div>
|
||||
<fluent-icon
|
||||
v-if="active"
|
||||
@@ -56,21 +68,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.preview-card--wrap {
|
||||
@apply flex flex-col min-w-[15rem] max-h-[21.25rem] max-w-[23.75rem] rounded-md border border-solid border-slate-75 dark:border-slate-600;
|
||||
|
||||
.header--wrap {
|
||||
@apply flex justify-between items-center px-2 w-full h-10 bg-slate-50 dark:bg-slate-900 rounded-t-[5px] border-b border-solid border-slate-50 dark:border-slate-600;
|
||||
}
|
||||
|
||||
.active {
|
||||
@apply bg-woot-50 border-b border-solid border-woot-75 dark:border-woot-700;
|
||||
}
|
||||
}
|
||||
|
||||
.active-card {
|
||||
@apply bg-woot-25 dark:bg-slate-700 border border-solid border-woot-300 dark:border-woot-400;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<button
|
||||
type="button"
|
||||
class="toggle-button"
|
||||
class="toggle-button p-0"
|
||||
:class="{ active: value, small: size === 'small' }"
|
||||
role="switch"
|
||||
:aria-checked="value.toString()"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
>
|
||||
<a @click="onTabClick">
|
||||
{{ name }}
|
||||
<div v-if="showBadge" class="badge">
|
||||
<div v-if="showBadge" class="badge min-w-[20px]">
|
||||
<span>
|
||||
{{ getItemCount }}
|
||||
</span>
|
||||
|
||||
@@ -13,18 +13,23 @@
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<h3
|
||||
class="overflow-hidden whitespace-nowrap text-ellipsis leading-tight"
|
||||
class="text-slate-800 dark:text-slate-100 text-base font-medium pl-6 overflow-hidden whitespace-nowrap mb-1.5 text-ellipsis leading-tight"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h3>
|
||||
<span v-if="isOver(item)" class="completed">
|
||||
<span
|
||||
v-if="isOver(item)"
|
||||
class="text-green-500 dark:text-green-500 ml-1"
|
||||
>
|
||||
<fluent-icon icon="checkmark" />
|
||||
</span>
|
||||
</div>
|
||||
<span class="step">
|
||||
{{ items.indexOf(item) + 1 }}
|
||||
</span>
|
||||
<p>{{ item.body }}</p>
|
||||
<p class="text-slate-600 dark:text-slate-300 text-sm m-0 pl-6">
|
||||
{{ item.body }}
|
||||
</p>
|
||||
</div>
|
||||
</transition-group>
|
||||
</template>
|
||||
@@ -60,3 +65,40 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.wizard-box {
|
||||
.item {
|
||||
@apply cursor-pointer after:bg-slate-75 before:bg-slate-75 dark:after:bg-slate-600 dark:before:bg-slate-600 py-4 pr-4 pl-6 relative before:h-4 before:top-0 last:before:h-0 first:before:h-0 last:after:h-0 before:content-[''] before:absolute before:w-0.5 after:content-[''] after:h-full after:absolute after:top-5 after:w-0.5;
|
||||
|
||||
&.active {
|
||||
h3 {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
}
|
||||
|
||||
&.over {
|
||||
&::after {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
|
||||
& + .item {
|
||||
&::before {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-slate-75 dark:bg-slate-600 rounded-2xl font-medium w-4 left-4 leading-4 z-[999] absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
📄
|
||||
</span>
|
||||
</div>
|
||||
<div class="max-w-[60%] min-w-[50%] overflow-hidden text-ellipsis">
|
||||
<div class="max-w-3/5 min-w-[50%] overflow-hidden text-ellipsis">
|
||||
<span
|
||||
class="h-4 overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<button
|
||||
class="header-section flex items-center text-base font-normal mr-4 ml-2 cursor-pointer text-woot-500 dark:text-woot-500"
|
||||
class="header-section flex items-center text-base font-normal mr-4 ml-2 p-0 cursor-pointer text-woot-500 dark:text-woot-500"
|
||||
@click.capture="goBack"
|
||||
>
|
||||
<fluent-icon icon="chevron-left" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="empty-state py-16 px-1 ml-0 mr-0">
|
||||
<h3
|
||||
v-if="title"
|
||||
class="text-slate-700 dark:text-slate-200 block text-center w-full text-4xl font-thin"
|
||||
class="text-slate-700 dark:text-slate-200 block text-center w-full text-xl font-thin"
|
||||
>
|
||||
{{ title }}
|
||||
</h3>
|
||||
@@ -15,6 +15,7 @@
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="inbox--name inline-flex items-center py-0.5 px-0 leading-3 font-medium bg-none text-slate-600 dark:text-slate-500 text-xs my-0 mx-2.5"
|
||||
class="inbox--name inline-flex items-center py-0.5 px-0 leading-3 whitespace-nowrap font-medium bg-none text-slate-600 dark:text-slate-500 text-xs my-0 mx-2.5"
|
||||
>
|
||||
<fluent-icon
|
||||
class="mr-0.5 rtl:ml-0.5 rtl:mr-0"
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-center p-8">
|
||||
<h6
|
||||
class="block text-base text-center w-100 text-slate-800 dark:text-slate-300"
|
||||
class="flex items-center gap-2 text-base text-center w-100 text-slate-800 dark:text-slate-300"
|
||||
>
|
||||
<span class="mr-3">{{ message }}</span>
|
||||
<span class="text-base font-medium text-slate-800 dark:text-slate-100">
|
||||
{{ message }}
|
||||
</span>
|
||||
<span class="spinner" />
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="small-2 report-card"
|
||||
:class="{ active: selected }"
|
||||
@click="onClick(index)"
|
||||
>
|
||||
<h3 class="heading">
|
||||
<span>{{ heading }}</span>
|
||||
<fluent-icon
|
||||
v-if="infoText"
|
||||
v-tooltip="infoText"
|
||||
size="14"
|
||||
icon="info"
|
||||
class="info-icon"
|
||||
/>
|
||||
</h3>
|
||||
<div class="metric-wrap">
|
||||
<h4 class="metric">
|
||||
{{ point }}
|
||||
</h4>
|
||||
<span v-if="trend !== 0" :class="trendClass">{{ trendValue }}</span>
|
||||
</div>
|
||||
<p class="desc">
|
||||
{{ desc }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
heading: { type: String, default: '' },
|
||||
infoText: { type: String, default: '' },
|
||||
point: { type: [Number, String], default: '' },
|
||||
trend: { type: Number, default: null },
|
||||
index: { type: Number, default: null },
|
||||
desc: { type: String, default: '' },
|
||||
selected: Boolean,
|
||||
onClick: { type: Function, default: () => {} },
|
||||
},
|
||||
computed: {
|
||||
trendClass() {
|
||||
if (this.trend > 0) {
|
||||
return 'metric-trend metric-up';
|
||||
}
|
||||
|
||||
return 'metric-trend metric-down';
|
||||
},
|
||||
trendValue() {
|
||||
if (this.trend > 0) {
|
||||
return `+${this.trend}%`;
|
||||
}
|
||||
|
||||
return `${this.trend}%`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
class="bg-slate-25 dark:bg-slate-900 pt-4 pb-0 px-8 border-b border-solid border-slate-50 dark:border-slate-800/50"
|
||||
>
|
||||
<h2 class="text-2xl text-slate-800 dark:text-slate-100">
|
||||
<h2 class="text-2xl text-slate-800 dark:text-slate-100 mb-1 font-medium">
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
<p
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<footer
|
||||
v-if="isFooterVisible"
|
||||
class="bg-white dark:bg-slate-800 h-[60px] border-t border-solid border-slate-75 dark:border-slate-700/50 flex items-center justify-between py-0 px-4"
|
||||
class="bg-white dark:bg-slate-800 h-12 border-t border-solid border-slate-75 dark:border-slate-700/50 flex items-center justify-between px-6"
|
||||
>
|
||||
<div class="left-aligned-wrap">
|
||||
<div class="text-xs text-slate-600 dark:text-slate-200">
|
||||
@@ -98,9 +98,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
pageFooterIconClass() {
|
||||
return this.isRTLView
|
||||
? 'margin-right-minus-slab'
|
||||
: 'margin-left-minus-slab';
|
||||
return this.isRTLView ? '-mr-3' : '-ml-3';
|
||||
},
|
||||
isFooterVisible() {
|
||||
return this.totalCount && !(this.firstIndex > this.totalCount);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<img
|
||||
v-show="shouldShowImage"
|
||||
:src="src"
|
||||
draggable="false"
|
||||
:class="thumbnailClass"
|
||||
@load="onImgLoad"
|
||||
@error="onImgError"
|
||||
|
||||
@@ -225,8 +225,11 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
.audio-wave-wrapper {
|
||||
min-height: 5rem;
|
||||
height: 5rem;
|
||||
@apply h-20 min-h-[5rem];
|
||||
|
||||
.video-js {
|
||||
@apply bg-transparent max-h-60 min-h-[3rem] pt-4 px-0 pb-0 resize-none;
|
||||
}
|
||||
}
|
||||
.video-js .vjs-control-bar {
|
||||
background-color: transparent;
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
class="fixed top-0 bottom-0 left-0 right-0 z-20 flex flex-col items-center justify-center w-full h-full gap-2 text-slate-900 dark:text-slate-50 bg-modal-backdrop-light dark:bg-modal-backdrop-dark"
|
||||
>
|
||||
<fluent-icon icon="cloud-backup" size="40" />
|
||||
<h4 class="page-sub-title text-slate-900 dark:text-slate-50">
|
||||
<h4 class="text-2xl break-words text-slate-900 dark:text-slate-50">
|
||||
{{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
@@ -146,6 +146,6 @@ export default {
|
||||
}
|
||||
}
|
||||
.button--note {
|
||||
@apply text-yellow-600 dark:text-yellow-600;
|
||||
@apply text-yellow-600 dark:text-yellow-600 bg-transparent dark:bg-transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user