Skip to content

Commit 545bdb1

Browse files
authored
feat: apply transparency layout to /about, /join-us, and /contact (#255)
1 parent 4f4aba6 commit 545bdb1

31 files changed

Lines changed: 1764 additions & 571 deletions

.opencode/agent/code-reviewer.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Review all code changes for correctness, standards compliance, and quality. You
2626
- Check for deprecated API usage.
2727
- Verify error handling follows project conventions.
2828
- Ensure code follows the project's structure and naming conventions.
29+
- Flag any hardcoded text strings in `.astro` templates — all user-facing strings must use the i18n system (`t()`). This is a blocking issue.
30+
- Verify new translation keys are properly registered in `src/i18n/ui.ts`.
2931

3032
## Output Format
3133

.opencode/agent/frontend-engineer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ Implement the user-facing parts of the application — interfaces, presentation
2525
- Build output formatting and display logic.
2626
- Handle user input validation and feedback.
2727
- Ensure consistent user experience across the application.
28+
- Use the project's i18n system (`useTranslations`, `t()`) for ALL user-facing text.
29+
- Place new translation keys in `src/i18n/ui.ts` under the appropriate page namespace.
30+
- Never hardcode Portuguese or any language strings in templates.
2831

2932
## Guidelines
3033

3134
- Study existing code patterns before writing new code.
3235
- Follow the project's established conventions and style.
3336
- Keep interface logic thin — delegate business logic to internal modules.
37+
- Load the `astro-i18n` skill before writing any `.astro` file.
38+
- Before writing a new page, first check `src/i18n/ui.ts` for existing keys that match the content you need.
3439
- Validate and verify your changes build and pass tests before reporting done.

.opencode/learnings/registry.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ All captured learnings from the AI Diamond Chain are registered here.
1515

1616
```markdown
1717
## [Date] - [Learning Title]
18+
1819
- **Type:** skill/agent/workflow/reference
1920
- **Source:** Which diamond/event produced this
2021
- **Summary:** 1-2 sentence description
@@ -25,6 +26,7 @@ All captured learnings from the AI Diamond Chain are registered here.
2526
---
2627

2728
## 2026-04-17 - Continuous Learning System
29+
2830
- **Type:** skill
2931
- **Source:** User request to create learning rules
3032
- **Summary:** Created continuous-learning skill and supporting docs to ensure all learnings are captured, condensed for reuse, and documented for long-term reference
@@ -34,6 +36,7 @@ All captured learnings from the AI Diamond Chain are registered here.
3436
---
3537

3638
## 2026-04-17 - Tmux Automation Skill
39+
3740
- **Type:** skill
3841
- **Source:** User request for tmux skill for detached session control
3942
- **Summary:** Created tmux-automation skill with commands for creating detached sessions, sending keys programmatically, capturing output, and session management
@@ -43,8 +46,19 @@ All captured learnings from the AI Diamond Chain are registered here.
4346
---
4447

4548
## 2026-04-18 - DaisyUI v5 Custom Theme Configuration
49+
4650
- **Type:** skill
4751
- **Source:** Implementation Diamond - Custom theme creation for PodCodar brand
4852
- **Summary:** Learned DaisyUI v5's new `@plugin "daisyui/theme"` syntax with OKLCH color format, created light/dark theme pair with PodCodar brand colors (tech blues + warm amber accents), disabled default themes for clean implementation
4953
- **Location:** `.opencode/skills/daisyui-v5-themes/SKILL.md`, `src/styles/global.css`
50-
- **Confidence:** 🟢 High
54+
- **Confidence:** 🟢 High
55+
56+
---
57+
58+
## 2026-04-26 - i18n Text Convention: No Hardcoded Strings
59+
60+
- **Type:** skill/agent/workflow
61+
- **Source:** Refactoring transparency layout to /about, /join-us, /contact — discovered massive duplication of hardcoded strings across pages
62+
- **Summary:** Established mandatory convention: ALL user-visible text in `.astro` templates must use the i18n system (`t()`). Updated `astro-i18n` skill with text convention rule, updated `frontend-engineer` and `code-reviewer` agents to enforce it, and documented in `AGENTS.md`. Data-driven content from `src/data/*.ts` files (member names, metric values, etc.) is exempted.
63+
- **Location:** `.opencode/skills/astro-i18n/SKILL.md`, `.opencode/agent/frontend-engineer.md`, `.opencode/agent/code-reviewer.md`, `AGENTS.md`
64+
- **Confidence:** 🟢 High

.opencode/skills/astro-i18n/SKILL.md

Lines changed: 98 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ compatibility: opencode
1212
## Quick Start
1313

1414
### 1. Configure astro.config.mjs
15+
1516
```js
1617
i18n: {
1718
locales: ['pt-br', 'en'],
@@ -23,12 +24,14 @@ i18n: {
2324
```
2425

2526
### 2. Create Translation Files
27+
2628
```
2729
src/i18n/ui.ts # Translation strings
2830
src/i18n/utils.ts # Helper functions
2931
```
3032

3133
### 3. Organize Pages
34+
3235
```
3336
src/pages/
3437
├── index.astro # default locale (pt-br)
@@ -46,53 +49,57 @@ src/pages/
4649
## Core Concepts
4750

4851
### Locale Detection Priority
52+
4953
1. **Cookie** (user selected) - highest priority
5054
2. **Browser Accept-Language header** - middleware (SSR required)
5155
3. **Default locale** - fallback
5256

5357
### URL Structure
58+
5459
| prefixDefaultLocale | default locale URL | other locale URL |
55-
|---------------------|-------------------|-----------------|
56-
| false | `/` | `/en/` |
57-
| true | `/pt-br/` | `/en/` |
60+
| ------------------- | ------------------ | ---------------- |
61+
| false | `/` | `/en/` |
62+
| true | `/pt-br/` | `/en/` |
5863

5964
---
6065

6166
## File Reference
6267

6368
### src/i18n/ui.ts
69+
6470
```typescript
6571
export const languages = {
66-
en: 'English',
67-
'pt-br': 'Português (Brasil)',
72+
en: "English",
73+
"pt-br": "Português (Brasil)",
6874
} as const;
6975

70-
export const defaultLang = 'pt-br';
76+
export const defaultLang = "pt-br";
7177

7278
export const ui = {
7379
en: {
74-
'nav.home': 'Home',
75-
'nav.blog': 'Blog',
76-
'nav.about': 'About',
77-
'nav.contact': 'Contact',
78-
'footer.copyright': 'All rights reserved.',
80+
"nav.home": "Home",
81+
"nav.blog": "Blog",
82+
"nav.about": "About",
83+
"nav.contact": "Contact",
84+
"footer.copyright": "All rights reserved.",
7985
},
80-
'pt-br': {
81-
'nav.home': 'Início',
82-
'nav.blog': 'Blog',
83-
'nav.about': 'Sobre',
84-
'nav.contact': 'Contato',
85-
'footer.copyright': 'Todos os direitos reservados.',
86+
"pt-br": {
87+
"nav.home": "Início",
88+
"nav.blog": "Blog",
89+
"nav.about": "Sobre",
90+
"nav.contact": "Contato",
91+
"footer.copyright": "Todos os direitos reservados.",
8692
},
8793
} as const;
8894
```
8995

9096
### src/i18n/utils.ts
97+
9198
```typescript
92-
import { ui, defaultLang } from './ui';
99+
import { ui, defaultLang } from "./ui";
93100

94101
export function getLangFromUrl(url: URL): keyof typeof ui {
95-
const segments = url.pathname.split('/').filter(Boolean);
102+
const segments = url.pathname.split("/").filter(Boolean);
96103
const firstSegment = segments[0];
97104
if (firstSegment && firstSegment in ui) {
98105
return firstSegment as keyof typeof ui;
@@ -146,6 +153,7 @@ const t = useTranslations(lang);
146153
## Language Picker with Cookie Persistence
147154

148155
### src/components/LanguagePicker.astro
156+
149157
```astro
150158
---
151159
import { getRelativeLocaleUrl } from 'astro:i18n';
@@ -203,15 +211,76 @@ const currentPath = getPathWithoutLocale(pathname, currentLang);
203211

204212
---
205213

214+
## Text Convention (MANDATORY)
215+
216+
ALL user-visible text in `.astro` files MUST use the i18n system. Hardcoded
217+
strings in templates are forbidden.
218+
219+
### Correct
220+
221+
```astro
222+
---
223+
import { getLangFromUrl, useTranslations } from '@/i18n/utils';
224+
const lang = getLangFromUrl(Astro.url);
225+
const t = useTranslations(lang);
226+
---
227+
<HeroSection title={t('about.hero.title')} eyebrow={t('about.hero.eyebrow')} />
228+
<SectionHeader title={t('contact.methods.title')} subtitle={t('contact.methods.subtitle')} />
229+
<p>{t('contributing.donations.body')}</p>
230+
```
231+
232+
### Wrong
233+
234+
```astro
235+
<HeroSection title="Sobre nós" eyebrow="PodCodar" />
236+
<SectionHeader title="Canais de Comunicação" subtitle="Escolha o canal..." />
237+
<p>Se quiser contribuir financeiramente...</p>
238+
```
239+
240+
### Exception
241+
242+
Data-driven content from `src/data/*.ts` files (board member names, metric
243+
values, channel names, project names) is iterable data, not display strings.
244+
These may be used directly:
245+
246+
```astro
247+
<!-- OK — iterated from marketing.ts data -->
248+
{projects.map((project) => <h3>{project.name}</h3>)}
249+
250+
<!-- NOT OK — hardcoded section header -->
251+
<h2>Projetos e repositórios</h2>
252+
<!-- Should be: -->
253+
<h2>{t('about.projects.title')}</h2>
254+
```
255+
256+
### Adding New Keys
257+
258+
When adding a new key to `src/i18n/ui.ts`, follow the namespace pattern:
259+
260+
```
261+
{page}.{section}.{field}
262+
```
263+
264+
Examples:
265+
266+
- `about.hero.eyebrow` — About page, hero section, eyebrow badge
267+
- `joinUs.steps.01.title` — Join Us page, steps section, step 1 title
268+
- `contributing.volunteering.body` — Contributing page, volunteering section, body text
269+
270+
---
271+
206272
## Common Pitfalls
207273

208274
### 1. Hardcoded lang Attribute
275+
209276
**WRONG**:
277+
210278
```html
211-
<html lang="en">
279+
<html lang="en"></html>
212280
```
213281

214282
**CORRECT**:
283+
215284
```astro
216285
---
217286
import { getLangFromUrl } from '../i18n/utils';
@@ -221,12 +290,15 @@ const lang = getLangFromUrl(Astro.url);
221290
```
222291

223292
### 2. Static Links Without getRelativeLocaleUrl
293+
224294
**WRONG**:
295+
225296
```html
226-
<a href="/about">
297+
<a href="/about"></a>
227298
```
228299

229300
**CORRECT**:
301+
230302
```astro
231303
---
232304
import { getRelativeLocaleUrl } from 'astro:i18n';
@@ -236,13 +308,16 @@ const lang = getLangFromUrl(Astro.url);
236308
```
237309

238310
### 3. Wrong Default Locale
311+
239312
**WRONG** (default must be explicitly set):
313+
240314
```js
241315
locales: ['en', 'pt-br'],
242316
defaultLocale: 'en',
243317
```
244318

245319
**CORRECT**:
320+
246321
```js
247322
locales: ['pt-br', 'en'],
248323
defaultLocale: 'pt-br',
@@ -278,6 +353,7 @@ defaultLocale: 'pt-br',
278353
## When Server-Side Redirect is Needed
279354

280355
For server-side redirect based on browser language, add SSR adapter:
356+
281357
1. Install `@astrojs/node`
282358
2. Set `output: 'server'`
283359
3. Create `src/middleware.ts` for server-side detection
@@ -311,4 +387,4 @@ src/
311387
│ └── LanguagePicker.astro
312388
└── layouts/
313389
└── BlogPost.astro
314-
```
390+
```

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ This squad uses 9 specialized agents:
163163
- **Configured in**: `astro.config.ts`
164164
- **Skill available**: `astro-i18n` for adding English support
165165
- Default locale does not use URL prefix (`prefixDefaultLocale: false`)
166+
- **Convention**: ALL user-visible text in `.astro` templates must go through the i18n system (`t()`). Hardcoded strings are not allowed. See the `astro-i18n` skill for the full rule.
167+
- **How**: Import `useTranslations` from `@/i18n/utils`, call `t('key')`. Add keys to `src/i18n/ui.ts` under the relevant page namespace (e.g., `about.hero.title`).
166168

167169
---
168170

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Changelog
2+
3+
## Upcoming Release
4+
5+
- Consistent Layout across pages (#254)
6+
- Mobile-Friendly navbar (#252)

0 commit comments

Comments
 (0)