diff --git a/.env b/.env.example
similarity index 68%
rename from .env
rename to .env.example
index 537be565..380aaaba 100644
--- a/.env
+++ b/.env.example
@@ -1,2 +1,2 @@
APP_CARD_DEFAULT_IMAGE=https://art.shlisselburg.org/static/img/main.jpg
-
+NEXT_PUBLIC_YMETRIKA_ACCOUNT=XXX
diff --git a/.gitignore b/.gitignore
index 817645cf..35ab2d8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ dist
.vercel
.next
tsconfig.tsbuildinfo
+.env
diff --git a/CLAUDE.md b/CLAUDE.md
index a9fe8cea..7b9608d3 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -26,6 +26,18 @@ Feature branches are named `issue-XXX` where `XXX` is the related GitHub issue n
ESLint 9 flat config (`eslint.config.js`) using `FlatCompat` from `@eslint/eslintrc` to bridge `eslint-config-next` (which doesn't support native flat config in Next.js 15.x). Extends `next/core-web-vitals`. Enforces: no semicolons, double quotes, 4-space indentation, always-multiline trailing commas, `eol-last`.
+**React components:** Use regular function declarations (not arrow functions) and `type` for props. Do not use `React.FC`.
+
+```tsx
+export type MyComponentProps = {
+ value: string
+}
+
+export function MyComponent({ value }: MyComponentProps) {
+ return
{value}
+}
+```
+
## Architecture
**Pages Router with SSG/ISR:** All pages use `getStaticProps`/`getStaticPaths` with 30-second revalidation. The catch-all route `pages/[...slug].tsx` handles all dynamic content pages.
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 0c71cc1d..4554ee69 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -7,7 +7,7 @@ import "src/style/kazimir/video.css"
import App from "next/app"
import Head from "next/head"
import Script from "next/script"
-import { YMetrika } from "src/components/YMetrika"
+import { YMetrika } from "@/components/YMetrika"
import { ThemeColor } from "@/ui/ThemeColor"
export default class MyApp extends App {
@@ -41,7 +41,9 @@ export default class MyApp extends App {
href="/feed.xml"
/>
-
+ {process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT && (
+
+ )}
{
+ it("should embed account id into metrika counter variable", () => {
+ const result = script(99999)
+ expect(result).toContain("w.yaCounter99999")
+ })
+
+ it("should embed account id into metrika config", () => {
+ const result = script(99999)
+ expect(result).toContain("id:99999")
+ })
+
+ it("should include metrika watch.js script url", () => {
+ const result = script(99999)
+ expect(result).toContain("https://mc.yandex.ru/metrika/watch.js")
+ })
+
+ it("should use yandex_metrika_callbacks", () => {
+ const result = script(99999)
+ expect(result).toContain("yandex_metrika_callbacks")
+ })
+
+ it("should produce different output for different accounts", () => {
+ const a = script(11111)
+ const b = script(22222)
+ expect(a).toContain("yaCounter11111")
+ expect(b).toContain("yaCounter22222")
+ expect(a).not.toContain("yaCounter22222")
+ })
+})
diff --git a/src/components/YMetrika.jsx b/src/components/YMetrika.tsx
similarity index 80%
rename from src/components/YMetrika.jsx
rename to src/components/YMetrika.tsx
index 33d61f26..14c3ee0c 100644
--- a/src/components/YMetrika.jsx
+++ b/src/components/YMetrika.tsx
@@ -1,6 +1,8 @@
-import React from "react"
+export type YMetrikaProps = {
+ account: number
+}
-function script(account) {
+export function script(account: number) {
return `
(function (d, w, c) {
(w[c] = w[c] || []).push(function() {
@@ -14,14 +16,14 @@ function script(account) {
});
} catch(e) { }
});
-
+
var n = d.getElementsByTagName("script")[0],
s = d.createElement("script"),
f = function () { n.parentNode.insertBefore(s, n); };
s.type = "text/javascript";
s.async = true;
s.src = "https://mc.yandex.ru/metrika/watch.js";
-
+
if (w.opera == "[object Opera]") {
d.addEventListener("DOMContentLoaded", f, false);
} else { f(); }
@@ -29,6 +31,6 @@ function script(account) {
`
}
-export const YMetrika = (props) => (
-
-)
+export function YMetrika({ account }: YMetrikaProps) {
+ return
+}
diff --git a/vitest.config.ts b/vitest.config.ts
index 683d5a85..2afc56f9 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -9,6 +9,6 @@ export default defineConfig({
},
},
test: {
- include: ["src/**/*.test.ts"],
+ include: ["src/**/*.test.{ts,tsx}"],
},
})