diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..79d38c5 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +PUBLIC_GA_ID= \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebeda96..514f6e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: pull_request: - branches: [main] + branches: [main, develop] jobs: build: diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5b7325b..e0db204 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,7 +2,7 @@ name: Deploy to GitHub Pages on: push: - branches: [ main ] + branches: [main] workflow_dispatch: permissions: @@ -11,7 +11,7 @@ permissions: id-token: write concurrency: - group: "pages" + group: 'pages' cancel-in-progress: false jobs: @@ -20,18 +20,18 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - + - name: Setup Node uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' - + - name: Install dependencies run: npm install - + - name: Build with Astro run: npm run build - + - name: Upload artifact if: github.event_name != 'pull_request' uses: actions/upload-pages-artifact@v3 diff --git a/.gitignore b/.gitignore index c025635..72e6304 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,6 @@ dist/ .DS_Store # vscode settings -.vscode/ \ No newline at end of file +.vscode/ + +*.local diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e6f3387 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,215 @@ +# AGENTS.md + +This document provides a detailed guide for agents interacting with this codebase, which is built on the Astro framework. Follow these standards to ensure consistency and maintainability. For further details on Astro, refer to the [official documentation](https://docs.astro.build/). + +--- + +## 1. Build, Lint, and Test Commands + +### Build Commands + +- **Development Server**: + + ```bash + pnpm dev + ``` + + Use this command to spin up a development server. It includes live-reloading. + +- **Build for Production**: + + ```bash + pnpm build + ``` + + This compiles the codebase into optimized production-ready files under the `dist/` directory. + +- **Preview Production Build**: + ```bash + pnpm preview + ``` + This command serves the production build locally for testing. + +### Linting and Formatting + +- **Run Prettier**: + ```bash + pnpm format + ``` + This formats all code under the `src` folder according to the Prettier settings. + +### Testing Commands + +(Note: No testing framework is currently integrated. Update this section if added.) + +To simulate the test command: + +```bash +pnpm test +``` + +Currently, this outputs `Error: no test specified`. + +For individual test setups, the framework used (e.g. Jest, Vitest) will define the process. + +--- + +## 2. Code Style Guidelines + +### General Formatting Rules + +This codebase uses **Prettier** for consistent formatting. Key settings include: + +- **Tab Width**: 2 spaces +- **Line Width**: 110 characters max +- **Semicolons**: Disabled +- **Quotes**: Single quotes preferred (`'example'`, not `"example"`) +- **Plugins**: Uses `prettier-plugin-astro` for `.astro` files. + +Run the formatter before committing code: + +```bash +pnpm format +``` + +### Import Conventions + +1. Place **external imports** above internal ones: + +```typescript +import { useState } from 'react' +import utils from '@/lib/utils' +``` + +2. **Do not use wildcard imports** (e.g., `import * as fs`). +3. Maintain alphabetical order where possible. + +### Code Organization + +1. Use TypeScript for all new files (`.ts`, `.tsx`). +2. Follow the directory structure: + - Components in `src/components` + - Pages in `src/pages` + - Utilities in `src/lib` + +### Naming Conventions + +#### Files/Folders + +- Use `kebab-case` for filenames (`example-file.ts`). +- Directories reflect their contents (`components`, `utils`). + +#### Variables and Functions + +Use `camelCase` for variables and methods: + +```javascript +const fetchData = () => {} +``` + +#### Types + +- Interface names should use `PascalCase`: + +```typescript +interface User { + id: string + name: string +} +``` + +### Error Handling + +1. Always check for edge cases in asynchronous operations: + +```typescript +try { + const response = await fetch('/api/data') + const data = response.json() +} catch (error) { + console.error('Error fetching data:', error) +} +``` + +2. Avoid silent failures. Log or handle errors appropriately. + +--- + +## 3. Guidelines for Agents + +Agents (like Copilot) must adhere to these coding standards to ensure consistency. + +1. **Pre-Execution** + - Ensure Prettier is configured. Adjust any settings, such as overriding `tabWidth` or `printWidth`, to align with this repository. + - Validate TypeScript definitions before proceeding. + +2. **During Execution** + - When generating test files, suggest using Jest or Vitest (if no tests are found). + - For updates, refactor to use modular imports and maintain concise separation of logic. + - **Follow SEO and i18n guidelines** defined in section 4 when creating or modifying pages. + +3. **Post-Execution** + - Always include a test or linting step before suggesting commits. + - Suggest meaningful commit messages, such as: + ```bash + chore: format code with Prettier + ``` + +--- + +## 4. Accessibility (a11y) Guidelines + +All new UI components and pages must be built with accessibility in mind from the start. Agents must prioritize the following core principles: + +### 1. Semantic HTML & Structure +- **Use HTML5 elements:** Prioritize `
`, ` + + + + + + + + + + + + + + + + diff --git a/src/layouts/components/Header/components/ResponsiveToggle.astro b/src/layouts/components/Header/components/ResponsiveToggle.astro new file mode 100644 index 0000000..58517a8 --- /dev/null +++ b/src/layouts/components/Header/components/ResponsiveToggle.astro @@ -0,0 +1,119 @@ +--- +/** + * ResponsiveToggle Component + * + * @description A toggle button for mobile navigation with full accessibility support + * Based on accessible-astro-starter patterns + */ +interface Props { + /** + * Additional classes to apply to the ResponsiveToggle + */ + class?: string +} + +const { class: className } = Astro.props +--- + + + + + + diff --git a/src/pages/[lang]/accommodation.astro b/src/pages/[lang]/accommodation.astro new file mode 100644 index 0000000..6d745ba --- /dev/null +++ b/src/pages/[lang]/accommodation.astro @@ -0,0 +1,36 @@ +--- +import Layout from '../../layouts/Layout.astro' +import AccommodationPage from '../../components/AccommodationPage.astro' + +export function getStaticPaths() { + return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] +} + +const { lang } = Astro.params + +const titles = { + es: 'Dónde alojarse | PyConES 2026', + en: 'Where to stay | PyConES 2026', + ca: 'On allotjar-se | PyConES 2026', +} + +const title = titles[(lang || 'es') as keyof typeof titles] +--- + + +
+
+ +
+
+
+ + diff --git a/src/pages/[lang]/code-of-conduct.astro b/src/pages/[lang]/code-of-conduct.astro new file mode 100644 index 0000000..b1ecb84 --- /dev/null +++ b/src/pages/[lang]/code-of-conduct.astro @@ -0,0 +1,276 @@ +--- +import Layout from '../../layouts/Layout.astro' +import { texts } from '../../i18n/code-of-conduct' + +export function getStaticPaths() { + return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] +} + +const { lang } = Astro.params + +const t = texts[(lang || 'es') as keyof typeof texts] + +const { + title, + heading, + intro, + commitment, + detailIntro, + why, + scope, + standards, + enforcement, + reporting, + attribution, +} = t +--- + + +
+ +
+

