diff --git a/README.md b/README.md index e215bc4..974c987 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,173 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# impact.tr -## Getting Started +Next.js 16 + Tailwind 4. SSG, markdown-driven content, self-host (Docker). -First, run the development server: +## Dev / build ```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +npm install +npm run dev # localhost:3000 (we use 3010 in the background) +npm run build # production build +npm run start # serve the production build ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +Docker: -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +```bash +docker compose up -d --build # HOST_PORT=3010 by default +``` -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +## Content workflow (no CMS, yalnızca markdown + git) -## Learn More +Yeni edisyon, yeni yarışma formatı, yeni foto = dosya ekle + commit + push. Site otomatik güncellenir. -To learn more about Next.js, take a look at the following resources: +### Yeni edisyon ekle -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +1. `content/editions/.md` dosyası oluştur. Örnek: + ```md + --- + slug: ankara-hands-on-2026 + competition: hands-on-challenge # hands-on-challenge | ideathon | robo-soccer + name: Hands-On Challenge — Ankara Regional + status: past # past | upcoming | announced + startDate: "2026-06-14" + endDate: "2026-06-15" + city: Ankara + venue: ODTÜ KKM + stats: + teams: 24 + participants: 200 + volunteers: 25 + winners: + - { place: 1, team: "Takım Adı", school: "Okul", members: 4 } + - { place: 2, team: "...", school: "...", members: 3 } + teams: + - { name: "Takım A", school: "Lise X", size: 4 } + - { name: "Takım B", school: "Ü. Y", size: 3 } + partners: + - "Partner 1" + testimonials: + - { by: "İsim", org: "Kurum", quote: "..." } + summary: "Tek cümlelik özet, kart & meta yerlerinde görünür." + --- + Serbest metin (markdown). `##`, `###`, listeler, bağlantılar. + ``` -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +2. Foto klasörü oluştur (opsiyonel): `public/photos//01.jpg` … `NN.jpg`. + Şu an otomatik galeri **sadece** `cemberlitas-hands-on-2026` için bağlı — yeni edisyonları otomatik çekmesi için tek satırlık helper gerekiyor (aşağıda TODO). -## Deploy on Vercel +3. Commit + push → SSG yeniden üretir, anasayfadaki "Edisyonlar" grid'i ve toplam metrikler (`stats` varsa) otomatik güncellenir. -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +### Yeni yarışma formatı -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +`content/competitions/.md`: +```md +--- +slug: archeology-hackathon +name: Archeology Hackathon Challenge +short: Kültürel miras hackathonu +tagline: "Bir cümle hook." +format: "Kısa açıklama." +durationDays: 2 +ageGroups: [Lise, Üniversite] +categories: [Veri, Görüntü işleme] +color: brand # brand | accent | pink +order: 4 +--- +Markdown body. +``` + +Sonra `src/components/Nav.tsx`'a bir link daha ekle; ve `src/lib/content.ts`'te `CompetitionSlug` union type'ına yeni slug'ı ekle. + +### Yeni yorum / review + +`src/lib/reviews.ts` içindeki `reviews` dizisine ekle: +```ts +{ + quote: "...", + by: "İsim", + org: "Kurum", + edition: "Çemberlitaş 2026", +} +``` + +Edition-specific testimonial'lar için o edisyonun `.md` dosyasındaki `testimonials` alanını kullan — edisyon detay sayfasında görünür. + +### Foto ekle + +- Yeni foto: `public/photos//.jpg`. 1600px genişlik civarı, JPG quality ~78 öneri. +- Çoklu indirme için Drive linki varsa: + ```bash + /tmp/gdown-venv/bin/gdown --folder "" -O public/photos/ + # sonra Pillow ile 1600px'e küçült (script örneği geliştirilebilir) + ``` + +## Pending / TODO + +Kod seviyesinde hazır olup **veri bekleyen** şeyler: + +- [ ] **Ataköy edisyonu** — tarih (`startDate`/`endDate`) doğrulanmalı. Şu an `2025-12-20/21` tahmin. Takım listesi + kazananlar eklenmeli. +- [ ] **Çemberlitaş Hands-On 2026** — 16 takımın tam listesi (okul + kişi) `teams` alanına girilmeli. Tüm podium (2. ve 3.) girilmeli. +- [ ] **Çemberlitaş Ideathon 2025** — stats (katılımcı/takım sayısı), kazananlar, varsa foto klasörü. +- [ ] **Robo Soccer** — resmi isim kesinleşirse (`Robo Soccer` mı `Impact Robo Soccer` mı), tarih/mekan netleşince `istanbul-robo-soccer.md` ve `ankara-robo-soccer.md` güncellenmeli. Başvuru Google Forms URL'si ekle → yarışma sayfasına embed. +- [ ] **Ataköy foto klasörü** — Drive'da `1JzYEOfWaT6oTSDgycG0GCg-rXrlZRK5K` çekilemedi (sadece boş alt klasörler indirdi). Manuel indirip `public/photos/atakoy-hands-on/` altına kopyalanmalı. +- [ ] **Ek testimonials** — şu an yalnızca M. Buğrahan Kılıç'ın yorumu var. Katılımcı/gönüllü yorumları toplanmalı. +- [ ] **Diğer etkinlikler (LinkedIn'den çıkan)** — ZAĞANOS International STEM Expo, ZAĞANOS Case Study Challenge, Archeology Hackathon Challenge, Arduino workshops. Bunların hangisi ayrı bir format mı, hangisi tek seferlik mi karar ver; `content/competitions/` veya `content/editions/` altına uygun şekilde eklenmeli. + +Kod seviyesinde **yapılacaklar**: + +- [ ] Otomatik edisyon galerisi: `public/photos//` klasörü varsa edisyon detay sayfasına otomatik `` düşsün. Şu an sadece `cemberlitas-hands-on-2026` için hardcoded. `src/lib/photos.ts` gibi bir helper: `getEditionPhotos(slug)` → `fs.readdirSync` ile otomatik. +- [ ] **OG image** (`src/app/opengraph-image.tsx`) — WhatsApp/Slack/Twitter link preview için. +- [ ] **sitemap.xml** ve **robots.txt** (`src/app/sitemap.ts`, `src/app/robots.ts`). +- [ ] **Google Forms embed** Robo Soccer başvuru için. Form URL'si geldiğinde `/yarismalar/robo-soccer/basvuru` route'u ya da yarışma sayfasına iframe blok. +- [ ] **Yorum gönderme** — şu an `mailto:` linki. İleride bir Google Forms ile Sheets'e düşsün; yeni yorumları elden `reviews.ts`'ye taşıma akışı. +- [ ] **"Önceki etkinlikler" arşiv sayfası** — `/edisyonlar` index'i henüz yok; ana sayfadan 6 kart görünüyor. Tüm edisyonları listeleyen bir sayfa eklenmeli. +- [ ] **Gerçek logo** — şu an "i" harfi violet blok. IG'deki "impact" wordmark SVG'ye çevirilip `public/logo.svg` + `Logo.tsx` güncellenmeli. +- [ ] **Foto optimizasyonu** — şu an 1600px JPG. Next Image zaten optimize ediyor ama AVIF/WebP export eklenebilir. +- [ ] **E-posta rate-limiting / iletişim formu** — mailto iyi ama spam gelirse form'a taşıyabiliriz. + +## Deploy + +Self-host Docker Compose. Üretim adımları: + +```bash +# Reverse proxy (caddy/nginx) impact.tr → 127.0.0.1:3010 +docker compose up -d --build +docker compose logs -f web +``` + +Reverse proxy örneği (Caddy): +```caddy +impact.tr { + reverse_proxy 127.0.0.1:3010 +} +``` + +## Yapı + +``` +content/ + competitions/*.md # yarışma formatları + editions/*.md # edisyonlar (metrik, kazanan, takım, testimonial) +public/ + photos//*.jpg # edisyon/format fotoğrafları +src/ + app/ # App Router sayfaları + page.tsx # anasayfa + yarismalar/[slug]/ # yarışma detay + edisyonlar/[slug]/ # edisyon detay + sponsor/, hakkimizda/, iletisim/ + components/ # Nav, Footer, Section, PageHero, Gallery, PhotoStrip, ... + lib/ + content.ts # markdown loader, helpers + contact.ts # iletişim, ekip, değerler, SDG (tek kaynak) + reviews.ts # yorumlar + foto index +``` + +## İletişim + +- Site: [impact.tr](https://impact.tr) +- E-posta: contact@impact.tr · info@impact.tr · hello@impact.tr +- Ekip: tarik@ · tuna@ · yigit@ impact.tr +- Instagram: [@impact.tr](https://www.instagram.com/impact.tr/) +- LinkedIn: [impactcommunit](https://www.linkedin.com/company/impactcommunit/) diff --git a/content/competitions/hands-on-challenge.md b/content/competitions/hands-on-challenge.md new file mode 100644 index 0000000..2c44031 --- /dev/null +++ b/content/competitions/hands-on-challenge.md @@ -0,0 +1,33 @@ +--- +slug: hands-on-challenge +name: Hands-On Challenge +short: Robotik yarışması +tagline: "ESP32 ile takım bazlı, non-stop robotik üretim maratonu." +format: "1-2 gün boyunca takımlar; mekanik tasarım, elektronik ve yazılımı birleştirerek göreve özel robotlar geliştirir ve sahada yarıştırır." +durationDays: 2 +ageGroups: + - Lise + - Üniversite +categories: + - Robotik tasarım + - Gömülü yazılım + - Mekatronik +color: brand +icon: robot +order: 1 +--- + +## Format + +Hands-On Challenge, Impact'in amiral yarışmasıdır. Takımlar belirlenen göreve ilişkin bir robotu tasarlar, kod yazar, sahada jüri karşısında test eder. + +- **Süre:** 1-2 gün non-stop üretim +- **Takım:** 3-5 kişi +- **Platform:** ESP32 odaklı açık platform +- **Puanlama:** Görev performansı + jüri değerlendirmesi + +## Neden farklı + +- Türkiye'de **ESP32'ye özel** ilk ulusal format +- 150 TL kit erişilebilirliği ile **sosyoekonomik kapsayıcılık** +- Regional → championship funnel'i diff --git a/content/competitions/ideathon.md b/content/competitions/ideathon.md new file mode 100644 index 0000000..993de83 --- /dev/null +++ b/content/competitions/ideathon.md @@ -0,0 +1,32 @@ +--- +slug: ideathon +name: Ideathon +short: Fikir maratonu +tagline: "Bir günde fikirden projeye: tema, mentor, jüri." +format: "Tek günlük fikir maratonu. Açılış seminerleri ile başlar, temanın duyurulmasının ardından takımlar mentor desteğiyle fikir üretir ve günün sonunda jüri karşısında sunum yapar." +durationDays: 1 +ageGroups: + - Lise +categories: + - Sürdürülebilirlik + - Sosyal inovasyon + - Teknoloji +color: accent +icon: lightbulb +order: 2 +--- + +## Format + +- **Süre:** 11 saat (10:00 – 21:00) +- **Takım:** 3-5 öğrenci +- **Akış:** Açılış semineri → tema reveal → mentorlu fikir üretimi → ara atölyeler → jüri sunumu + ödül töreni +- **Katılım:** Ücretsiz + +## Çıktı + +Her takım, günün sonunda: +- Problem tanımı +- Çözüm konsepti +- 5 dakikalık pitch sunumu +- Prototip / mockup diff --git a/content/competitions/robo-soccer.md b/content/competitions/robo-soccer.md new file mode 100644 index 0000000..97182d4 --- /dev/null +++ b/content/competitions/robo-soccer.md @@ -0,0 +1,33 @@ +--- +slug: robo-soccer +name: Robo Soccer +short: Robot futbol ligi +tagline: "5 şehirde regional, ardından büyük final: Türkiye'nin yeni robot ligi." +format: "Takımlar otonom robotlarıyla sahada karşılaşır. Sezon boyunca 5 regional düzenlenir; en başarılı takımlar Championship'e kalır." +durationDays: 1 +ageGroups: + - Lise + - Üniversite +categories: + - Otonom kontrol + - Görüntü işleme + - Mekatronik +color: accent +icon: ball +order: 3 +--- + +## Sezon Yapısı + +1. **5 Regional** — her şehirde elemeler. İstanbul ve Ankara ile başlıyoruz; kalan üç şehir yakında açıklanacak. +2. **Championship** — regional'lardan gelen top takımlar tek elemeli büyük finalde karşılaşır. + +## Takım + +- 3-5 kişilik takım +- Robotu kendin getir (BYOR) — standartlar sezon başında duyurulur +- Her regional'a ayrı başvuru açılır + +## Duyuru + +Tarihler ve başvuru için WhatsApp topluluğumuza katıl, Instagram'ı takip et. diff --git a/content/editions/ankara-robo-soccer.md b/content/editions/ankara-robo-soccer.md new file mode 100644 index 0000000..a7af405 --- /dev/null +++ b/content/editions/ankara-robo-soccer.md @@ -0,0 +1,10 @@ +--- +slug: ankara-robo-soccer +competition: robo-soccer +name: Robo Soccer — Ankara Regional +status: announced +city: Ankara +summary: "Sezonun ikinci durağı Ankara'da. Tarih ve mekan yakında." +--- + +Sezonun ikinci durağı Ankara'da. Detaylar yakında duyurulacak. diff --git a/content/editions/atakoy-hands-on.md b/content/editions/atakoy-hands-on.md new file mode 100644 index 0000000..5cd6b87 --- /dev/null +++ b/content/editions/atakoy-hands-on.md @@ -0,0 +1,17 @@ +--- +slug: atakoy-hands-on +competition: hands-on-challenge +name: Hands-On Challenge — Istanbul Regional (Ataköy) +status: past +city: İstanbul +venue: Ataköy Gençlik Merkezi +stats: + teams: 16 + participants: 100 + volunteers: 15 +summary: "Impact'in ilk bölgesel Hands-On Challenge edisyonu. Ataköy Gençlik Merkezi'nde lise ve üniversite öğrencileri iki gün süren üretim maratonunda bir araya geldi." +--- + +İlk bölgesel edisyonumuz Ataköy Gençlik Merkezi'nde düzenlendi. 16 takım, toplam 100'ü aşkın katılımcı ve 15 gönüllüyle, Impact'in format prensiplerini sahaya indirdiğimiz ilk büyük organizasyon oldu. + +Tarih, detaylı takım listesi, kazananlar ve galeri yakında eklenecek. diff --git a/content/editions/cemberlitas-hands-on-2026.md b/content/editions/cemberlitas-hands-on-2026.md new file mode 100644 index 0000000..b03d402 --- /dev/null +++ b/content/editions/cemberlitas-hands-on-2026.md @@ -0,0 +1,28 @@ +--- +slug: cemberlitas-hands-on-2026 +competition: hands-on-challenge +name: Hands-On Challenge — Çemberlitaş Regional +status: past +startDate: "2026-04-18" +endDate: "2026-04-19" +city: İstanbul +venue: Çemberlitaş Gençlik Merkezi +stats: + teams: 16 + participants: 150 + volunteers: 20 +winners: + - place: 1 + team: İTÜ MTAL + school: İTÜ Mesleki ve Teknik Anadolu Lisesi + members: 3 +testimonials: + - by: M. Buğrahan Kılıç + org: Sultangazi Bilim ve İnovasyon Merkezi + quote: "Impact Hands-On Challenge Çemberlitaş Regional 2 gün boyunca 16 robotik takımına, 150'den fazla katılımcıya, mentörlere ve eğitimcilere kapılarını açtı. Impact, eğitim programları ve yarışmalarıyla Türkiye'de STEM ekosisteminin her geçen gün gelişmesini sağlıyor. İkinci kez katıldığımız ve keyif aldığımız bu organizasyonu düzenleyen ekibi kutlarız." +summary: "İstanbul'un en büyük robot yarışmalarından biri. 2 günlük non-stop üretim maratonu." +--- + +18-19 Nisan 2026'da Çemberlitaş Gençlik Merkezi'nde gerçekleştirdiğimiz edisyon, İstanbul'un en büyük robot yarışmalarından biri oldu. Ekipler tek günde verilen görevlere ilişkin robotlar geliştirdi; iki günlük non-stop üretim maratonu ve problem çözme odaklı bir robotik deneyimi yaşandı. + +> Detaylı takım listesi ve tüm kazananlar yakında eklenecek. diff --git a/content/editions/cemberlitas-ideathon-2025.md b/content/editions/cemberlitas-ideathon-2025.md new file mode 100644 index 0000000..b9cc614 --- /dev/null +++ b/content/editions/cemberlitas-ideathon-2025.md @@ -0,0 +1,17 @@ +--- +slug: cemberlitas-ideathon-2025 +competition: ideathon +name: Ideathon — Çemberlitaş Regional +status: past +startDate: "2025-10-05" +endDate: "2025-10-05" +city: İstanbul +venue: Çemberlitaş Gençlik Merkezi +partners: + - Gençlik ve Spor Bakanlığı +summary: "11 saatlik fikir maratonu. Lise öğrencileri 3-5 kişilik takımlar halinde mentorlu fikir üretimi yaptı." +--- + +10:00'da açılış seminerleri ile başlayan program, tema duyurusunun ardından mentorlu çalışma saatleriyle devam etti. Gün sonunda takımlar jüri karşısında sunumlarını yaptı, ödül töreni ile kapanış gerçekleşti. + +> Takım isimleri ve kazananlar yakında eklenecek. diff --git a/content/editions/istanbul-robo-soccer.md b/content/editions/istanbul-robo-soccer.md new file mode 100644 index 0000000..fb66ca0 --- /dev/null +++ b/content/editions/istanbul-robo-soccer.md @@ -0,0 +1,10 @@ +--- +slug: istanbul-robo-soccer +competition: robo-soccer +name: Robo Soccer — İstanbul Regional +status: upcoming +city: İstanbul +summary: "Robo Soccer sezonunun ilk durağı. Tarih ve mekan yakında açıklanacak." +--- + +Impact Robo Soccer sezonunun ilk durağı İstanbul'da. Tarih, mekan ve başvuru detayları yakında duyurulacak. WhatsApp topluluğumuza katılarak ilk haberi alanlardan ol. diff --git a/package-lock.json b/package-lock.json index 0d21683..70bcdb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "repo", "version": "0.1.0", "dependencies": { + "gray-matter": "^4.0.3", + "marked": "^18.0.2", "next": "16.2.4", "react": "19.2.4", "react-dom": "19.2.4" @@ -3423,6 +3425,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", @@ -3469,6 +3484,18 @@ "node": ">=0.10.0" } }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3804,6 +3831,43 @@ "dev": true, "license": "ISC" }, + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -4125,6 +4189,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4517,6 +4590,15 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.23", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", @@ -4868,6 +4950,18 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/marked": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.2.tgz", + "integrity": "sha512-NsmlUYBS/Zg57rgDWMYdnre6OTj4e+qq/JS2ot3KrYLSoHLw+sDu0Nm1ZGpRgYAq6c+b1ekaY5NzVchMCQnzcg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5634,6 +5728,19 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -5859,6 +5966,12 @@ "node": ">=0.10.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -6003,6 +6116,15 @@ "node": ">=4" } }, + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", diff --git a/package.json b/package.json index be7ffc2..b8632ef 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "lint": "eslint" }, "dependencies": { + "gray-matter": "^4.0.3", + "marked": "^18.0.2", "next": "16.2.4", "react": "19.2.4", "react-dom": "19.2.4" diff --git a/public/photos/cemberlitas-hands-on/01.jpg b/public/photos/cemberlitas-hands-on/01.jpg new file mode 100644 index 0000000..8590cb9 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/01.jpg differ diff --git a/public/photos/cemberlitas-hands-on/02.jpg b/public/photos/cemberlitas-hands-on/02.jpg new file mode 100644 index 0000000..75c5a68 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/02.jpg differ diff --git a/public/photos/cemberlitas-hands-on/03.jpg b/public/photos/cemberlitas-hands-on/03.jpg new file mode 100644 index 0000000..babf802 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/03.jpg differ diff --git a/public/photos/cemberlitas-hands-on/04.jpg b/public/photos/cemberlitas-hands-on/04.jpg new file mode 100644 index 0000000..6ee4537 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/04.jpg differ diff --git a/public/photos/cemberlitas-hands-on/05.jpg b/public/photos/cemberlitas-hands-on/05.jpg new file mode 100644 index 0000000..73c06e3 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/05.jpg differ diff --git a/public/photos/cemberlitas-hands-on/06.jpg b/public/photos/cemberlitas-hands-on/06.jpg new file mode 100644 index 0000000..46b2068 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/06.jpg differ diff --git a/public/photos/cemberlitas-hands-on/07.jpg b/public/photos/cemberlitas-hands-on/07.jpg new file mode 100644 index 0000000..dfda2c1 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/07.jpg differ diff --git a/public/photos/cemberlitas-hands-on/08.jpg b/public/photos/cemberlitas-hands-on/08.jpg new file mode 100644 index 0000000..971e015 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/08.jpg differ diff --git a/public/photos/cemberlitas-hands-on/09.jpg b/public/photos/cemberlitas-hands-on/09.jpg new file mode 100644 index 0000000..b1511ff Binary files /dev/null and b/public/photos/cemberlitas-hands-on/09.jpg differ diff --git a/public/photos/cemberlitas-hands-on/10.jpg b/public/photos/cemberlitas-hands-on/10.jpg new file mode 100644 index 0000000..8011517 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/10.jpg differ diff --git a/public/photos/cemberlitas-hands-on/11.jpg b/public/photos/cemberlitas-hands-on/11.jpg new file mode 100644 index 0000000..cea3c16 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/11.jpg differ diff --git a/public/photos/cemberlitas-hands-on/12.jpg b/public/photos/cemberlitas-hands-on/12.jpg new file mode 100644 index 0000000..8e3711b Binary files /dev/null and b/public/photos/cemberlitas-hands-on/12.jpg differ diff --git a/public/photos/cemberlitas-hands-on/13.jpg b/public/photos/cemberlitas-hands-on/13.jpg new file mode 100644 index 0000000..b3f35ad Binary files /dev/null and b/public/photos/cemberlitas-hands-on/13.jpg differ diff --git a/public/photos/cemberlitas-hands-on/14.jpg b/public/photos/cemberlitas-hands-on/14.jpg new file mode 100644 index 0000000..4d66fe7 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/14.jpg differ diff --git a/public/photos/cemberlitas-hands-on/15.jpg b/public/photos/cemberlitas-hands-on/15.jpg new file mode 100644 index 0000000..cd8007f Binary files /dev/null and b/public/photos/cemberlitas-hands-on/15.jpg differ diff --git a/public/photos/cemberlitas-hands-on/16.jpg b/public/photos/cemberlitas-hands-on/16.jpg new file mode 100644 index 0000000..50244f5 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/16.jpg differ diff --git a/public/photos/cemberlitas-hands-on/17.jpg b/public/photos/cemberlitas-hands-on/17.jpg new file mode 100644 index 0000000..4ea1b5e Binary files /dev/null and b/public/photos/cemberlitas-hands-on/17.jpg differ diff --git a/public/photos/cemberlitas-hands-on/18.jpg b/public/photos/cemberlitas-hands-on/18.jpg new file mode 100644 index 0000000..609e099 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/18.jpg differ diff --git a/public/photos/cemberlitas-hands-on/19.jpg b/public/photos/cemberlitas-hands-on/19.jpg new file mode 100644 index 0000000..73048e0 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/19.jpg differ diff --git a/public/photos/cemberlitas-hands-on/20.jpg b/public/photos/cemberlitas-hands-on/20.jpg new file mode 100644 index 0000000..5927769 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/20.jpg differ diff --git a/public/photos/cemberlitas-hands-on/21.jpg b/public/photos/cemberlitas-hands-on/21.jpg new file mode 100644 index 0000000..c9fd328 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/21.jpg differ diff --git a/public/photos/cemberlitas-hands-on/22.jpg b/public/photos/cemberlitas-hands-on/22.jpg new file mode 100644 index 0000000..3c450a0 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/22.jpg differ diff --git a/public/photos/cemberlitas-hands-on/23.jpg b/public/photos/cemberlitas-hands-on/23.jpg new file mode 100644 index 0000000..81cfdc4 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/23.jpg differ diff --git a/public/photos/cemberlitas-hands-on/24.jpg b/public/photos/cemberlitas-hands-on/24.jpg new file mode 100644 index 0000000..4989835 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/24.jpg differ diff --git a/public/photos/cemberlitas-hands-on/25.jpg b/public/photos/cemberlitas-hands-on/25.jpg new file mode 100644 index 0000000..5c45cee Binary files /dev/null and b/public/photos/cemberlitas-hands-on/25.jpg differ diff --git a/public/photos/cemberlitas-hands-on/26.jpg b/public/photos/cemberlitas-hands-on/26.jpg new file mode 100644 index 0000000..458338b Binary files /dev/null and b/public/photos/cemberlitas-hands-on/26.jpg differ diff --git a/public/photos/cemberlitas-hands-on/27.jpg b/public/photos/cemberlitas-hands-on/27.jpg new file mode 100644 index 0000000..c1fb996 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/27.jpg differ diff --git a/public/photos/cemberlitas-hands-on/28.jpg b/public/photos/cemberlitas-hands-on/28.jpg new file mode 100644 index 0000000..3e8f602 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/28.jpg differ diff --git a/public/photos/cemberlitas-hands-on/29.jpg b/public/photos/cemberlitas-hands-on/29.jpg new file mode 100644 index 0000000..7a31139 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/29.jpg differ diff --git a/public/photos/cemberlitas-hands-on/30.jpg b/public/photos/cemberlitas-hands-on/30.jpg new file mode 100644 index 0000000..7f34161 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/30.jpg differ diff --git a/public/photos/cemberlitas-hands-on/31.jpg b/public/photos/cemberlitas-hands-on/31.jpg new file mode 100644 index 0000000..75eb0e7 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/31.jpg differ diff --git a/public/photos/cemberlitas-hands-on/32.jpg b/public/photos/cemberlitas-hands-on/32.jpg new file mode 100644 index 0000000..6866625 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/32.jpg differ diff --git a/public/photos/cemberlitas-hands-on/33.jpg b/public/photos/cemberlitas-hands-on/33.jpg new file mode 100644 index 0000000..5ec469c Binary files /dev/null and b/public/photos/cemberlitas-hands-on/33.jpg differ diff --git a/public/photos/cemberlitas-hands-on/34.jpg b/public/photos/cemberlitas-hands-on/34.jpg new file mode 100644 index 0000000..fb2c1ee Binary files /dev/null and b/public/photos/cemberlitas-hands-on/34.jpg differ diff --git a/public/photos/cemberlitas-hands-on/35.jpg b/public/photos/cemberlitas-hands-on/35.jpg new file mode 100644 index 0000000..93d6ddf Binary files /dev/null and b/public/photos/cemberlitas-hands-on/35.jpg differ diff --git a/public/photos/cemberlitas-hands-on/36.jpg b/public/photos/cemberlitas-hands-on/36.jpg new file mode 100644 index 0000000..f9ecc68 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/36.jpg differ diff --git a/public/photos/cemberlitas-hands-on/37.jpg b/public/photos/cemberlitas-hands-on/37.jpg new file mode 100644 index 0000000..4052247 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/37.jpg differ diff --git a/public/photos/cemberlitas-hands-on/38.jpg b/public/photos/cemberlitas-hands-on/38.jpg new file mode 100644 index 0000000..c23362f Binary files /dev/null and b/public/photos/cemberlitas-hands-on/38.jpg differ diff --git a/public/photos/cemberlitas-hands-on/39.jpg b/public/photos/cemberlitas-hands-on/39.jpg new file mode 100644 index 0000000..242aaf9 Binary files /dev/null and b/public/photos/cemberlitas-hands-on/39.jpg differ diff --git a/public/photos/cemberlitas-hands-on/40.jpg b/public/photos/cemberlitas-hands-on/40.jpg new file mode 100644 index 0000000..9d96f6b Binary files /dev/null and b/public/photos/cemberlitas-hands-on/40.jpg differ diff --git a/src/app/edisyonlar/[slug]/page.tsx b/src/app/edisyonlar/[slug]/page.tsx new file mode 100644 index 0000000..0236de7 --- /dev/null +++ b/src/app/edisyonlar/[slug]/page.tsx @@ -0,0 +1,285 @@ +import Link from "next/link"; +import { notFound } from "next/navigation"; +import type { Metadata } from "next"; +import Image from "next/image"; +import { PageHero } from "@/components/PageHero"; +import { PhotoStrip } from "@/components/PhotoStrip"; +import { Section } from "@/components/Section"; +import { StatsStrip } from "@/components/StatsStrip"; +import { TestimonialCard } from "@/components/TestimonialCard"; +import { Gallery } from "@/components/Gallery"; +import { + formatDateRange, + getCompetition, + getEdition, + getEditions, +} from "@/lib/content"; +import { photos } from "@/lib/reviews"; + +export function generateStaticParams() { + return getEditions().map((e) => ({ slug: e.slug })); +} + +export async function generateMetadata( + props: PageProps<"/edisyonlar/[slug]">, +): Promise { + const { slug } = await props.params; + const e = getEdition(slug); + if (!e) return {}; + return { + title: e.name, + description: e.summary ?? undefined, + }; +} + +const statusLabel = { + upcoming: "Yaklaşan", + announced: "Duyuruldu", + past: "Geçmiş", +} as const; + +export default async function EditionPage( + props: PageProps<"/edisyonlar/[slug]">, +) { + const { slug } = await props.params; + const e = getEdition(slug); + if (!e) notFound(); + const c = getCompetition(e.competition); + + const isCemberlitasHoC = e.slug === "cemberlitas-hands-on-2026"; + const heroPhoto = isCemberlitasHoC ? photos.cemberlitas[14] : undefined; + const gallery = isCemberlitasHoC + ? [0, 7, 14, 20, 26, 32].map((i) => photos.cemberlitas[i]) + : []; + const strip = isCemberlitasHoC + ? [3, 18, 24, 35].map((i) => photos.cemberlitas[i]) + : []; + + return ( + <> + + + {statusLabel[e.status]} + + + {formatDateRange(e.startDate, e.endDate)} + + {e.city && ( + + {e.city} + + )} + + } + /> + + {/* Meta row */} +
+
+ + {e.venue && } + {e.city && } + {c && } +
+
+ + {/* Stats */} + {e.stats && ( +
+ 0 + ? [{ value: e.partners.length, label: "Partner" }] + : e.startDate && e.endDate + ? [ + { + value: String( + Math.round( + (new Date(e.endDate).getTime() - + new Date(e.startDate).getTime()) / + 86400000, + ) + 1, + ), + label: "Gün", + }, + ] + : []), + ]} + /> +
+ )} + + {/* Body */} + {(e.bodyHtml || e.summary) && ( +
+
+
+
+ {e.summary && ( +

{e.summary}

+ )} + {e.bodyHtml &&
} +
+
+ {heroPhoto && ( +
+
+ +
+
+ )} +
+
+ )} + + {/* Gallery */} + {gallery.length > 0 && ( +
+ +
+ +
+
+ )} + + {/* Winners */} + {e.winners && e.winners.length > 0 && ( +
+
+ {e.winners.map((w) => ( +
+
+ {w.place === 1 + ? "🥇 Birincilik" + : w.place === 2 + ? "🥈 İkincilik" + : w.place === 3 + ? "🥉 Üçüncülük" + : `#${w.place}`} +
+
{w.team}
+ {w.school && ( +
{w.school}
+ )} + {w.members && ( +
+ {w.members} kişilik takım +
+ )} +
+ ))} +
+
+ )} + + {/* Teams */} + {e.teams && e.teams.length > 0 && ( +
+
+ + + + + + + + + + {e.teams.map((t, i) => ( + + + + + + ))} + +
TakımOkulKişi
{t.name}{t.school ?? "—"}{t.size ?? "—"}
+
+
+ )} + + {/* Partners */} + {e.partners && e.partners.length > 0 && ( +
+
+ {e.partners.map((p) => ( + + {p} + + ))} +
+
+ )} + + {/* Testimonials */} + {e.testimonials && e.testimonials.length > 0 && ( +
+
+ {e.testimonials.map((t, i) => ( + + ))} +
+
+ )} + + {/* Back */} +
+ + ← {c ? `${c.name} tüm edisyonları` : "Anasayfa"} + +
+ + ); +} + +function Meta({ label, value }: { label: string; value: string }) { + return ( +
+
+ {label} +
+
{value}
+
+ ); +} diff --git a/src/app/globals.css b/src/app/globals.css index a2dc41e..5a2e4fd 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,26 +1,93 @@ @import "tailwindcss"; +@theme { + --color-ink: #0a0a0a; + --color-ink-muted: #525252; + --color-ink-faint: #8a8a8a; + --color-paper: #ffffff; + --color-paper-2: #fafafa; + --color-paper-3: #f4f4f5; + --color-line: #0a0a0a; + + --color-brand: #6d28d9; + --color-brand-600: #5b21b6; + --color-brand-400: #8b5cf6; + --color-brand-50: #f5f3ff; + --color-accent: #fde047; + --color-accent-600: #facc15; + + --font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; + --font-mono: var(--font-geist-mono), ui-monospace, monospace; +} + :root { - --background: #ffffff; - --foreground: #171717; + color-scheme: light; } -@theme inline { - --color-background: var(--background); - --color-foreground: var(--foreground); - --font-sans: var(--font-geist-sans); - --font-mono: var(--font-geist-mono); -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } +html, body { + background: var(--color-paper); + color: var(--color-ink); } body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; + font-family: var(--font-sans); + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +::selection { + background: var(--color-accent); + color: var(--color-ink); +} + +/* Prose tweaks for markdown body (light theme) */ +.prose-impact h2 { + font-size: 1.75rem; + font-weight: 800; + margin-top: 2.5rem; + margin-bottom: 0.75rem; + letter-spacing: -0.02em; +} +.prose-impact h3 { + font-size: 1.25rem; + font-weight: 700; + margin-top: 1.75rem; + margin-bottom: 0.5rem; +} +.prose-impact p { + margin-top: 0.85rem; + margin-bottom: 0.85rem; + color: var(--color-ink-muted); + line-height: 1.7; +} +.prose-impact ul { + list-style: disc; + padding-left: 1.25rem; + color: var(--color-ink-muted); +} +.prose-impact li { + margin-top: 0.25rem; +} +.prose-impact a { + color: var(--color-brand); + text-decoration: underline; + text-underline-offset: 3px; +} +.prose-impact strong { + color: var(--color-ink); + font-weight: 700; +} + +/* Marquee (no JS, pure CSS) */ +@keyframes marquee { + from { transform: translateX(0); } + to { transform: translateX(-50%); } +} +.marquee-track { + display: flex; + width: max-content; + animation: marquee 40s linear infinite; +} +@media (prefers-reduced-motion: reduce) { + .marquee-track { animation: none; } } diff --git a/src/app/hakkimizda/page.tsx b/src/app/hakkimizda/page.tsx new file mode 100644 index 0000000..b242dea --- /dev/null +++ b/src/app/hakkimizda/page.tsx @@ -0,0 +1,131 @@ +import type { Metadata } from "next"; +import Image from "next/image"; +import { PageHero } from "@/components/PageHero"; +import { PhotoStrip } from "@/components/PhotoStrip"; +import { Section } from "@/components/Section"; +import { sdgs, site, team, values } from "@/lib/contact"; +import { photos } from "@/lib/reviews"; + +export const metadata: Metadata = { + title: "Hakkımızda", + description: site.description, +}; + +export default function AboutPage() { + const heroPhoto = photos.cemberlitas[18]; + const sidePhotos = [11, 27, 33].map((i) => photos.cemberlitas[i]); + const strip = [4, 16, 22, 39].map((i) => photos.cemberlitas[i]); + + return ( + <> + STEM için, gençler tarafından} + lead="Impact; robotik yarışmaları, ideathonlar ve eğitim programlarıyla Türkiye'de STEM ekosisteminin her geçen gün gelişmesini sağlayan bir gençlik topluluğu." + variant="photo" + photo={{ src: heroPhoto.src, alt: "Impact etkinlikten bir kare" }} + /> + + {/* MISSION */} +
+
+
+

+ Bilim, teknoloji, mühendislik ve matematiği{" "} + herkes için erişilebilir kılmak; + ilham veren bir gelecek tasarlamak ve gençleri 21. yüzyılın becerileriyle + buluşturmak. +

+

+ Her etkinliğimiz, geleceği sadece anlayan değil aktif olarak inşa eden bir + nesil yetiştirmeyi hedefler. Gençleri eğitim, sosyal etki ve sürdürülebilir + kalkınmanın kesişiminde gerçek dünya teknolojileriyle tanıştırıyoruz. +

+
+
+ {sidePhotos.map((p) => ( +
+ +
+ ))} +
+
+
+ + {/* TEAM */} +
+
+ {team.map((m) => ( +
+
+ + {m.name + .split(" ") + .map((w) => w[0]) + .slice(0, 2) + .join("")} + +
+ {m.name} +
+
+ {m.role} +
+
+
+ ))} +
+
+ + {/* PHOTO STRIP */} +
+
+ +
+
+ + {/* VALUES */} +
+
+ {values.map((v) => ( + + {v} + + ))} +
+
+ + {/* SDG */} +
+
+ {sdgs.map((s) => ( +
+
{s.number}
+
+ {s.name} +
+
+ ))} +
+
+ + ); +} diff --git a/src/app/iletisim/page.tsx b/src/app/iletisim/page.tsx new file mode 100644 index 0000000..58bf5e0 --- /dev/null +++ b/src/app/iletisim/page.tsx @@ -0,0 +1,136 @@ +import type { Metadata } from "next"; +import { PageHero } from "@/components/PageHero"; +import { Section } from "@/components/Section"; +import { contact, team } from "@/lib/contact"; + +export const metadata: Metadata = { + title: "İletişim", + description: "Impact iletişim kanalları: e-posta, Instagram, LinkedIn, WhatsApp.", +}; + +const channels = [ + { + key: "email", + title: "E-posta", + value: contact.email, + href: `mailto:${contact.email}`, + help: "Genel sorular, sponsor talepleri ve işbirlikleri.", + }, + { + key: "instagram", + title: "Instagram", + value: `@${contact.instagram.handle}`, + href: contact.instagram.url, + help: "Etkinlik duyuruları, geçmiş fotoğraflar, anlık içerik.", + }, + { + key: "linkedin", + title: "LinkedIn", + value: "impactcommunit", + href: contact.linkedin.url, + help: "Kurumsal iletişim, sponsor ve partner ağı.", + }, + { + key: "whatsapp", + title: "WhatsApp", + value: "Topluluğa katıl", + href: contact.whatsapp.url, + help: "Katılımcı, gönüllü ve mentor topluluğu.", + }, +]; + +const altMails = [ + "contact@impact.tr", + "info@impact.tr", + "hello@impact.tr", +]; + +export default function ContactPage() { + return ( + <> + Bize ulaşın} + lead="Sponsor, partner, gönüllü, mentor ya da sadece meraklı — hangi kanalı seçersen seç yanıt veriyoruz." + /> + + {/* Channels */} +
+ +
+ + {/* Team emails */} +
+
+ {team.map((m) => { + const handle = m.name.split(" ")[0].toLowerCase().replace(/ı/g, "i"); + const email = `${handle}@impact.tr`; + return ( + + + {m.name + .split(" ") + .map((w) => w[0]) + .slice(0, 2) + .join("")} + +
+
{m.name}
+
+ {m.role} +
+
+
+ {email} → +
+
+ ); + })} +
+
+ + {/* Alt mails */} +
+
+ {altMails.map((m) => ( + + {m} ↗ + + ))} +
+
+ + ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 976eb90..3f2a2ff 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,9 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import { Nav } from "@/components/Nav"; +import { Footer } from "@/components/Footer"; +import { site } from "@/lib/contact"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -13,21 +16,40 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + metadataBase: new URL(site.url), + title: { + default: "impact — STEM için, gençler tarafından", + template: "%s · impact", + }, + description: site.description, + openGraph: { + type: "website", + url: site.url, + siteName: "impact", + title: "impact — STEM için, gençler tarafından", + description: site.description, + locale: "tr_TR", + }, + twitter: { + card: "summary_large_image", + title: "impact", + description: site.description, + }, }; export default function RootLayout({ children, -}: Readonly<{ - children: React.ReactNode; -}>) { +}: Readonly<{ children: React.ReactNode }>) { return ( - {children} + +