Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a8361d710 | ||
|
|
502ffee31f | ||
|
|
5a322230ae | ||
|
|
f919c288b2 |
+8
-1
@@ -1,6 +1,13 @@
|
||||
import type { I18nConfig } from './types.js';
|
||||
/** Cookie name the template uses to persist a visitor's locale choice. */
|
||||
export declare const LOCALE_COOKIE_NAME = "ipal-locale";
|
||||
/**
|
||||
* Cookie name for the persisted locale choice. Uses NEXT_LOCALE — the convention
|
||||
* Next.js and its i18n ecosystem expect — so the cookie is interoperable with
|
||||
* other libraries that read the active locale (instead of a plugin-specific
|
||||
* name). Written only under functional consent; cleared when that consent is
|
||||
* withdrawn (see consent cookieMap).
|
||||
*/
|
||||
export declare const LOCALE_COOKIE_NAME = "NEXT_LOCALE";
|
||||
type NegotiateLocaleArgs = {
|
||||
/** Raw Accept-Language header value */
|
||||
acceptLanguage?: null | string;
|
||||
|
||||
Vendored
+7
-1
@@ -1,5 +1,11 @@
|
||||
import { getLocaleCodes, isValidLocale } from './helpers.js';
|
||||
/** Cookie name the template uses to persist a visitor's locale choice. */ export const LOCALE_COOKIE_NAME = 'ipal-locale';
|
||||
/** Cookie name the template uses to persist a visitor's locale choice. */ /**
|
||||
* Cookie name for the persisted locale choice. Uses NEXT_LOCALE — the convention
|
||||
* Next.js and its i18n ecosystem expect — so the cookie is interoperable with
|
||||
* other libraries that read the active locale (instead of a plugin-specific
|
||||
* name). Written only under functional consent; cleared when that consent is
|
||||
* withdrawn (see consent cookieMap).
|
||||
*/ export const LOCALE_COOKIE_NAME = 'NEXT_LOCALE';
|
||||
/**
|
||||
* Resolves which locale to serve, in priority order:
|
||||
* 1. Cookie (explicit prior choice)
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+18
-3
@@ -4,12 +4,13 @@ Sztywna procedura dla pracownika albo AI (Antigravity). Mówi CO robić, W JAKIE
|
||||
KOLEJNOŚCI, i CZYM SIĘ KIEROWAĆ. Zasady są twarde, przykłady realne — wzięte z
|
||||
faktycznych błędów, które się zdarzyły. Odstępstwa tylko za świadomą decyzją.
|
||||
|
||||
Powiązane: [publishing.md](./publishing.md) (cykl publikacji), [getting-started.md](./getting-started.md)
|
||||
Powiązane: [standardy-kodu.md](./standardy-kodu.md) (dobre praktyki senior),
|
||||
[publishing.md](./publishing.md) (cykl publikacji), [getting-started.md](./getting-started.md)
|
||||
(nowy projekt), ../ANTIGRAVITY-ZASADY-AGENT.md (zasady dla AI).
|
||||
|
||||
---
|
||||
|
||||
## ZŁOTE ZASADY
|
||||
## ZŁOTE ZASADY (łam tylko świadomie)
|
||||
|
||||
1. **Nic na sztywno.** Tekst, obraz, link, dane firmy → panel/baza, nie kod.
|
||||
2. **Logika w pluginie, projekt podłącza.** Jeśli piszesz w projekcie coś, co
|
||||
@@ -18,6 +19,8 @@ Powiązane: [publishing.md](./publishing.md) (cykl publikacji), [getting-started
|
||||
4. **Weryfikuj każdy etap grepem.** Nie zakładaj, że zadziałało. Sprawdź.
|
||||
5. **Napraw u źródła, nie łataj.** Bez `as any`, `@ts-ignore`, kopii logiki.
|
||||
6. **Zmiana w pluginie nie działa, dopóki nie: build → publish → wciągnięcie.**
|
||||
7. **Zmieniłeś API → zaktualizuj docs w tym samym commicie.** Docs jadą w
|
||||
pakiecie; rozjazd kod↔docs = agent dostaje złą mapę.
|
||||
|
||||
---
|
||||
|
||||
@@ -39,6 +42,11 @@ cd ~/payload-cms/ipal-kit
|
||||
# 1. ŹRÓDŁA — nanieś zmianę, ZWERYFIKUJ że jest
|
||||
grep -c "<symbol-zmiany>" src/<ścieżka> # MUSI być >0
|
||||
|
||||
# 1b. DOCS — jeśli zmiana dotyka API/zachowania, ZAKTUALIZUJ docs/
|
||||
# (nowa funkcja, zmiana sygnatury, nowe pole panelu, nowy adapter...).
|
||||
# Docs jadą w pakiecie (files: dist, docs) — nieaktualne docs = agent
|
||||
# dostaje złą mapę. Kod i docs publikuj RAZEM.
|
||||
|
||||
# 2. BUILD — zbuduj, ZWERYFIKUJ że dist ma zmianę
|
||||
pnpm build
|
||||
grep -c "<symbol-zmiany>" dist/<ścieżka> # MUSI być >0
|
||||
@@ -83,6 +91,9 @@ pokazał 0. Naprawa: dodać eksport, przejść łańcuch od nowa.
|
||||
publish, grep dist po buildzie.
|
||||
- **`pnpm add` przy działającym dev** → proces ma stary adapter w pamięci.
|
||||
Payload czyta email/config przy starcie. ZAWSZE restart po wciągnięciu.
|
||||
- **Publikacja bez aktualizacji docs** → agent (Antigravity) po `pnpm add`
|
||||
czyta `node_modules/@intecion/ipal-kit/docs/` z NIEAKTUALNĄ mapą. Jeśli
|
||||
zmieniłeś API — docs w tym samym commicie.
|
||||
|
||||
---
|
||||
|
||||
@@ -236,4 +247,8 @@ Nie mów „działa", dopóki:
|
||||
- [ ] brak dubletu @payloadcms/ui (Część D)
|
||||
- [ ] grep potwierdza wersję pluginu w node_modules
|
||||
- [ ] sekrety w .env (nie w repo), maskowane w panelu
|
||||
- [ ] brak plików middleware.ts, brak zaszytej mapy slugów
|
||||
- [ ] brak plików middleware.ts, brak zaszytej mapy slugów
|
||||
- [ ] strona 404 (not-found.tsx) — edytowalna, per język, link powrotu
|
||||
- [ ] formularze z buildera w panelu (NIE własne hardkodowane)
|
||||
- [ ] compliance: polityki, baner cookies, zgoda RODO w formularzach
|
||||
(patrz [wymagania-prawne.md](./wymagania-prawne.md))
|
||||
@@ -108,6 +108,7 @@ export default buildConfig({
|
||||
| access | Role admin > editor > user, kontrola dostępu | [access.md](./access.md) |
|
||||
| payload-helpers | getSiteSettings / getSiteIntegrations | [payload-helpers.md](./payload-helpers.md) |
|
||||
| seo | Metadata, hreflang, auto-fill, plugin-seo | [seo.md](./seo.md) |
|
||||
| architektura-tresci | **Jak budować, żeby klient wszystko edytował** (filozofia CMS) | [architektura-tresci.md](./architektura-tresci.md) |
|
||||
| blocks | RenderBlocks — silnik renderowania bloków | [blocks.md](./blocks.md) |
|
||||
| consent | Banner cookies GDPR, Google Consent Mode | [consent.md](./consent.md) |
|
||||
| turnstile | Cloudflare Turnstile (widget + verify) | [turnstile.md](./turnstile.md) |
|
||||
|
||||
+37
-2
@@ -109,7 +109,7 @@ Dostępne tokeny (każdy ma odpowiednik `-dark` używany pod `dark:`):
|
||||
| `--ipal-hover` | `#f5f5f5` | hover przycisków drugorzędnych |
|
||||
| `--ipal-radius` | `0.375rem` | zaokrąglenie przycisków |
|
||||
|
||||
Wymaga `@source` skanującego pakiet (patrz frontend-setup.md) — inaczej Tailwind
|
||||
Wymaga `@source` skanującego pakiet (patrz getting-started.md) — inaczej Tailwind
|
||||
nie wygeneruje tych klas.
|
||||
|
||||
### Gdy tokeny nie wystarczą
|
||||
@@ -131,4 +131,39 @@ Sloty: `root`, `primaryButton`, `secondaryButton`. Podany className zastępuje
|
||||
domyślny (nie dokleja się).
|
||||
|
||||
Elementy mają też `data-ipal="banner"` i `data-ipal="cookie-button"` — stabilne
|
||||
uchwyty do CSS albo testów e2e.
|
||||
uchwyty do CSS albo testów e2e.
|
||||
|
||||
## Locale jako cookie functional (wbudowane)
|
||||
|
||||
Plugin sam zarządza jedną cookie functional: **`NEXT_LOCALE`** (wybór języka).
|
||||
Nie musisz nic konfigurować — działa out of the box:
|
||||
|
||||
- **Zapis za zgodą.** Middleware zapisuje `NEXT_LOCALE` tylko, gdy użytkownik
|
||||
zaakceptował kategorię **functional**. Bez zgody język działa (negocjacja per
|
||||
żądanie), ale nie jest utrwalany w cookie.
|
||||
- **Sprzątanie po cofnięciu.** Gdy użytkownik cofnie zgodę na functional, hook
|
||||
consent usuwa `NEXT_LOCALE` automatycznie. Odpowiada za to `DEFAULT_COOKIE_MAP`:
|
||||
|
||||
```ts
|
||||
const DEFAULT_COOKIE_MAP = {
|
||||
functional: [LOCALE_COOKIE_NAME], // 'NEXT_LOCALE' — plugin zna własną cookie
|
||||
}
|
||||
```
|
||||
|
||||
### Twoje własne cookie functional/analytics
|
||||
|
||||
Jeśli ustawiasz własne cookie podlegające zgodzie, rozszerz mapę — hook wtedy
|
||||
sprzątnie też Twoje po cofnięciu zgody:
|
||||
|
||||
```ts
|
||||
useConsent({
|
||||
functional: ['NEXT_LOCALE', 'moje-ustawienie'],
|
||||
analytics: ['_ga', '_gid'],
|
||||
})
|
||||
```
|
||||
|
||||
Przekazana mapa zastępuje domyślną — pamiętaj dołączyć `NEXT_LOCALE`, jeśli
|
||||
chcesz zachować sprzątanie locale (albo zaimportuj `LOCALE_COOKIE_NAME` i dodaj).
|
||||
|
||||
> Mechanizm zgody dla locale jest opisany też od strony i18n:
|
||||
> [i18n.md](./i18n.md#cookie-locale-a-zgoda-rodo).
|
||||
@@ -4,6 +4,31 @@ Wpina `@payloadcms/plugin-form-builder` (kolekcje forms + form-submissions) i
|
||||
dostarcza `submitForm` — wywoływalną z frontu funkcję, która spina: weryfikację
|
||||
Turnstile → zapis zgłoszenia → wysyłkę maili (naszym senderem).
|
||||
|
||||
## ⚠️ ZASADA: formularz POCHODZI z buildera w panelu (obowiązkowe)
|
||||
|
||||
**Formularze buduje redaktor w panelu** (kolekcja Forms), NIE deweloper w kodzie.
|
||||
To jest CMS — klient sam definiuje pola, etykiety, komunikaty, odbiorcę. Front
|
||||
tylko RENDERUJE formularz z panelu i wysyła przez `submitForm`.
|
||||
|
||||
**NIGDY nie twórz własnego, hardkodowanego formularza** — z ręcznie wpisanymi
|
||||
polami, etykietami w JSX, własną walidacją. To łamie „nic na sztywno" (klient nie
|
||||
zmieni pól ani tekstów) i omija cały mechanizm pluginu (Turnstile, rate-limit,
|
||||
consent RODO, powiadomienia).
|
||||
|
||||
| ŹLE (własny formularz) | DOBRZE (builder pluginu) |
|
||||
|---|---|
|
||||
| `<input name="email" placeholder="Email" />` w JSX | pola z kolekcji Forms (panel) |
|
||||
| etykiety/komunikaty w kodzie | etykiety per język w panelu |
|
||||
| własna walidacja/wysyłka | `submitForm` (Turnstile+consent+mail) |
|
||||
| klient nie zmieni formularza | klient edytuje pola w panelu |
|
||||
|
||||
**Jak poprawnie:** redaktor tworzy formularz w kolekcji Forms → front pobiera
|
||||
jego definicję → renderuje pola dynamicznie → wysyła przez `submitForm`. Pola,
|
||||
etykiety, komunikaty, odbiorca — wszystko z panelu.
|
||||
|
||||
Jeśli formularz wymaga pola, którego builder nie ma — dodaj je przez konfigurację
|
||||
`fields` (patrz niżej) albo rozbuduj plugin. NIE hardkoduj własnego formularza.
|
||||
|
||||
## Zależność
|
||||
|
||||
```json
|
||||
|
||||
@@ -172,6 +172,9 @@ export const blockRegistry: BlockComponentMap = {
|
||||
}
|
||||
```
|
||||
|
||||
> **Jak budować treść, żeby klient mógł wszystko edytować** (filozofia
|
||||
> CMS, kolejność komponent→blok→strona): [architektura-tresci.md](./architektura-tresci.md).
|
||||
|
||||
**Puste `blocks: []` crashuje** (traverseFields) — zawsze co najmniej jeden blok.
|
||||
|
||||
### enhanceProps — wstrzykiwanie danych server-side do bloków
|
||||
|
||||
+33
-1
@@ -107,4 +107,36 @@ Zachowanie:
|
||||
locale z: cookie → Accept-Language → default
|
||||
- wybrany locale zapisany w cookie (`LOCALE_COOKIE_NAME`)
|
||||
|
||||
`DEFAULT_MIDDLEWARE_MATCHER` wyklucza `api`, `admin`, `_next`, pliki statyczne.
|
||||
`DEFAULT_MIDDLEWARE_MATCHER` wyklucza `api`, `admin`, `_next`, pliki statyczne.
|
||||
|
||||
## Cookie locale a zgoda (RODO)
|
||||
|
||||
Wybór języka zapisywany jest w cookie **`NEXT_LOCALE`** (konwencja Next.js —
|
||||
kompatybilna z innymi bibliotekami i18n, które czytają aktywny locale). Ale
|
||||
zapis podlega zgodzie: to cookie kategorii **functional**, więc:
|
||||
|
||||
- **Zapis TYLKO za zgodą.** Middleware zapisuje `NEXT_LOCALE` jedynie, gdy
|
||||
użytkownik zgodził się na kategorię functional (`mayPersistLocale` sprawdza
|
||||
zgodę). Bez zgody język działa per żądanie (negocjacja z Accept-Language),
|
||||
ale nie jest utrwalany.
|
||||
- **Sprzątanie po cofnięciu zgody.** Gdy użytkownik cofnie zgodę na functional,
|
||||
cookie `NEXT_LOCALE` jest usuwane automatycznie (consent zna tę cookie przez
|
||||
`DEFAULT_COOKIE_MAP` — patrz [consent.md](./consent.md)).
|
||||
|
||||
Nazwa cookie to jedna stała `LOCALE_COOKIE_NAME` (`modules/i18n/negotiateLocale`),
|
||||
propagująca do middleware i sprzątania consent. Można nadpisać w
|
||||
`createLocaleMiddleware({ cookieName })`, ale domyślnie `NEXT_LOCALE` jest
|
||||
zalecane (interop).
|
||||
|
||||
### Kolejność negocjacji locale
|
||||
|
||||
1. Cookie `NEXT_LOCALE` (jeśli jest — czyli był wybór za zgodą)
|
||||
2. Nagłówek `Accept-Language` (preferencje przeglądarki)
|
||||
3. `defaultLocale` z konfiguracji
|
||||
|
||||
Wejście na `/` → negocjacja → redirect na `/pl` (albo wynik negocjacji).
|
||||
Zmiana języka (URL `/en` różny od cookie) → zapis nowego wyboru (za zgodą).
|
||||
|
||||
> **Migracja ze starej nazwy:** wcześniej cookie nazywało się `ipal-locale`.
|
||||
> Po zmianie na `NEXT_LOCALE` użytkownicy ze starą cookie przejdą raz ponowną
|
||||
> negocjację (stara cookie ignorowana). Jednorazowe, bez wpływu na nowe projekty.
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@intecion/ipal-kit",
|
||||
"version": "1.0.16",
|
||||
"version": "1.0.18",
|
||||
"description": "Intecion Payload Advanced Library — a Payload CMS 3 plugin: i18n, SEO, forms, consent, analytics, blog/archives.",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -3,7 +3,14 @@ import type { I18nConfig } from './types.js'
|
||||
import { getLocaleCodes, isValidLocale } from './helpers.js'
|
||||
|
||||
/** Cookie name the template uses to persist a visitor's locale choice. */
|
||||
export const LOCALE_COOKIE_NAME = 'ipal-locale'
|
||||
/**
|
||||
* Cookie name for the persisted locale choice. Uses NEXT_LOCALE — the convention
|
||||
* Next.js and its i18n ecosystem expect — so the cookie is interoperable with
|
||||
* other libraries that read the active locale (instead of a plugin-specific
|
||||
* name). Written only under functional consent; cleared when that consent is
|
||||
* withdrawn (see consent cookieMap).
|
||||
*/
|
||||
export const LOCALE_COOKIE_NAME = 'NEXT_LOCALE'
|
||||
|
||||
type NegotiateLocaleArgs = {
|
||||
/** Raw Accept-Language header value */
|
||||
|
||||
Reference in New Issue
Block a user