+ {heading} +

+
+
+
+ + +
+
+

+ {intro} +

+

+ {commitment} +

+

+ {detailIntro} +

+
+
+ + +
+

+ + {why.title} +

+

+ {why.intro} +

+
    + { + why.reasons.map((reason) => ( +
  • +
  • + )) + } +
+
+ + +
+

+ + {scope.title} +

+
+

+ {scope.body} +

+
+
+ + +
+

+ + {standards.title} +

+ + +
+

+ + {standards.positiveTitle} +

+
+
    + { + standards.positiveItems.map((item) => ( +
  • +
  • + )) + } +
+
+
+ + +
+

+ + {standards.negativeTitle} +

+
+
    + { + standards.negativeItems.map((item) => ( +
  • +
  • + )) + } +
+
+
+ + +
+

+ + {standards.harassmentNote} +

+
+
+ + +
+

+ + {enforcement.title} +

+
+

+ {enforcement.body} +

+
+
+ + +
+

+ + {reporting.title} +

+

+ {reporting.intro} +

+
+ { + reporting.channels.map((channel, index) => ( +
+ + {index + 1} + +

+ {channel} +

+
+ )) + } +
+
+

+ + {reporting.privacy} +

+
+
+ + +
+

+ + {attribution.title} +

+

+ {attribution.intro} +

+
    + { + attribution.sources.map((source) => ( +
  • +
  • + )) + } +
