@beknurakhmed/webforge-cli 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/angular/angular.json +1 -0
- package/templates/overlays/blog/angular/src/main.ts +1 -1
- package/templates/overlays/crm/angular/src/main.ts +1 -1
- package/templates/overlays/crm/nextjs/src/app/deals/page.tsx +35 -83
- package/templates/overlays/crm/nextjs/src/app/globals.css +68 -26
- package/templates/overlays/portfolio/angular/src/main.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beknurakhmed/webforge-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Interactive CLI to generate website project templates — landing pages, e-commerce, CRM, dashboards, blogs, portfolios with React, Vue, Angular, Next.js, Nuxt and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,110 +1,62 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
|
|
5
3
|
interface Deal {
|
|
6
4
|
id: number;
|
|
7
|
-
title: string;
|
|
8
5
|
company: string;
|
|
9
|
-
value:
|
|
10
|
-
stage: 'Qualification' | 'Proposal' | 'Negotiation' | 'Closed Won' | 'Closed Lost';
|
|
11
|
-
probability: number;
|
|
6
|
+
value: number;
|
|
12
7
|
contact: string;
|
|
13
|
-
|
|
14
|
-
icon: string;
|
|
8
|
+
stage: string;
|
|
15
9
|
}
|
|
16
10
|
|
|
17
11
|
const deals: Deal[] = [
|
|
18
|
-
{ id: 1,
|
|
19
|
-
{ id: 2,
|
|
20
|
-
{ id: 3,
|
|
21
|
-
{ id: 4,
|
|
22
|
-
{ id: 5,
|
|
23
|
-
{ id: 6,
|
|
12
|
+
{ id: 1, company: 'TechCorp Inc.', value: 45000, contact: 'Sarah Chen', stage: 'Prospect' },
|
|
13
|
+
{ id: 2, company: 'Innovate.io', value: 28000, contact: 'James Wilson', stage: 'Proposal' },
|
|
14
|
+
{ id: 3, company: 'DesignLab Co.', value: 15000, contact: 'Maria Garcia', stage: 'Qualified' },
|
|
15
|
+
{ id: 4, company: 'GlobalNet Ltd.', value: 62000, contact: 'Robert Kim', stage: 'Won' },
|
|
16
|
+
{ id: 5, company: 'StartupXYZ', value: 18500, contact: 'Emily Brown', stage: 'Proposal' },
|
|
17
|
+
{ id: 6, company: 'Oscorp Labs', value: 34000, contact: 'Michael Davis', stage: 'Prospect' },
|
|
18
|
+
{ id: 7, company: 'LexCorp', value: 55000, contact: 'Rachel Green', stage: 'Qualified' },
|
|
19
|
+
{ id: 8, company: 'Umbrella Co.', value: 21000, contact: 'Lisa Wang', stage: 'Won' },
|
|
24
20
|
];
|
|
25
21
|
|
|
26
|
-
const stages = ['
|
|
22
|
+
const stages = ['Prospect', 'Qualified', 'Proposal', 'Won'];
|
|
27
23
|
|
|
28
24
|
export default function DealsPage() {
|
|
29
|
-
const [activeStage, setActiveStage] = useState('All');
|
|
30
|
-
|
|
31
|
-
const filtered = activeStage === 'All' ? deals : deals.filter((d) => d.stage === activeStage);
|
|
32
25
|
const pipelineTotal = deals
|
|
33
|
-
.filter((d) => d.stage !== '
|
|
34
|
-
.reduce((sum, d) => sum +
|
|
26
|
+
.filter((d) => d.stage !== 'Won')
|
|
27
|
+
.reduce((sum, d) => sum + d.value, 0);
|
|
35
28
|
|
|
36
29
|
return (
|
|
37
30
|
<div className="page">
|
|
38
31
|
<div className="page-header">
|
|
39
|
-
<h1>Deals</h1>
|
|
40
|
-
<p>
|
|
32
|
+
<h1>Deals Pipeline</h1>
|
|
33
|
+
<p>Pipeline value: ${pipelineTotal.toLocaleString()}</p>
|
|
41
34
|
</div>
|
|
42
35
|
|
|
43
|
-
<div className="deals-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
</div>
|
|
48
|
-
<div className="deal-stat">
|
|
49
|
-
<p className="deal-stat-value">${pipelineTotal.toLocaleString()}</p>
|
|
50
|
-
<p className="deal-stat-label">Pipeline Value</p>
|
|
51
|
-
</div>
|
|
52
|
-
<div className="deal-stat">
|
|
53
|
-
<p className="deal-stat-value">{deals.filter((d) => d.stage === 'Closed Won').length}</p>
|
|
54
|
-
<p className="deal-stat-label">Won This Month</p>
|
|
55
|
-
</div>
|
|
56
|
-
<div className="deal-stat">
|
|
57
|
-
<p className="deal-stat-value">{Math.round(deals.reduce((sum, d) => sum + d.probability, 0) / deals.length)}%</p>
|
|
58
|
-
<p className="deal-stat-label">Avg. Probability</p>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div className="filter-group" style={{ marginBottom: '1.5rem' }}>
|
|
63
|
-
{stages.map((stage) => (
|
|
64
|
-
<button
|
|
65
|
-
key={stage}
|
|
66
|
-
className={`filter-btn ${activeStage === stage ? 'active' : ''}`}
|
|
67
|
-
onClick={() => setActiveStage(stage)}
|
|
68
|
-
>
|
|
69
|
-
{stage}
|
|
70
|
-
</button>
|
|
71
|
-
))}
|
|
72
|
-
</div>
|
|
36
|
+
<div className="deals-board">
|
|
37
|
+
{stages.map((stage) => {
|
|
38
|
+
const stageDeals = deals.filter((d) => d.stage === stage);
|
|
39
|
+
const stageTotal = stageDeals.reduce((sum, d) => sum + d.value, 0);
|
|
73
40
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
<span className={`stage-badge ${deal.stage.toLowerCase().replace(' ', '-')}`}>{deal.stage}</span>
|
|
80
|
-
</div>
|
|
81
|
-
<h3 className="deal-title">{deal.title}</h3>
|
|
82
|
-
<p className="deal-company">{deal.company}</p>
|
|
83
|
-
<div className="deal-details">
|
|
84
|
-
<div className="deal-detail">
|
|
85
|
-
<span className="deal-label">Value</span>
|
|
86
|
-
<span className="deal-value-text">{deal.value}</span>
|
|
87
|
-
</div>
|
|
88
|
-
<div className="deal-detail">
|
|
89
|
-
<span className="deal-label">Contact</span>
|
|
90
|
-
<span>{deal.contact}</span>
|
|
91
|
-
</div>
|
|
92
|
-
<div className="deal-detail">
|
|
93
|
-
<span className="deal-label">Close Date</span>
|
|
94
|
-
<span>{deal.closeDate}</span>
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
<div className="deal-probability">
|
|
98
|
-
<div className="probability-header">
|
|
99
|
-
<span>Probability</span>
|
|
100
|
-
<span>{deal.probability}%</span>
|
|
41
|
+
return (
|
|
42
|
+
<div key={stage} className="deals-column">
|
|
43
|
+
<div className="column-header">
|
|
44
|
+
<h3 className="column-title">{stage}</h3>
|
|
45
|
+
<span className="column-count">{stageDeals.length}</span>
|
|
101
46
|
</div>
|
|
102
|
-
<
|
|
103
|
-
|
|
47
|
+
<p className="column-total">${stageTotal.toLocaleString()}</p>
|
|
48
|
+
<div className="column-cards">
|
|
49
|
+
{stageDeals.map((deal) => (
|
|
50
|
+
<div key={deal.id} className="deal-card">
|
|
51
|
+
<h4 className="deal-company">{deal.company}</h4>
|
|
52
|
+
<p className="deal-value">${deal.value.toLocaleString()}</p>
|
|
53
|
+
<span className="deal-contact">👤 {deal.contact}</span>
|
|
54
|
+
</div>
|
|
55
|
+
))}
|
|
104
56
|
</div>
|
|
105
57
|
</div>
|
|
106
|
-
|
|
107
|
-
)
|
|
58
|
+
);
|
|
59
|
+
})}
|
|
108
60
|
</div>
|
|
109
61
|
</div>
|
|
110
62
|
);
|
|
@@ -101,31 +101,73 @@ a { text-decoration: none; color: inherit; }
|
|
|
101
101
|
.status-badge.lead { background: #fef3c7; color: #d97706; }
|
|
102
102
|
.status-badge.inactive { background: #f3f4f6; color: #6b7280; }
|
|
103
103
|
|
|
104
|
-
/* Deals */
|
|
105
|
-
.deals-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
.
|
|
128
|
-
|
|
104
|
+
/* Deals Kanban Board */
|
|
105
|
+
.deals-board {
|
|
106
|
+
display: grid;
|
|
107
|
+
grid-template-columns: repeat(4, 1fr);
|
|
108
|
+
gap: 1.25rem;
|
|
109
|
+
min-height: 400px;
|
|
110
|
+
}
|
|
111
|
+
.deals-column {
|
|
112
|
+
background: var(--bg);
|
|
113
|
+
border-radius: var(--radius);
|
|
114
|
+
padding: 1rem;
|
|
115
|
+
}
|
|
116
|
+
.column-header {
|
|
117
|
+
display: flex;
|
|
118
|
+
justify-content: space-between;
|
|
119
|
+
align-items: center;
|
|
120
|
+
margin-bottom: 0.25rem;
|
|
121
|
+
}
|
|
122
|
+
.column-title {
|
|
123
|
+
font-size: 0.9rem;
|
|
124
|
+
font-weight: 700;
|
|
125
|
+
color: var(--dark);
|
|
126
|
+
}
|
|
127
|
+
.column-count {
|
|
128
|
+
background: var(--white);
|
|
129
|
+
color: var(--text-light);
|
|
130
|
+
font-size: 0.75rem;
|
|
131
|
+
font-weight: 600;
|
|
132
|
+
width: 24px;
|
|
133
|
+
height: 24px;
|
|
134
|
+
border-radius: 50%;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
}
|
|
139
|
+
.column-total {
|
|
140
|
+
font-size: 0.8rem;
|
|
141
|
+
color: var(--text-light);
|
|
142
|
+
margin-bottom: 1rem;
|
|
143
|
+
}
|
|
144
|
+
.column-cards {
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
gap: 0.75rem;
|
|
148
|
+
}
|
|
149
|
+
.deal-card {
|
|
150
|
+
background: var(--white);
|
|
151
|
+
padding: 1rem;
|
|
152
|
+
border-radius: 8px;
|
|
153
|
+
box-shadow: var(--shadow);
|
|
154
|
+
}
|
|
155
|
+
.deal-company {
|
|
156
|
+
font-size: 0.95rem;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
color: var(--dark);
|
|
159
|
+
margin-bottom: 0.25rem;
|
|
160
|
+
}
|
|
161
|
+
.deal-value {
|
|
162
|
+
font-size: 1.1rem;
|
|
163
|
+
font-weight: 700;
|
|
164
|
+
color: var(--primary);
|
|
165
|
+
margin-bottom: 0.5rem;
|
|
166
|
+
}
|
|
167
|
+
.deal-contact {
|
|
168
|
+
font-size: 0.8rem;
|
|
169
|
+
color: var(--text-light);
|
|
170
|
+
}
|
|
129
171
|
|
|
130
172
|
/* Settings */
|
|
131
173
|
.settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); gap: 1.5rem; }
|
|
@@ -160,6 +202,6 @@ a { text-decoration: none; color: inherit; }
|
|
|
160
202
|
.sidebar-link { justify-content: center; padding: 0.75rem; }
|
|
161
203
|
.crm-main { margin-left: 70px; padding: 1rem; }
|
|
162
204
|
.dashboard-grid { grid-template-columns: 1fr; }
|
|
163
|
-
.deals-
|
|
205
|
+
.deals-board { grid-template-columns: repeat(2, 1fr); }
|
|
164
206
|
.settings-grid { grid-template-columns: 1fr; }
|
|
165
207
|
}
|