Skip to content

Commit cd596dc

Browse files
committed
refactor: roadmap.
1 parent 5a59bcd commit cd596dc

File tree

6 files changed

+229
-178
lines changed

6 files changed

+229
-178
lines changed

public/roadmap/roadmap.piml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
(title) Backend Support for Fezcodex
1515
(description) Integrate a cloud provider and add support for backend for Fezcodex.
1616
(category) Infrastructure
17+
(epic) Core Infrastructure
1718
(status) Planned
1819
(priority) Medium
1920
(created_at) 2025-11-29T10:00:00+03:00
@@ -55,6 +56,7 @@
5556
(title) Refactor Projects Page
5657
(description) Better styles & UI/UX for project related pages and components.
5758
(category) UI/UX
59+
(epic) UI Overhaul
5860
(status) Completed
5961
(priority) High
6062
(created_at) 2025-11-28T18:00:00+03:00
@@ -66,6 +68,7 @@
6668
(title) Refactor Blogpost Page
6769
(description) Better styles & UI/UX for blog related pages and components.
6870
(category) UI/UX
71+
(epic) UI Overhaul
6972
(status) Completed
7073
(priority) High
7174
(created_at) 2025-11-28T18:00:00+03:00

src/components/roadmap/RoadmapCard.js

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
import React from 'react';
22
import { Link } from 'react-router-dom';
33
import { motion } from 'framer-motion';
4-
import { KanbanIcon } from '@phosphor-icons/react'; // Using KanbanIcon as a default/watermark icon
5-
import { getStatusClasses, getPriorityClasses, statusTextColor } from '../../utils/roadmapHelpers';
4+
import {
5+
KanbanIcon,
6+
Lightning,
7+
Circle,
8+
ArrowsClockwise,
9+
CheckCircle,
10+
PauseCircle,
11+
Fire,
12+
Equals,
13+
ArrowDown
14+
} from '@phosphor-icons/react';
15+
import { getStatusClasses, getPriorityClasses } from '../../utils/roadmapHelpers';
616

