diff --git a/src/_nav.js b/src/_nav.js
index 14c02f4fe..e05863e70 100644
--- a/src/_nav.js
+++ b/src/_nav.js
@@ -16,33 +16,61 @@ import {
} from '@coreui/icons'
import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react'
+// Helper component for external link labels with icon
+const ExternalLinkLabel = ({ children }) => (
+ <>
+ {children}
+
+ >
+)
+
+// Badge configuration constants
+const BADGE_PRO = {
+ color: 'danger',
+ text: 'PRO',
+}
+
+const BADGE_NEW = {
+ color: 'info',
+ text: 'NEW',
+}
+
+// CoreUI Pro documentation base URL
+const PRO_DOCS_BASE = 'https://coreui.io/react/docs'
+
+// Navigation item factories for consistency and DRY principle
+const createNavItem = (name, to, options = {}) => ({
+ component: CNavItem,
+ name,
+ to,
+ ...options,
+})
+
+const createProNavItem = (name, path) => ({
+ component: CNavItem,
+ name: {name},
+ href: `${PRO_DOCS_BASE}${path}`,
+ badge: BADGE_PRO,
+})
+
const _nav = [
{
component: CNavItem,
name: 'Dashboard',
to: '/dashboard',
icon: ,
- badge: {
- color: 'info',
- text: 'NEW',
- },
+ badge: BADGE_NEW,
},
{
component: CNavTitle,
name: 'Theme',
},
- {
- component: CNavItem,
- name: 'Colors',
- to: '/theme/colors',
+ createNavItem('Colors', '/theme/colors', {
icon: ,
- },
- {
- component: CNavItem,
- name: 'Typography',
- to: '/theme/typography',
+ }),
+ createNavItem('Typography', '/theme/typography', {
icon: ,
- },
+ }),
{
component: CNavTitle,
name: 'Components',
@@ -53,132 +81,25 @@ const _nav = [
to: '/base',
icon: ,
items: [
- {
- component: CNavItem,
- name: 'Accordion',
- to: '/base/accordion',
- },
- {
- component: CNavItem,
- name: 'Breadcrumb',
- to: '/base/breadcrumbs',
- },
- {
- component: CNavItem,
- name: (
-
- {'Calendar'}
-
-
- ),
- href: 'https://coreui.io/react/docs/components/calendar/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Cards',
- to: '/base/cards',
- },
- {
- component: CNavItem,
- name: 'Carousel',
- to: '/base/carousels',
- },
- {
- component: CNavItem,
- name: 'Collapse',
- to: '/base/collapses',
- },
- {
- component: CNavItem,
- name: 'List group',
- to: '/base/list-groups',
- },
- {
- component: CNavItem,
- name: 'Navs & Tabs',
- to: '/base/navs',
- },
- {
- component: CNavItem,
- name: 'Pagination',
- to: '/base/paginations',
- },
- {
- component: CNavItem,
- name: 'Placeholders',
- to: '/base/placeholders',
- },
- {
- component: CNavItem,
- name: 'Popovers',
- to: '/base/popovers',
- },
- {
- component: CNavItem,
- name: 'Progress',
- to: '/base/progress',
- },
- {
- component: CNavItem,
- name: 'Smart Pagination',
- href: 'https://coreui.io/react/docs/components/smart-pagination/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: (
-
- {'Smart Table'}
-
-
- ),
- href: 'https://coreui.io/react/docs/components/smart-table/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Spinners',
- to: '/base/spinners',
- },
- {
- component: CNavItem,
- name: 'Tables',
- to: '/base/tables',
- },
- {
- component: CNavItem,
- name: 'Tabs',
- to: '/base/tabs',
- },
- {
- component: CNavItem,
- name: 'Tooltips',
- to: '/base/tooltips',
- },
- {
- component: CNavItem,
- name: (
-
- {'Virtual Scroller'}
-
-
- ),
- href: 'https://coreui.io/react/docs/components/virtual-scroller/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
+ createNavItem('Accordion', '/base/accordion'),
+ createNavItem('Breadcrumb', '/base/breadcrumbs'),
+ createProNavItem('Calendar', '/components/calendar/'),
+ createNavItem('Cards', '/base/cards'),
+ createNavItem('Carousel', '/base/carousels'),
+ createNavItem('Collapse', '/base/collapses'),
+ createNavItem('List group', '/base/list-groups'),
+ createNavItem('Navs & Tabs', '/base/navs'),
+ createNavItem('Pagination', '/base/paginations'),
+ createNavItem('Placeholders', '/base/placeholders'),
+ createNavItem('Popovers', '/base/popovers'),
+ createNavItem('Progress', '/base/progress'),
+ createProNavItem('Smart Pagination', '/components/smart-pagination/'),
+ createProNavItem('Smart Table', '/components/smart-table/'),
+ createNavItem('Spinners', '/base/spinners'),
+ createNavItem('Tables', '/base/tables'),
+ createNavItem('Tabs', '/base/tabs'),
+ createNavItem('Tooltips', '/base/tooltips'),
+ createProNavItem('Virtual Scroller', '/components/virtual-scroller/'),
],
},
{
@@ -187,35 +108,10 @@ const _nav = [
to: '/buttons',
icon: ,
items: [
- {
- component: CNavItem,
- name: 'Buttons',
- to: '/buttons/buttons',
- },
- {
- component: CNavItem,
- name: 'Buttons groups',
- to: '/buttons/button-groups',
- },
- {
- component: CNavItem,
- name: 'Dropdowns',
- to: '/buttons/dropdowns',
- },
- {
- component: CNavItem,
- name: (
-
- {'Loading Button'}
-
-
- ),
- href: 'https://coreui.io/react/docs/components/loading-button/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
+ createNavItem('Buttons', '/buttons/buttons'),
+ createNavItem('Buttons groups', '/buttons/button-groups'),
+ createNavItem('Dropdowns', '/buttons/dropdowns'),
+ createProNavItem('Loading Button', '/components/loading-button/'),
],
},
{
@@ -223,167 +119,23 @@ const _nav = [
name: 'Forms',
icon: ,
items: [
- {
- component: CNavItem,
- name: (
-
- {'Autocomplete'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/autocomplete/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Checks & Radios',
- to: '/forms/checks-radios',
- },
- {
- component: CNavItem,
- name: (
-
- {'Date Picker'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/date-picker/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Date Range Picker',
- href: 'https://coreui.io/react/docs/forms/date-range-picker/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Floating Labels',
- to: '/forms/floating-labels',
- },
- {
- component: CNavItem,
- name: 'Form Control',
- to: '/forms/form-control',
- },
- {
- component: CNavItem,
- name: 'Input Group',
- to: '/forms/input-group',
- },
- {
- component: CNavItem,
- name: (
-
- {'Multi Select'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/multi-select/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: (
-
- {'Password Input'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/password-input/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Range',
- to: '/forms/range',
- },
- {
- component: CNavItem,
- name: (
-
- {'Range Slider'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/range-slider/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: (
-
- {'Rating'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/rating/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Select',
- to: '/forms/select',
- },
- {
- component: CNavItem,
- name: (
-
- {'Stepper'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/stepper/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: (
-
- {'Time Picker'}
-
-
- ),
- href: 'https://coreui.io/react/docs/forms/time-picker/',
- badge: {
- color: 'danger',
- text: 'PRO',
- },
- },
- {
- component: CNavItem,
- name: 'Layout',
- to: '/forms/layout',
- },
- {
- component: CNavItem,
- name: 'Validation',
- to: '/forms/validation',
- },
+ createProNavItem('Autocomplete', '/forms/autocomplete/'),
+ createNavItem('Checks & Radios', '/forms/checks-radios'),
+ createProNavItem('Date Picker', '/forms/date-picker/'),
+ createProNavItem('Date Range Picker', '/forms/date-range-picker/'),
+ createNavItem('Floating Labels', '/forms/floating-labels'),
+ createNavItem('Form Control', '/forms/form-control'),
+ createNavItem('Input Group', '/forms/input-group'),
+ createProNavItem('Multi Select', '/forms/multi-select/'),
+ createProNavItem('Password Input', '/forms/password-input/'),
+ createNavItem('Range', '/forms/range'),
+ createProNavItem('Range Slider', '/forms/range-slider/'),
+ createProNavItem('Rating', '/forms/rating/'),
+ createNavItem('Select', '/forms/select'),
+ createProNavItem('Stepper', '/forms/stepper/'),
+ createProNavItem('Time Picker', '/forms/time-picker/'),
+ createNavItem('Layout', '/forms/layout'),
+ createNavItem('Validation', '/forms/validation'),
],
},
{
@@ -397,21 +149,9 @@ const _nav = [
name: 'Icons',
icon: ,
items: [
- {
- component: CNavItem,
- name: 'CoreUI Free',
- to: '/icons/coreui-icons',
- },
- {
- component: CNavItem,
- name: 'CoreUI Flags',
- to: '/icons/flags',
- },
- {
- component: CNavItem,
- name: 'CoreUI Brands',
- to: '/icons/brands',
- },
+ createNavItem('CoreUI Free', '/icons/coreui-icons'),
+ createNavItem('CoreUI Flags', '/icons/flags'),
+ createNavItem('CoreUI Brands', '/icons/brands'),
],
},
{
@@ -419,26 +159,10 @@ const _nav = [
name: 'Notifications',
icon: ,
items: [
- {
- component: CNavItem,
- name: 'Alerts',
- to: '/notifications/alerts',
- },
- {
- component: CNavItem,
- name: 'Badges',
- to: '/notifications/badges',
- },
- {
- component: CNavItem,
- name: 'Modal',
- to: '/notifications/modals',
- },
- {
- component: CNavItem,
- name: 'Toasts',
- to: '/notifications/toasts',
- },
+ createNavItem('Alerts', '/notifications/alerts'),
+ createNavItem('Badges', '/notifications/badges'),
+ createNavItem('Modal', '/notifications/modals'),
+ createNavItem('Toasts', '/notifications/toasts'),
],
},
{
@@ -446,10 +170,7 @@ const _nav = [
name: 'Widgets',
to: '/widgets',
icon: ,
- badge: {
- color: 'info',
- text: 'NEW',
- },
+ badge: BADGE_NEW,
},
{
component: CNavTitle,
@@ -460,26 +181,10 @@ const _nav = [
name: 'Pages',
icon: ,
items: [
- {
- component: CNavItem,
- name: 'Login',
- to: '/login',
- },
- {
- component: CNavItem,
- name: 'Register',
- to: '/register',
- },
- {
- component: CNavItem,
- name: 'Error 404',
- to: '/404',
- },
- {
- component: CNavItem,
- name: 'Error 500',
- to: '/500',
- },
+ createNavItem('Login', '/login'),
+ createNavItem('Register', '/register'),
+ createNavItem('Error 404', '/404'),
+ createNavItem('Error 500', '/500'),
],
},
{
diff --git a/src/views/widgets/Widgets.js b/src/views/widgets/Widgets.js
index 4a34afe4c..63359149d 100644
--- a/src/views/widgets/Widgets.js
+++ b/src/views/widgets/Widgets.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, { useMemo } from 'react'
import {
CCard,
CCardBody,
@@ -34,16 +34,120 @@ import { DocsExample } from 'src/components'
import WidgetsBrand from './WidgetsBrand'
import WidgetsDropdown from './WidgetsDropdown'
+// Constants
+const CHART_LABELS = ['M', 'T', 'W', 'T', 'F', 'S', 'S', 'M', 'T', 'W', 'T', 'F', 'S', 'S', 'M']
+
+const COMMON_CHART_OPTIONS = {
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ display: false,
+ },
+ },
+ scales: {
+ x: {
+ display: false,
+ },
+ y: {
+ display: false,
+ },
+ },
+}
+
+const LINE_CHART_OPTIONS = {
+ ...COMMON_CHART_OPTIONS,
+ elements: {
+ line: {
+ tension: 0.4,
+ },
+ point: {
+ radius: 0,
+ },
+ },
+}
+
+// Helper to generate random data
+const generateRandomData = (count, min = 40, max = 100) =>
+ Array.from({ length: count }, () => Math.floor(Math.random() * (max - min + 1) + min))
+
+// Footer component for widgets
+const WidgetFooter = () => (
+ noreferrer
+ target="_blank"
+ >
+ View more
+
+
+)
+
+// Chart factory functions
+const createBarChartConfig = (color, data) => ({
+ labels: CHART_LABELS,
+ datasets: [
+ {
+ backgroundColor: getStyle(color),
+ borderColor: 'transparent',
+ borderWidth: 1,
+ data,
+ },
+ ],
+})
+
+const createLineChartConfig = (color, data) => ({
+ labels: CHART_LABELS,
+ datasets: [
+ {
+ backgroundColor: 'transparent',
+ borderColor: getStyle(color),
+ borderWidth: 2,
+ data,
+ },
+ ],
+})
+
const Widgets = () => {
- const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
+ // Generate random data once per render
+ const chartData = useMemo(() => ({
+ bar1: generateRandomData(15),
+ bar2: generateRandomData(15),
+ bar3: generateRandomData(15),
+ line1: generateRandomData(15),
+ line2: generateRandomData(15),
+ line3: generateRandomData(15),
+ }), [])
+
+ // Reusable chart components
+ const BarChart = ({ color, data }) => (
+
+ )
+
+ const LineChart = ({ color, data }) => (
+
+ )
return (
Widgets
+ {/* CWidgetStatsA Example */}
+
+ {/* CWidgetStatsB Example - Default */}
@@ -80,6 +184,8 @@ const Widgets = () => {
+
+ {/* CWidgetStatsB Example - Inverse */}
@@ -124,460 +230,56 @@ const Widgets = () => {
+
+ {/* CWidgetStatsE Example - With Charts */}
- }
+ chart={}
title="title"
value="1,123"
/>
- }
+ chart={}
title="title"
value="1,123"
/>
- }
+ chart={}
title="title"
value="1,123"
/>
- }
+ chart={}
title="title"
value="1,123"
/>
- }
+ chart={}
title="title"
value="1,123"
/>
- }
+ chart={}
title="title"
value="1,123"
/>
+
+ {/* CWidgetStatsF Example - Basic */}
@@ -614,7 +316,9 @@ const Widgets = () => {
-
+
+ {/* CWidgetStatsF Example - With Footer */}
+
{
title="income"
value="$1.999,50"
color="primary"
- footer={
-
- View more
-
-
- }
+ footer={}
/>
@@ -641,17 +335,7 @@ const Widgets = () => {
title="income"
value="$1.999,50"
color="info"
- footer={
-
- View more
-
-
- }
+ footer={}
/>
@@ -660,17 +344,7 @@ const Widgets = () => {
title="income"
value="$1.999,50"
color="warning"
- footer={
-
- View more
-
-
- }
+ footer={}
/>
@@ -679,22 +353,14 @@ const Widgets = () => {
title="income"
value="$1.999,50"
color="danger"
- footer={
-
- View more
-
-
- }
+ footer={}
/>
-
+
+ {/* CWidgetStatsF Example - No Padding */}
+
{
+
+ {/* WidgetsBrand Examples */}
+
+
+ {/* CWidgetStatsC Example - Card Group */}
{
/>
+
+ {/* CWidgetStatsC Example - Grid */}
@@ -826,6 +499,8 @@ const Widgets = () => {
+
+ {/* CWidgetStatsC Example - Inverse */}
@@ -895,4 +570,4 @@ const Widgets = () => {
)
}
-export default Widgets
+export default Widgets
\ No newline at end of file