1
0
mirror of https://github.com/tabler/tabler.git synced 2026-06-17 04:40:04 +04:00

Add CRM dashboard with JSON-based cards and charts

This commit is contained in:
Bartek
2026-05-05 01:19:43 +02:00
parent d8bbb1e5a7
commit 2073b2daf4
12 changed files with 717 additions and 0 deletions
+81
View File
@@ -0,0 +1,81 @@
---
title: CRM Dashboard
page-header: CRM Dashboard
page-menu: dashboards.crm
page-libs: [apexcharts]
layout: default
permalink: dashboard-crm.html
---
<div>
<p>Welcome back — here's your CRM overview for today.</p>
<div class="col-12">
<div class="row row-cards">
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="primary" icon="currency-dollar" lt=true
title="MRR" description="$92.4K" change-value="+9.5%" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="azure" icon="filter" lt=true
title="Pipeline" description="$2.4M" change-value="+14%" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="green" icon="circle-check" lt=true
title="Deals won" description="74" change-value="+8" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="purple" icon="percentage" lt=true
title="Conversion" description="5.97%" change-value="+0.4%" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="yellow" icon="activity" lt=true
title="Activities" description="318" change-value="+22" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="red" icon="clock" lt=true
title="Tasks due" description="12" change-value="3 urgent" change-value-color="red" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="cyan" icon="user-plus" lt=true
title="Leads added" description="148" change-value="+31" %}
</div>
<div class="col-sm-6 col-lg-3">
{% include "cards/crm-stats.html" color="green" icon="trending-up" lt=true
title="Churn rate" description="1.8%" change-value="-0.3%" %}
</div>
<div class="col-lg-6">
<div class="row row-cards">
<div class="col-12">
{% include "cards/charts/mrr-overview.html" %}
</div>
<div class="col-12">
{% include "cards/top-deals.html" %}
</div>
</div>
</div>
<div class="col-lg-6">
<div class="row row-cards">
<div class="col-12">
{% include "cards/charts/pipeline-funnel.html" %}
</div>
<div class="col-12">
{% include "cards/recent-activity.html" %}
</div>
</div>
</div>
<div class="col-lg-4">
{% include "cards/tasks-due.html" %}
</div>
<div class="col-lg-4">
{% include "cards/team-leaderboard.html" %}
</div>
<div class="col-lg-4">
{% include "cards/churn-risk.html" %}
</div>
</div>
</div>
</div>
+64
View File
@@ -1877,6 +1877,70 @@
}
]
},
"crm-mrr-overview": {
"type": "line",
"stroke-width": [
3,
2
],
"stroke-dash": [
0,
6
],
"series": [
{
"name": "This year",
"color": "primary",
"data": [
62,
65,
64,
71,
75,
73,
79,
84,
82,
90,
94,
101
]
},
{
"name": "Last year",
"color": "secondary",
"data": [
56,
58,
57,
63,
66,
65,
68,
72,
73,
77,
79,
83
]
}
],
"categories": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"y-max": 110
},
"new-clients": {
"type": "line",
"datetime": true,
+276
View File
@@ -0,0 +1,276 @@
{
"tasks_due": {
"title": "Tasks due",
"badge": 3,
"button_text": "Add task",
"items": [
{
"text": "Send Q2 proposal to Skyline Retail",
"due": "Today",
"color": "red"
},
{
"text": "Follow up with CloudBase - 2nd touch",
"due": "Today",
"color": "red"
},
{
"text": "Schedule demo for NovaBuild Co",
"due": "Tomorrow",
"color": "yellow"
},
{
"text": "Update pipeline notes - Orion Logistics",
"due": "Tomorrow",
"color": "secondary"
},
{
"text": "Prepare renewal deck for MetroPay",
"due": "May 4",
"color": "yellow"
},
{
"text": "Review churn signals - 3 at-risk accounts",
"due": "May 5",
"color": "red"
}
]
},
"leaderboard": {
"title": "Team leaderboard",
"period": "Q2 - May 1, 2026",
"items": [
{
"name": "Olivia Bennett",
"initials": "OB",
"avatar_color": "primary",
"progress": 92,
"amount": "$148K",
"deals": 18,
"score": 92
},
{
"name": "Marcus Lee",
"initials": "ML",
"avatar_color": "purple",
"progress": 78,
"amount": "$124K",
"deals": 15,
"score": 78
},
{
"name": "Sara Mitchell",
"initials": "SM",
"avatar_color": "green",
"progress": 65,
"amount": "$98K",
"deals": 12,
"score": 65
},
{
"name": "James Okonkwo",
"initials": "JO",
"avatar_color": "yellow",
"progress": 54,
"amount": "$82K",
"deals": 10,
"score": 54
},
{
"name": "Lena Muller",
"initials": "LM",
"avatar_color": "red",
"progress": 40,
"amount": "$61K",
"deals": 8,
"score": 40
}
]
},
"churn_risk": {
"title": "Churn risk",
"badge": "3 accounts",
"items": [
{
"company": "Orion Logistics",
"last_contact": "18 days ago",
"level": "High",
"level_color": "red",
"amount": "$24K"
},
{
"company": "Summit Media",
"last_contact": "22 days ago",
"level": "High",
"level_color": "red",
"amount": "$18K"
},
{
"company": "BluePeak Tech",
"last_contact": "12 days ago",
"level": "Medium",
"level_color": "yellow",
"amount": "$31K"
}
]
},
"recent_activity": {
"title": "Recent activity",
"view_all_text": "View all",
"items": [
{
"text": "Olivia Bennett moved Skyline Retail to Negotiation",
"time": "4 min ago",
"icon": "git-merge",
"icon_color": "primary"
},
{
"text": "Marcus Lee added note to CloudBase opportunity",
"time": "22 min ago",
"icon": "notes",
"icon_color": "purple"
},
{
"text": "Sara Mitchell completed task: Schedule NovaBuild demo",
"time": "1 hour ago",
"icon": "check",
"icon_color": "green"
},
{
"text": "Churn alert triggered for Orion Logistics account",
"time": "2 hours ago",
"icon": "alert-triangle",
"icon_color": "red"
},
{
"text": "James Okonkwo created proposal for MetroPay renewal",
"time": "Yesterday",
"icon": "file-text",
"icon_color": "yellow"
}
]
},
"top_deals": {
"title": "Top deals",
"filter_text": "Filter",
"add_deal_text": "Add deal",
"columns": [
"Company",
"Stage",
"Value",
"Probability",
"Owner"
],
"items": [
{
"company": "Skyline Retail",
"contact": "Hannah Cruz",
"stage": "Negotiation",
"stage_color": "yellow",
"value": "$48,000",
"probability": 80,
"probability_color": "green",
"owner_initials": "OB",
"owner_color": "primary"
},
{
"company": "CloudBase Inc",
"contact": "David Park",
"stage": "Proposal",
"stage_color": "purple",
"value": "$32,500",
"probability": 60,
"probability_color": "yellow",
"owner_initials": "ML",
"owner_color": "purple"
},
{
"company": "NovaBuild Co",
"contact": "Priya Sharma",
"stage": "Qualified",
"stage_color": "azure",
"value": "$27,000",
"probability": 45,
"probability_color": "primary",
"owner_initials": "SR",
"owner_color": "green"
},
{
"company": "MetroPay Ltd",
"contact": "Tom Ellis",
"stage": "Proposal",
"stage_color": "purple",
"value": "$21,800",
"probability": 55,
"probability_color": "yellow",
"owner_initials": "JO",
"owner_color": "yellow"
},
{
"company": "Greenridge Partners",
"contact": "Amy Tan",
"stage": "Negotiation",
"stage_color": "yellow",
"value": "$18,400",
"probability": 70,
"probability_color": "green",
"owner_initials": "OB",
"owner_color": "primary"
},
{
"company": "Orion Logistics",
"contact": "Ben Okafor",
"stage": "Qualified",
"stage_color": "azure",
"value": "$14,200",
"probability": 35,
"probability_color": "primary",
"owner_initials": "LM",
"owner_color": "red"
}
]
},
"pipeline_funnel": {
"title": "Pipeline funnel",
"period": "This quarter",
"conversion_label": "Conversion rate",
"conversion_value": "5.97%",
"items": [
{
"label": "Leads",
"count": 1240,
"amount": "$2.4M",
"progress": 100,
"color": "primary"
},
{
"label": "Qualified",
"count": 680,
"amount": "$1.6M",
"progress": 75,
"color": "azure"
},
{
"label": "Proposal",
"count": 310,
"amount": "$940K",
"progress": 52,
"color": "purple"
},
{
"label": "Negotiation",
"count": 148,
"amount": "$580K",
"progress": 34,
"color": "yellow"
},
{
"label": "Closed won",
"count": 74,
"amount": "$312K",
"progress": 18,
"color": "green"
}
]
}
}
+4
View File
@@ -10,6 +10,10 @@
"crypto": {
"url": "dashboard-crypto.html",
"title": "Crypto"
},
"crm": {
"url": "dashboard-crm.html",
"title": "CRM"
}
}
},
@@ -0,0 +1,26 @@
<div class="card">
<div class="card-body">
<div class="d-flex align-items-start justify-content-between gap-3 mb-2">
<div>
<div class="fw-medium">Monthly recurring revenue</div>
<div class="d-flex align-items-baseline gap-2 mt-1">
<div class="h1 mb-0">$92,400</div>
<div class="text-green small fw-medium">+9.5%</div>
</div>
</div>
<div class="d-flex align-items-center gap-3">
<div class="d-flex align-items-center gap-2">
<span class="legend bg-primary"></span>
<span class="small text-secondary">This year</span>
</div>
<div class="d-flex align-items-center gap-2">
<span class="legend bg-secondary"></span>
<span class="small text-secondary">Last year</span>
</div>
</div>
</div>
{% include "ui/chart.html" chart-id="crm-mrr-overview" height=10 %}
</div>
</div>
@@ -0,0 +1,31 @@
<div class="card h-100">
{% assign funnel = crm-dashboard.pipeline_funnel %}
<div class="card-body">
<div class="d-flex align-items-center justify-content-between mb-4">
<div class="fw-medium">{{ funnel.title }}</div>
<div class="small text-secondary">{{ funnel.period }}</div>
</div>
<div class="d-flex flex-column gap-2">
{% for item in funnel.items %}
<div class="row g-2 align-items-center">
<div class="col-3 small text-secondary">{{ item.label }}</div>
<div class="col">
<div class="position-relative">
{% include "ui/progress.html" value=item.progress color=item.color class="h-4" %}
<div class="position-absolute top-50 start-0 translate-middle-y px-2 small fw-semibold text-white">
{{
item.count }}</div>
</div>
</div>
<div class="col-auto small fw-medium text-body text-nowrap">{{ item.amount }}</div>
</div>
{% endfor %}
</div>
<div class="d-flex justify-content-between border-top mt-4 pt-3">
<div class="small text-secondary">{{ funnel.conversion_label }}</div>
<div class="small fw-semibold text-green">{{ funnel.conversion_value }}</div>
</div>
</div>
</div>
+25
View File
@@ -0,0 +1,25 @@
<div class="card h-100">
{% assign churn = crm-dashboard.churn_risk %}
<div class="card-header">
<div class="d-flex align-items-center gap-2">
{% include "ui/icon.html" icon="alert-triangle" class="text-red" %}
<h3 class="card-title mb-0">{{ churn.title }}</h3>
<span class="badge bg-red-lt">{{ churn.badge }}</span>
</div>
</div>
<div class="list-group list-group-flush">
{% for item in churn.items %}
<div class="list-group-item">
<div class="row align-items-center g-2">
<div class="col">
<div class="fw-medium">{{ item.company }}</div>
<div class="small text-secondary">Last contact: {{ item.last_contact }}</div>
</div>
<div class="col-auto"><span class="badge bg-{{ item.level_color }}-lt">{{ item.level }}</span></div>
<div class="col-auto fw-semibold">{{ item.amount }}</div>
</div>
</div>
{% endfor %}
</div>
</div>
+65
View File
@@ -0,0 +1,65 @@
{% assign chart-type = include.chart-type | default: 'line' %}
{% assign chart-position = include.chart-position | default: 'right' %}
{% assign chart-color = include.color | default: 'primary' %}
<div class="card card-sm{% if include.class %} {{ include.class }}{% endif %}">
<div class="card-body px-3 py-2">
<div class="row align-items-center">
{% if include.icon %}
<div class="col-auto">
<span
class="{% if include.color %}bg-{{ include.color }}{% if include.lt %}-lt{% else %} text-white{% endif %}{% endif %} avatar avatar-square">{%
include "ui/icon.html" icon=include.icon %}</span>
</div>
{% elsif include.person-id %}
<div class="col-auto">
{% include "ui/avatar.html" person-id=include.person-id %}
</div>
{% elsif include.chart-data and chart-position == "left" %}
<div class="col-auto">
{% include "ui/chart-sparkline.html" id=include.id data=include.chart-data type=chart-type
color=include.color label=include.chart-label label-icon=include.chart-label-icon %}
</div>
{% endif %}
<div class="col">
<div class="text-secondary small">
{{ include.title | default: 1700 }}
{% if include.small-icon %}
{% include "ui/icon.html" icon=include.small-icon color=include.color class="icon-sm ms-1" %}
{% endif %}
{% if include.description-value %}
<span class="float-end fw-medium text-{{ include.description-value-color | default: 'green' }}">{{
include.description-value }}</span>
{% endif %}
</div>
<div class="h3 m-0 p-0">
{{ include.description | default: "Users" }}
</div>
<div class="text-secondary small text-{{ include.change-value-color | default: 'green' }}">
{{ include.change-value | default: "" }}
</div>
</div>
{% if include.chart-data and chart-position=="right" %}
<div class="col-auto">
{% include "ui/chart-sparkline.html" id=include.id data=include.chart-data type=chart-type color=chart-color
label=include.chart-label label-icon=include.chart-label-icon %}
</div>
{% endif %}
{% if include.trending %}
<div class="col-auto">
{% include "ui/trending.html" value=include.trending %}
</div>
{% endif %}
{% if include.button %}
<div class="col-auto">
{% include "ui/button.html" text=include.button size="sm" %}
</div>
{% endif %}
</div>
</div>
</div>
@@ -0,0 +1,28 @@
<div class="card" style="height: 28rem">
{% assign activity = crm-dashboard.recent_activity %}
<div class="card-header">
<h3 class="card-title">{{ activity.title }}</h3>
<div class="card-actions">
<a href="#" class="small fw-medium text-primary">{{ activity.view_all_text }}</a>
</div>
</div>
<div class="card-body card-body-scrollable card-body-scrollable-shadow">
<div class="divide-y">
{% for item in activity.items %}
<div class="py-3">
<div class="row align-items-center">
<div class="col-auto">
<span class="avatar avatar-sm bg-{{ item.icon_color }}-lt">
{% include "ui/icon.html" icon=item.icon class="icon text-{{ item.icon_color }}" %}
</span>
</div>
<div class="col">
<div class="fw-medium">{{ item.text }}</div>
<div class="small text-secondary">{{ item.time }}</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
+34
View File
@@ -0,0 +1,34 @@
<div class="card h-100">
{% assign tasks = crm-dashboard.tasks_due %}
<div class="card-header">
<div class="d-flex align-items-center gap-2">
<h3 class="card-title mb-0">{{ tasks.title }}</h3>
<span class="badge bg-red text-white">{{ tasks.badge }}</span>
</div>
<div class="card-actions">
<button type="button" class="btn btn-primary btn-sm">
{% include "ui/icon.html" icon="plus" class="me-1" %}
{{ tasks.button_text }}
</button>
</div>
</div>
<div class="list-group list-group-flush list-group-hoverable">
{% for item in tasks.items %}
<label class="list-group-item">
<div class="row align-items-center g-2">
<div class="col-auto">
<input type="checkbox" class="form-check-input m-0">
</div>
<div class="col">
<div>{{ item.text }}</div>
</div>
<div class="col-auto d-flex align-items-center gap-2">
<span class="legend bg-{{ item.color }}"></span>
<span class="small text-secondary">{{ item.due }}</span>
</div>
</div>
</label>
{% endfor %}
</div>
</div>
@@ -0,0 +1,28 @@
<div class="card h-100">
{% assign leaderboard = crm-dashboard.leaderboard %}
<div class="card-header">
<div>
<h3 class="card-title mb-0">{{ leaderboard.title }}</h3>
<div class="small text-secondary mt-1">{{ leaderboard.period }}</div>
</div>
</div>
<div class="list-group list-group-flush">
{% for item in leaderboard.items %}
<div class="list-group-item">
<div class="row align-items-center g-2">
<div class="col-auto fw-bold {% if forloop.first %}text-yellow{% else %}text-secondary{% endif %} w-1 px-3">{{ forloop.index }}</div>
<div class="col-auto">{% include "ui/avatar.html" placeholder=item.initials color=item.avatar_color size="sm" %}</div>
<div class="col">
<div class="fw-medium">{{ item.name }}</div>
{% include "ui/progress.html" size="sm" value=item.progress color=item.avatar_color class="mt-2" %}
</div>
<div class="col-auto text-end">
<div class="fw-semibold">{{ item.amount }}</div>
<div class="small text-secondary">{{ item.deals }} deals - {{ item.score }}%</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
+55
View File
@@ -0,0 +1,55 @@
<div class="card">
{% assign deals = crm-dashboard.top_deals %}
<div class="card-header">
<h3 class="card-title">{{ deals.title }}</h3>
<div class="card-actions d-flex gap-2">
<button type="button" class="btn btn-sm">
{% include "ui/icon.html" icon="filter" class="me-1" %}
{{ deals.filter_text }}
</button>
<button type="button" class="btn btn-primary btn-sm">
{% include "ui/icon.html" icon="plus" class="me-1" %}
{{ deals.add_deal_text }}
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-vcenter card-table text-nowrap">
<thead>
<tr>
{% for column in deals.columns %}
<th>{{ column }}</th>
{% endfor %}
<th class="w-1"></th>
</tr>
</thead>
<tbody>
{% for item in deals.items %}
<tr>
<td>
<div class="fw-medium">{{ item.company }}</div>
<div class="small text-secondary">{{ item.contact }}</div>
</td>
<td><span class="badge bg-{{ item.stage_color }}-lt text-{{ item.stage_color }}">{{ item.stage }}</span></td>
<td class="fw-semibold">{{ item.value }}</td>
<td>
<div class="d-flex align-items-center gap-2">
<div class="w-100">
{% include "ui/progress.html" size="sm" value=item.probability color=item.probability_color %}
</div>
<span class="small text-secondary">{{ item.probability }}%</span>
</div>
</td>
<td>{% include "ui/avatar.html" placeholder=item.owner_initials color=item.owner_color size="sm" %}</td>
<td>
<button type="button" class="btn btn-icon btn-sm">
{% include "ui/icon.html" icon="dots" %}
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>