717
const RoadmapCard = ({ app, index }) => {
18+
const getStatusIcon = (status) => {
19+
switch (status) {
20+
case 'Planned': return <Circle weight="bold" />;
21+
case 'In Progress': return <ArrowsClockwise weight="bold" className="animate-spin" />;
22+
case 'Completed': return <CheckCircle weight="bold" />;
23+
case 'On Hold': return <PauseCircle weight="bold" />;
24+
default: return <Circle weight="bold" />;
25+
}
26+
};
27+
28+
const getPriorityIcon = (priority) => {
29+
switch (priority) {
30+
case 'High': return <Fire weight="fill" />;
31+
case 'Medium': return <Equals weight="bold" />;
32+
case 'Low': return <ArrowDown weight="bold" />;
33+
default: return <ArrowDown weight="bold" />;
34+
}
35+
};
36+
837
return (
938
<motion.div
1039
initial={{ opacity: 0, y: 20 }}
@@ -30,18 +59,28 @@ const RoadmapCard = ({ app, index }) => {
3059

3160
{/* Content */}
3261
<div className="relative z-10 flex-grow">
33-
<div className="flex items-center justify-between mb-2">
62+
<div className="flex items-center justify-between mb-3 gap-2">
3463
<span
35-
className={`px-2 py-0 inline-flex text-xs font-mono font-semibold rounded-md shadow-sm border ${getStatusClasses(app.status || 'Planned')} ${statusTextColor(app.status || 'Planned')}`}
64+
className={`px-2 py-0.5 inline-flex items-center gap-1.5 text-[10px] font-mono font-bold uppercase tracking-wider rounded-md shadow-sm ${getStatusClasses(app.status || 'Planned')}`}
3665
>
66+
{getStatusIcon(app.status || 'Planned')}
3767
{app.status || 'Planned'}
3868
</span>
3969
<span
40-
className={`px-2 py-0 inline-flex text-xs font-mono font-semibold rounded-md shadow-sm border ${getPriorityClasses(app.priority || 'Low')}`}
70+
className={`px-2 py-0.5 inline-flex items-center gap-1.5 text-[10px] font-mono font-bold uppercase tracking-wider rounded-md shadow-sm ${getPriorityClasses(app.priority || 'Low')}`}
4171
>
72+
{getPriorityIcon(app.priority || 'Low')}
4273
{app.priority || 'Low'}
4374
</span>
4475
</div>
76+
77+
{app.epic && (
78+
<div className="mb-3 inline-flex items-center gap-1.5 px-2 py-0.5 rounded-md bg-purple-500/20 border border-purple-500/50 text-purple-300 text-[10px] font-mono uppercase tracking-wider font-bold w-fit">
79+
<Lightning weight="fill" size={12} />
80+
{app.epic}
81+
</div>
82+
)}
83+
4584
<h4 className="text-xl font-bold font-mono text-white mb-2 tracking-tight group-hover:text-primary-400 transition-colors">
4685
{app.title}
4786
</h4>
@@ -51,9 +90,10 @@ const RoadmapCard = ({ app, index }) => {
5190
</div>
5291

5392
{app.notes && (
54-
<div className="relative z-10 mt-3 pt-3 border-t border-gray-700">
55-
<p className="text-gray-500 text-xs italic line-clamp-2">
56-
Notes: {app.notes}
93+
<div className="relative z-10 mt-4 bg-black/20 rounded-lg p-3 border border-white/5">
94+
<p className="text-gray-500 text-xs italic line-clamp-2 font-mono">
95+
<span className="font-bold text-gray-400 not-italic mr-2">NOTE:</span>
96+
{app.notes}
5797
</p>
5898
</div>
5999
)}

src/components/roadmap/RoadmapView.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useEffect } from 'react';
22
import RoadmapCard from './RoadmapCard';
3-
import { getOnlyBgStatusColor, statusTextColor } from '../../utils/roadmapHelpers';
3+
import { getStatusClasses } from '../../utils/roadmapHelpers';
44
import { EyeIcon, EyeSlashIcon } from '@phosphor-icons/react';
55
import { useAchievements } from '../../context/AchievementContext';
66

@@ -41,13 +41,11 @@ const RoadmapView = ({ issuesData = [] }) => {
4141
return (
4242
<div key={status} className="bg-gray-900/70 backdrop-blur-sm rounded-xl shadow-lg p-4 border border-gray-800">
4343
<h3
44-
className={`text-lg font-mono tracking-wider mb-4 flex items-center justify-between text-white`}
44+
className={`mb-4 flex items-center justify-between`}
4545
>
46-
<span className="flex items-center gap-2">
47-
<span
48-
className={`w-3 h-3 rounded-full ${getOnlyBgStatusColor(status)} ${statusTextColor(status)}`}
49-
></span>
50-
{status} ({groupIssues[status]?.length || 0})
46+
<span className={`inline-flex items-center gap-2 px-3 py-1 rounded-lg text-sm font-mono font-bold uppercase tracking-wider ${getStatusClasses(status)}`}>
47+
{status}
48+
<span className="opacity-70">({groupIssues[status]?.length || 0})</span>
5149
</span>
5250
<button
5351
onClick={() => toggleColumnVisibility(status)}

src/components/roadmap/TableView.js

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useState } from 'react';
22
import { Link, useNavigate } from 'react-router-dom';
3-
import { MagnifyingGlass, Funnel, CaretUp, CaretDown, Check } from '@phosphor-icons/react';
4-
import { getStatusClasses, getPriorityClasses, statusTextColor } from '../../utils/roadmapHelpers';
3+
import { MagnifyingGlass, Funnel, CaretUp, CaretDown, Check, Lightning, ArrowsDownUp } from '@phosphor-icons/react';
4+
import { getStatusClasses, getPriorityClasses } from '../../utils/roadmapHelpers';
55

66
const TableView = ({ issuesData = [] }) => {
77
const navigate = useNavigate();
@@ -21,7 +21,8 @@ const TableView = ({ issuesData = [] }) => {
2121
const filteredApps = issuesData.filter((app) => {
2222
const matchesFilter = activeFilters.length === 0 || activeFilters.includes(app.status || 'Planned');
2323
const matchesSearch = (app.title?.toLowerCase() || '').includes(searchQuery.toLowerCase()) ||
24-
(app.description?.toLowerCase() || '').includes(searchQuery.toLowerCase());
24+
(app.description?.toLowerCase() || '').includes(searchQuery.toLowerCase()) ||
25+
(app.epic?.toLowerCase() || '').includes(searchQuery.toLowerCase());
2526
return matchesFilter && matchesSearch;
2627
});
2728

@@ -41,6 +42,8 @@ const TableView = ({ issuesData = [] }) => {
4142
comparison =
4243
priorityOrder.indexOf(a.priority || 'Low') -
4344
priorityOrder.indexOf(b.priority || 'Low');
45+
} else if (sortBy === 'epic') {
46+
comparison = (a.epic || '').localeCompare(b.epic || '');
4447
}
4548

4649
return sortOrder === 'asc' ? comparison : -comparison;
@@ -56,8 +59,10 @@ const TableView = ({ issuesData = [] }) => {
5659
};
5760

5861
const SortIcon = ({ column }) => {
59-
if (sortBy !== column) return <div className="w-4 h-4" />; // Placeholder to prevent layout shift
60-
return sortOrder === 'asc' ? <CaretUp weight="bold" size={14} /> : <CaretDown weight="bold" size={14} />;
62+
if (sortBy !== column) {
63+
return <ArrowsDownUp size={14} weight="bold" className="text-gray-500 opacity-70 group-hover:opacity-100 group-hover:text-primary-400 transition-all" />;
64+
}
65+
return sortOrder === 'asc' ? <CaretUp weight="bold" size={14} className="text-primary-400" /> : <CaretDown weight="bold" size={14} className="text-primary-400" />;
6166
};
6267

6368
return (
@@ -71,7 +76,7 @@ const TableView = ({ issuesData = [] }) => {
7176
</div>
7277
<input
7378
type="text"
74-
placeholder="Search issues by title or description..."
79+
placeholder="Search issues by title, description, or epic..."
7580
value={searchQuery}
7681
onChange={(e) => setSearchQuery(e.target.value)}
7782
className="block w-full pl-11 pr-4 py-3 border border-gray-700 rounded-xl leading-5 bg-gray-800/50 text-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500/50 focus:border-primary-500 focus:bg-gray-800 transition-all duration-300 text-sm font-mono"
@@ -89,10 +94,10 @@ const TableView = ({ issuesData = [] }) => {
8994
key={status}
9095
onClick={() => handleFilterChange(status)}
9196
className={`
92-
group relative px-3 py-1.5 rounded-lg text-xs font-mono font-bold transition-all duration-200 border select-none
97+
group relative px-3 py-1.5 rounded-lg text-xs font-mono font-bold uppercase tracking-wider transition-all duration-200 select-none
9398
${activeFilters.includes(status)
94-
? `${getStatusClasses(status).split(' ')[0]} ${getStatusClasses(status).split(' ')[1]} ${statusTextColor(status)} shadow-md ring-1 ring-white/10`
95-
: 'bg-gray-800/40 border-gray-700 text-gray-500 hover:border-gray-600 hover:bg-gray-800 hover:text-gray-300'
99+
? `${getStatusClasses(status)} shadow-md ring-1 ring-white/10`
100+
: 'bg-gray-800/40 border border-gray-700 text-gray-500 hover:border-gray-600 hover:bg-gray-800 hover:text-gray-300'
96101
}
97102
`}
98103
>
@@ -114,6 +119,7 @@ const TableView = ({ issuesData = [] }) => {
114119
<tr className="bg-gray-800/60">
115120
{[
116121
{ key: 'title', label: 'Title' },
122+
{ key: 'epic', label: 'Epic' },
117123
{ key: 'description', label: 'Description', noSort: true },
118124
{ key: 'status', label: 'Status' },
119125
{ key: 'priority', label: 'Priority' },
@@ -125,7 +131,7 @@ const TableView = ({ issuesData = [] }) => {
125131
scope="col"
126132
onClick={() => !col.noSort && handleSort(col.key)}
127133
className={`
128-
px-6 py-4 text-left text-xs font-mono font-bold text-gray-400 uppercase tracking-wider
134+
px-6 py-4 text-left text-xs font-mono font-bold text-gray-400 uppercase tracking-wider group
129135
${!col.noSort ? 'cursor-pointer hover:text-primary-400 hover:bg-gray-800/50 transition-colors select-none' : ''}
130136
`}
131137
>
@@ -159,21 +165,26 @@ const TableView = ({ issuesData = [] }) => {
159165
{app.title}
160166
</Link>
161167
</td>
168+
<td className="px-6 py-4 whitespace-nowrap">
169+
{app.epic ? (
170+
<span className="inline-flex items-center gap-1.5 px-2 py-1 rounded bg-purple-500/10 border border-purple-500/30 text-purple-300 text-[10px] font-mono uppercase tracking-wider font-bold">
171+
<Lightning weight="fill" size={10} />
172+
{app.epic}
173+
</span>
174+
) : (
175+
<span className="text-gray-600 font-mono text-xs">-</span>
176+
)}
177+
</td>
162178
<td className="px-6 py-4 text-sm text-gray-400 font-mono max-w-xs truncate" title={app.description}>
163179
{app.description}
164180
</td>
165181
<td className="px-6 py-4 whitespace-nowrap">
166-
<span className={`px-2.5 py-1 inline-flex items-center text-[10px] font-mono font-bold uppercase tracking-wide rounded-full border ${getStatusClasses(app.status)} ${statusTextColor(app.status)} shadow-sm`}>
182+
<span className={`px-2.5 py-1 inline-flex items-center text-[10px] font-mono font-bold uppercase tracking-wide rounded-full ${getStatusClasses(app.status)} shadow-sm`}>
167183
{app.status || 'Planned'}
168184
</span>
169185
</td>
170186
<td className="px-6 py-4 whitespace-nowrap">
171-
<span className={`flex items-center gap-2 text-xs font-mono font-bold ${getPriorityClasses(app.priority).split(' ')[0]}`}>
172-
<span className={`w-2 h-2 rounded-full ${
173-
app.priority === 'High' ? 'bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.6)]' :
174-
app.priority === 'Medium' ? 'bg-yellow-500 shadow-[0_0_8px_rgba(234,179,8,0.6)]' :
175-
'bg-green-500 shadow-[0_0_8px_rgba(34,197,94,0.6)]'
176-
}`}></span>
187+
<span className={`inline-flex items-center gap-1.5 px-2 py-1 rounded text-[10px] font-mono font-bold uppercase tracking-wide ${getPriorityClasses(app.priority)}`}>
177188
{app.priority || 'Low'}
178189
</span>
179190
</td>
@@ -187,7 +198,7 @@ const TableView = ({ issuesData = [] }) => {
187198
))
188199
) : (
189200
<tr>
190-
<td colSpan="6" className="px-6 py-16 text-center text-gray-500 font-mono">
201+
<td colSpan="7" className="px-6 py-16 text-center text-gray-500 font-mono">
191202
<div className="flex flex-col items-center justify-center gap-4">
192203
<div className="p-4 rounded-full bg-gray-800/50">
193204
<MagnifyingGlass size={32} className="opacity-50" />

0 commit comments

Comments
 (0)