Skip to content

Commit 4c21cb8

Browse files
committed
Cria área de ações do topico
1 parent d050a4e commit 4c21cb8

20 files changed

+952
-18
lines changed

gaeia-web/astro.config.mjs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@ export default defineConfig({
2020
'import.meta.env.PUBLIC_MODE': JSON.stringify(process.env.PUBLIC_MODE || 'hybrid'),
2121
},
2222
server: {
23+
hmr: {
24+
host: 'localhost',
25+
port: 4322,
26+
},
2327
watch: {
28+
usePolling: true,
29+
interval: 1000,
2430
// Watch parent vault for content changes
25-
ignored: ['!../**/*.md']
26-
}
31+
ignored: ['!../**/*.md'],
32+
},
2733
}
2834
}
2935
});

gaeia-web/docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ services:
55
dockerfile: docker/Dockerfile.dev
66
ports:
77
- "4321:4321"
8+
- "4322:4322"
89
volumes:
910
- .:/app
1011
- /app/node_modules

gaeia-web/src/components/BadgeDisplay.astro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ interface Props {
1313
}
1414
1515
const {
16-
id,
1716
name,
1817
description,
1918
icon,

gaeia-web/src/components/BadgeShelf.astro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const {
2727
} = Astro.props;
2828
2929
const earnedBadges = badges.filter(b => b.earned);
30-
const lockedBadges = badges.filter(b => !b.earned);
3130
3231
const displayBadges = showLocked
3332
? badges
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
---
2+
import type { ExtractedResource, ResourceType } from '../types/trilhas';
3+
4+
interface Props {
5+
resources: ExtractedResource[];
6+
}
7+
8+
const { resources } = Astro.props;
9+
10+
if (resources.length === 0) return;
11+
12+
const typeConfig: Record<ResourceType, { label: string; icon: string; color: string }> = {
13+
youtube: { label: 'Vídeos', icon: '', color: 'cyan' },
14+
arxiv: { label: 'Papers', icon: '📄', color: 'violet' },
15+
github: { label: 'Código', icon: '', color: 'bright' },
16+
documentation: { label: 'Docs', icon: '📖', color: 'emerald' },
17+
interactive: { label: 'Ferramentas', icon: '', color: 'amber' },
18+
article: { label: 'Artigos', icon: '📝', color: 'blue' },
19+
other: { label: 'Outros', icon: '🔗', color: 'dim' },
20+
};
21+
22+
// Only show types that have resources
23+
const activeTypes = (Object.keys(typeConfig) as ResourceType[]).filter(
24+
type => resources.some(r => r.type === type)
25+
);
26+
---
27+
28+
<section class="resource-panel" data-resource-panel>
29+
<div class="resource-panel-header">
30+
<h3 class="resource-panel-title">
31+
<svg class="rp-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
32+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10" />
33+
</svg>
34+
<span>{resources.length} recursos</span>
35+
</h3>
36+
<div class="resource-filters">
37+
<button class="resource-filter active" data-filter="all">Todos</button>
38+
{activeTypes.map(type => (
39+
<button class="resource-filter" data-filter={type} data-color={typeConfig[type].color}>
40+
<span class="filter-icon">{typeConfig[type].icon}</span>
41+
{typeConfig[type].label}
42+
</button>
43+
))}
44+
</div>
45+
</div>
46+
47+
<div class="resource-grid">
48+
{resources.map(resource => (
49+
<a
50+
href={resource.url}
51+
target="_blank"
52+
rel="noopener noreferrer"
53+
class={`resource-card resource-card--${resource.type}`}
54+
data-resource-type={resource.type}
55+
>
56+
<span class="resource-card-icon">{typeConfig[resource.type].icon}</span>
57+
<div class="resource-card-content">
58+
<span class="resource-card-title">{resource.title}</span>
59+
<span class="resource-card-domain">{resource.domain}</span>
60+
</div>
61+
<svg class="resource-card-arrow" fill="none" stroke="currentColor" viewBox="0 0 24 24">
62+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
63+
</svg>
64+
</a>
65+
))}
66+
</div>
67+
</section>
68+
69+
<style>
70+
.resource-panel {
71+
margin-top: 2rem;
72+
border-radius: 12px;
73+
background: rgba(15, 23, 42, 0.5);
74+
backdrop-filter: blur(8px);
75+
-webkit-backdrop-filter: blur(8px);
76+
border: 1px solid rgba(136, 146, 176, 0.15);
77+
overflow: hidden;
78+
}
79+
80+
.resource-panel-header {
81+
padding: 1rem 1.25rem;
82+
border-bottom: 1px solid rgba(136, 146, 176, 0.1);
83+
}
84+
85+
.resource-panel-title {
86+
display: flex;
87+
align-items: center;
88+
gap: 0.5rem;
89+
font-family: 'IBM Plex Sans', sans-serif;
90+
font-size: 0.875rem;
91+
font-weight: 600;
92+
color: var(--text-bright, #e2e8f0);
93+
margin: 0 0 0.75rem 0;
94+
}
95+
96+
.rp-icon {
97+
width: 18px;
98+
height: 18px;
99+
color: var(--synapse-cyan, #00d4ff);
100+
}
101+
102+
.resource-filters {
103+
display: flex;
104+
flex-wrap: wrap;
105+
gap: 0.375rem;
106+
}
107+
108+
.resource-filter {
109+
display: inline-flex;
110+
align-items: center;
111+
gap: 0.25rem;
112+
padding: 0.25rem 0.625rem;
113+
border: 1px solid rgba(136, 146, 176, 0.2);
114+
border-radius: 999px;
115+
background: transparent;
116+
color: var(--text-dim, rgba(136, 146, 176, 0.7));
117+
font-family: 'IBM Plex Sans', sans-serif;
118+
font-size: 0.6875rem;
119+
cursor: pointer;
120+
transition: all 0.2s ease;
121+
}
122+
123+
.resource-filter:hover {
124+
border-color: rgba(0, 212, 255, 0.3);
125+
color: var(--text-bright, #e2e8f0);
126+
}
127+
128+
.resource-filter.active {
129+
background: rgba(0, 212, 255, 0.1);
130+
border-color: rgba(0, 212, 255, 0.3);
131+
color: var(--synapse-cyan, #00d4ff);
132+
}
133+
134+
.filter-icon {
135+
font-size: 0.75rem;
136+
}
137+
138+
.resource-grid {
139+
display: grid;
140+
gap: 1px;
141+
background: rgba(136, 146, 176, 0.08);
142+
}
143+
144+
.resource-card {
145+
display: flex;
146+
align-items: center;
147+
gap: 0.75rem;
148+
padding: 0.75rem 1.25rem;
149+
background: rgba(15, 23, 42, 0.6);
150+
text-decoration: none;
151+
transition: all 0.2s ease;
152+
}
153+
154+
.resource-card:hover {
155+
background: rgba(0, 212, 255, 0.05);
156+
}
157+
158+
.resource-card.hidden {
159+
display: none;
160+
}
161+
162+
.resource-card-icon {
163+
font-size: 1rem;
164+
flex-shrink: 0;
165+
width: 24px;
166+
text-align: center;
167+
}
168+
169+
.resource-card-content {
170+
flex: 1;
171+
min-width: 0;
172+
display: flex;
173+
flex-direction: column;
174+
gap: 0.125rem;
175+
}
176+
177+
.resource-card-title {
178+
font-size: 0.8125rem;
179+
font-weight: 500;
180+
color: var(--text-bright, #e2e8f0);
181+
white-space: nowrap;
182+
overflow: hidden;
183+
text-overflow: ellipsis;
184+
}
185+
186+
.resource-card-domain {
187+
font-family: 'JetBrains Mono', monospace;
188+
font-size: 0.6875rem;
189+
color: var(--text-dim, rgba(136, 146, 176, 0.7));
190+
}
191+
192+
.resource-card-arrow {
193+
width: 14px;
194+
height: 14px;
195+
flex-shrink: 0;
196+
color: var(--text-faint, rgba(136, 146, 176, 0.5));
197+
transition: color 0.2s ease;
198+
}
199+
200+
.resource-card:hover .resource-card-arrow {
201+
color: var(--synapse-cyan, #00d4ff);
202+
}
203+
204+
/* Type-specific hover colors */
205+
.resource-card--youtube:hover { background: rgba(0, 212, 255, 0.06); }
206+
.resource-card--youtube:hover .resource-card-title { color: var(--synapse-cyan, #00d4ff); }
207+
208+
.resource-card--arxiv:hover { background: rgba(139, 92, 246, 0.06); }
209+
.resource-card--arxiv:hover .resource-card-title { color: var(--dendrite-violet, #8b5cf6); }
210+
211+
.resource-card--github:hover .resource-card-title { color: var(--text-bright, #e2e8f0); }
212+
213+
.resource-card--documentation:hover { background: rgba(16, 185, 129, 0.06); }
214+
.resource-card--documentation:hover .resource-card-title { color: #10b981; }
215+
216+
.resource-card--interactive:hover { background: rgba(245, 158, 11, 0.06); }
217+
.resource-card--interactive:hover .resource-card-title { color: var(--axon-amber, #f59e0b); }
218+
219+
.resource-card--article:hover { background: rgba(59, 130, 246, 0.06); }
220+
.resource-card--article:hover .resource-card-title { color: #3b82f6; }
221+
222+
@media (max-width: 640px) {
223+
.resource-panel-header {
224+
padding: 0.75rem 1rem;
225+
}
226+
.resource-card {
227+
padding: 0.625rem 1rem;
228+
}
229+
}
230+
</style>
231+
232+
<script>
233+
function initResourcePanel() {
234+
document.querySelectorAll<HTMLElement>('[data-resource-panel]').forEach(panel => {
235+
const filters = panel.querySelectorAll<HTMLButtonElement>('.resource-filter');
236+
const cards = panel.querySelectorAll<HTMLElement>('.resource-card');
237+
238+
filters.forEach(filter => {
239+
filter.addEventListener('click', () => {
240+
const type = filter.dataset.filter;
241+
242+
// Update active state
243+
filters.forEach(f => f.classList.remove('active'));
244+
filter.classList.add('active');
245+
246+
// Show/hide cards
247+
cards.forEach(card => {
248+
if (type === 'all' || card.dataset.resourceType === type) {
249+
card.classList.remove('hidden');
250+
} else {
251+
card.classList.add('hidden');
252+
}
253+
});
254+
});
255+
});
256+
});
257+
}
258+
259+
initResourcePanel();
260+
document.addEventListener('astro:after-swap', initResourcePanel);
261+
</script>

gaeia-web/src/components/Sidebar.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
import ProgressRing from './ProgressRing.astro';
33
import GaeiaLogo from './GaeiaLogo.astro';
4-
import { getAllTrilhas, getTrilhaTopicoIds, getAllTopicos } from '../utils/trilhas';
4+
import { getAllTrilhas, getAllTopicos } from '../utils/trilhas';
55
import { url } from '../utils/url';
66
77
// Load trilhas for navigation

gaeia-web/src/components/StreakCounter.astro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ interface Props {
99
const {
1010
currentStreak,
1111
longestStreak,
12-
lastActiveDate,
1312
weekActivity = [false, false, false, false, false, false, false]
1413
} = Astro.props;
1514

0 commit comments

Comments
 (0)