+
+
+
diff --git a/src/pages/[lang]/index.astro b/src/pages/[lang]/index.astro index 71ac21b..337c112 100644 --- a/src/pages/[lang]/index.astro +++ b/src/pages/[lang]/index.astro @@ -1,5 +1,5 @@ --- -import IndexPage from '../../components/index.astro' +import IndexPage from '@/components/index.astro' export function getStaticPaths() { return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] diff --git a/src/pages/[lang]/location.astro b/src/pages/[lang]/location.astro new file mode 100644 index 0000000..f384090 --- /dev/null +++ b/src/pages/[lang]/location.astro @@ -0,0 +1,28 @@ +--- +import Layout from '../../layouts/Layout.astro' +import LocationPage from '../../components/LocationPage.astro' + +export function getStaticPaths() { + return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] +} + +const { lang } = Astro.params + +const titles = { + es: 'Localización | PyConES 2026', + en: 'Location | PyConES 2026', + ca: 'Localització | PyConES 2026', +} + +const title = titles[(lang || 'es') as keyof typeof titles] +--- + + +
+
+ +
+
+
+ + diff --git a/src/pages/[lang]/sponsors.astro b/src/pages/[lang]/sponsors.astro index c35857e..97d8384 100644 --- a/src/pages/[lang]/sponsors.astro +++ b/src/pages/[lang]/sponsors.astro @@ -1,7 +1,7 @@ --- -import Layout from '../../layouts/Layout.astro' -import { SPONSORS_EMAIL } from '../constants' -import { texts } from '../../i18n/sponsors' +import Layout from '@/layouts/Layout.astro' +import { SPONSORS_EMAIL } from '@/constants.ts' +import { texts } from '@/i18n/sponsors' export function getStaticPaths() { return [{ params: { lang: 'es' } }, { params: { lang: 'en' } }, { params: { lang: 'ca' } }] @@ -26,7 +26,6 @@ const { benefitDetails, addons, pythonSpainPoints, - socialLinks, tiers, testimonials, interests, @@ -37,8 +36,8 @@ const { --- -
-
+
+
PyconES 2026 @@ -52,19 +51,19 @@ const {
-
+

{about.title}

-

{about.body}

+

{about.body}

-
+

{stats.title}

{ - stats.items.map((stat) => ( + stats.items.map((stat: { icon: string; value: string; label: string }) => (
-
+

{location.title}

@@ -171,35 +170,35 @@ const {

{audience.title}

-

{audience.seniority}

+

{audience.seniority}

-
+
JUNIOR 38%
-
+
SENIOR / PRO 57%
@@ -215,7 +214,7 @@ const {
{ - audience.items.map((item) => ( + audience.items.map((item: { icon: string; value: string; label: string }) => (
-

{interests.title}

+

{interests.title}

{ (() => { const colors = ['#ff8200', '#fca09c', '#ffc72c', '#fff1ca;', '#ffdfbf', '#fa716b', '#fb923c'] return ( <>
- {interests.items.map((interest, i) => ( -
- - ))} + {interests.items.map( + (interest: { pc: string; label: string; emoji: string }, i: number) => ( +
+ + ), + )}
) @@ -269,11 +272,11 @@ const {
-
+

{testimonials.title}

{ - testimonials.items.map((t) => ( + testimonials.items.map((t: { quote: string; name: string; role: string; photo: string }) => (
{ - pastSponsors.items.map((sponsor) => ( + pastSponsors.items.map((sponsor: { logo: string; name: string }) => (
{sponsor.name}
@@ -331,7 +334,7 @@ const {

{collaborators.title}

{ - collaborators.items.map((collab) => ( + collaborators.items.map((collab: { logo: string; name: string }) => (
{collab.name}
@@ -341,42 +344,44 @@ const {
-
+

{tiers.title}

- +
{ - tiers.items.map((t) => ( - - )) + tiers.items.map( + (t: { name: string; price: string; limit: string; emoji: string; color: string }) => ( + + ), + ) } @@ -402,13 +407,13 @@ const { > {row.label} - {row.data.map((val) => ( + {row.data.map((val: string) => (
{tiers.column1} - - - - - - + + + + + +
@@ -442,7 +447,7 @@ const {

{benefitDetails.title}

{ - benefitDetails.items.map((detail) => ( + benefitDetails.items.map((detail: { title: string; desc: string }) => (

{detail.title}

{detail.desc}

@@ -457,7 +462,7 @@ const {

Add-ons

{ - addons.map((addon) => ( + addons.map((addon: { name: string; price: string; desc: string; available: string }) => (
{addon.name}
@@ -480,7 +485,7 @@ const {

{ - pythonSpainPoints.items.map((point) => ( + pythonSpainPoints.items.map((point: { icon: string; title: string; desc: string }) => (
- - -
-

{socialLinks.title}

-
- { - socialLinks.items.map((link) => ( - - {link.icon} - {link.label} - - )) - } -
-
diff --git a/src/pages/index.astro b/src/pages/index.astro index aa37d48..04a1b5c 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,6 +1,6 @@ --- import { i18n } from 'astro:config/client' -import IndexPage from '../components/index.astro' +import IndexPage from '@/components/index.astro' const locales = i18n.locales const defaultLocale = i18n.defaultLocale diff --git a/src/style/global.css b/src/style/global.css index 94d8cbe..0f0cc2a 100644 --- a/src/style/global.css +++ b/src/style/global.css @@ -1,23 +1,28 @@ @import 'tailwindcss'; +html { + scroll-behavior: smooth; + scroll-padding-top: 6rem; + /* Adjust based on your header height */ +} + @theme { /* Fonts */ - --font-mono: 'JetBrains Mono Variable', monospace; --font-outfit: 'Outfit Variable', sans-serif; - --font-size-xs: 0.875rem; - --font-size-sm: 1rem; - --font-size-base: 1.125rem; - --font-size-lg: 1.25rem; - --font-size-xl: 1.5rem; - --font-size-2xl: 1.875rem; - --font-size-3xl: 2.25rem; - --font-size-4xl: 2.625rem; - --font-size-5xl: 3rem; - --font-size-6xl: 3.375rem; - --font-size-7xl: 3.75rem; - --font-size-8xl: 4.5rem; - --font-size-9xl: 6rem; + --font-size-xs: 1rem; + --font-size-sm: 1.125rem; + --font-size-base: 1.25rem; + --font-size-lg: 1.5rem; + --font-size-xl: 1.875rem; + --font-size-2xl: 2.25rem; + --font-size-3xl: 2.625rem; + --font-size-4xl: 3rem; + --font-size-5xl: 3.375rem; + --font-size-6xl: 3.75rem; + --font-size-7xl: 4.5rem; + --font-size-8xl: 6rem; + --font-size-9xl: 8rem; /* Font Weights */ --font-weight-thin: 100; @@ -49,9 +54,62 @@ --color-pycon-red-50: #fca09c; --color-pycon-red-25: #fdcfcd; + --color-pycon-mute: #cc6600; + --color-pycon-mute-100: #cc6600; + + --color-pycon-gray: #4a4a48; + --color-pycon-gray-100: #4a4a48; + --color-pycon-black: #1d1d1b; --color-pycon-black-100: #1d1d1b; --color-pycon-black-75: #555554; --color-pycon-black-50: #8e8e8d; --color-pycon-black-25: #c6c6c6; + + --color-pycon-white: #ffffff; + + /*DS colors*/ + --color-pantone-151c: var(--color-pycon-orange-100); + --color-pantone-123c: var(--color-pycon-yellow-100); + --color-pantone-warm-red: var(--color-pycon-red-100); + --color-pantone-black-c: var(--color-pycon-black-100); + --color-pantone-yellow-100: var(--color-pycon-yellow); + --color-pantone-yellow-75: var(--color-pycon-yellow-75); + --color-pantone-yellow-50: var(--color-pycon-yellow-50); + --color-pantone-yellow-25: var(--color-pycon-yellow-25); + --color-pantone-warm-red-100: var(--color-pycon-red); + --color-pantone-warm-red-75: var(--color-pycon-red-75); + --color-pantone-warm-red-50: var(--color-pycon-red-50); + --color-pantone-warm-red-25: var(--color-pycon-red-25); + + --color-tier-main: var(--color-pycon-yellow); + --color-contrast-tier-main: #1d1d1b; + + --color-tier-platinum: var(--color-pycon-orange); + --color-contrast-tier-platinum: #ffffff; + + --color-tier-gold: var(--color-pycon-red); + --color-contrast-tier-gold: #ffffff; + + --color-tier-silver: var(--color-pycon-mute); + --color-contrast-tier-silver: #ffffff; + + --color-tier-bronze: var(--color-pycon-gray); + --color-contrast-tier-bronze: #ffffff; +} + +@layer base { + :root { + --bg-color: #1d1d1b; + --text-color: #ffffff; + --bg-symbol: url('/images/symbol-black-dark.svg'); + color-scheme: dark; + } + + :root.light { + --bg-color: #ffffff; + --text-color: #1d1d1b; + --bg-symbol: url('/images/symbol-black-light.svg'); + color-scheme: light; + } } diff --git a/src/types/sponsors.ts b/src/types/sponsors.ts new file mode 100644 index 0000000..364c819 --- /dev/null +++ b/src/types/sponsors.ts @@ -0,0 +1,9 @@ +export type TSponsorTier = 'bronze' | 'silver' | 'gold' | 'platinum' | 'main' + +export interface ISponsor { + name: string + website: string + tier: TSponsorTier + logobg: string + logo: string +} diff --git a/tsconfig.json b/tsconfig.json index e11a86f..2e66b49 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,10 @@ { "extends": "astro/tsconfigs/base", - "include": ["src/**/*"] + "include": ["src/**/*"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } }