Skip to content

Commit 05dcceb

Browse files
authored
Merge pull request #75 from miloshb/stage
Dual-site hosting for corporate and brand [major]
2 parents a517651 + 6209122 commit 05dcceb

71 files changed

Lines changed: 1288 additions & 151 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

doc/README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ Cloudflare Pages compiles every single active branch in the repository into its
4040

4141
| Git Branch | Deployment Target URL | Environment Purpose |
4242
| :--- | :--- | :--- |
43-
| **`main`** | [studiosunandsea.com](https://studiosunandsea.com) | Live Production Site |
44-
| **`stage`** | [stage.studio-sun-and-sea.pages.dev](https://stage.studio-sun-and-sea.pages.dev) | QA Staging Sandbox |
43+
| **`main`** | [studiosunandsea.com](https://studiosunandsea.com) and [eireneintentiocitta.hr](https://eireneintentiocitta.hr) | Live Production Sites |
44+
| **`stage`** (default) | [stage.studio-sun-and-sea.pages.dev](https://stage.studio-sun-and-sea.pages.dev) | QA Staging Sandbox |
4545
| `mindbody` | [mindbody.studio-sun-and-sea.pages.dev](https://mindbody.studio-sun-and-sea.pages.dev) | Widget Testing Environment |
4646
| `content` | [content.studio-sun-and-sea.pages.dev](https://content.studio-sun-and-sea.pages.dev) | Content and UI Testing |
4747
| `cm` | [cm.studio-sun-and-sea.pages.dev](https://cm.studio-sun-and-sea.pages.dev) | Configuration Management Testing |
4848
| `feat/*` | `[branch-name].studio-sun-and-sea.pages.dev` | Automated Preview Link |
4949

50+
Cloudflare hosts both [studiosunandsea.com](https://studiosunandsea.com) and [eireneintentiocitta.hr](https://eireneintentiocitta.hr) from this GitHub repo. The environment variable **SITE_MODE** is used to drive different site behaviour where needed (*brand* => Studio Sun & Sea; *corp* => Eirene Intentio Citta d.o.o.).
51+
5052
---
5153

5254
## 3. Automated CI/CD Testing & Production Validation
@@ -59,7 +61,9 @@ Automated test pipeline is configured natively via GitHub Actions inside `.githu
5961
3. **Configuration Sync**: Verifies that `public/robots.txt` contains the correct absolute path matching the sitemap tracking string.
6062
4. **Link Health Integrity ([Linkinator](https://jbeckwith.com/projects/linkinator))**: Spins up a local background preview server instance to mimic Cloudflare's serving layer and crawls all links to guarantee **zero internal 404 broken routes**.
6163
5. **Automated Release Bumping**: Semantic versions (`npm version`) are calculated and pushed **only** upon successful validation landing on the `main` branch.
64+
* If the commit message contains [major] or [minor], it bumps accordingly.
65+
* Otherwise, it defaults to a standard patch bump (e.g. 0.0.2 -> 0.0.3).
6266
6. **AI Agent Scan**: Check conformance to standards for agentic commerce: [AI Agent Scan Remediation](../security/com.isitagentready.md)
6367

6468
---
65-
*Last Checked: June 2026*
69+
*Last Checked: September 2026*

doc/git-rulesets/nodestroy.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"id": 22620909,
3+
"name": "nodestroy",
4+
"target": "branch",
5+
"source_type": "Repository",
6+
"source": "miloshb/studio",
7+
"enforcement": "active",
8+
"conditions": {
9+
"ref_name": {
10+
"exclude": [],
11+
"include": [
12+
"refs/heads/stage",
13+
"~ALL"
14+
]
15+
}
16+
},
17+
"rules": [
18+
{
19+
"type": "deletion"
20+
},
21+
{
22+
"type": "non_fast_forward"
23+
}
24+
],
25+
"bypass_actors": []
26+
}

doc/git-rulesets/validate.json

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{
2+
"id": 22620910,
3+
"name": "validate",
4+
"target": "branch",
5+
"source_type": "Repository",
6+
"source": "miloshb/studio",
7+
"enforcement": "active",
8+
"conditions": {
9+
"ref_name": {
10+
"exclude": [],
11+
"include": [
12+
"refs/heads/stage",
13+
"refs/heads/main"
14+
]
15+
}
16+
},
17+
"rules": [
18+
{
19+
"type": "required_status_checks",
20+
"parameters": {
21+
"strict_required_status_checks_policy": true,
22+
"do_not_enforce_on_create": true,
23+
"required_status_checks": [
24+
{
25+
"context": "Cloudflare Pages: studio-sun-and-sea",
26+
"integration_id": 85455
27+
},
28+
{
29+
"context": "Cloudflare Pages: eirene-intentio-citta",
30+
"integration_id": 85455
31+
}
32+
]
33+
}
34+
},
35+
{
36+
"type": "pull_request",
37+
"parameters": {
38+
"required_approving_review_count": 0,
39+
"dismiss_stale_reviews_on_push": false,
40+
"required_reviewers": [],
41+
"require_code_owner_review": false,
42+
"require_last_push_approval": false,
43+
"required_review_thread_resolution": true,
44+
"require_extra_approval_for_unattributed_changes": true,
45+
"allowed_merge_methods": [
46+
"merge",
47+
"squash",
48+
"rebase"
49+
]
50+
}
51+
},
52+
{
53+
"type": "required_linear_history"
54+
},
55+
{
56+
"type": "code_quality",
57+
"parameters": {
58+
"severity": "errors"
59+
}
60+
},
61+
{
62+
"type": "code_scanning",
63+
"parameters": {
64+
"code_scanning_tools": [
65+
{
66+
"tool": "CodeQL",
67+
"security_alerts_threshold": "high_or_higher",
68+
"alerts_threshold": "errors"
69+
}
70+
]
71+
}
72+
},
73+
{
74+
"type": "copilot_code_review",
75+
"parameters": {
76+
"review_on_push": true,
77+
"review_draft_pull_requests": false
78+
}
79+
}
80+
],
81+
"bypass_actors": [
82+
{
83+
"actor_id": 5,
84+
"actor_type": "RepositoryRole",
85+
"bypass_mode": "always"
86+
}
87+
]
88+
}

public/styles/global.css

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,37 @@ img {
321321
object-fit: cover;
322322
border-radius: var(--radius-md);
323323
}
324+
325+
/* ---------------------------------
326+
11. TOOLTIPS
327+
---------------------------------- */
328+
329+
.tooltip {
330+
position: relative;
331+
cursor: help;
332+
border-bottom: 1px dotted #999;
333+
}
334+
335+
.tooltip .tooltiptext {
336+
visibility: hidden;
337+
opacity: 0;
338+
width: max-content;
339+
max-width: 240px;
340+
background-color: #333;
341+
color: #fff;
342+
text-align: left;
343+
padding: 6px 10px;
344+
border-radius: 4px;
345+
position: absolute;
346+
z-index: 10;
347+
bottom: 125%;
348+
left: 0;
349+
font-size: 0.85rem;
350+
line-height: 1.3;
351+
transition: opacity 0.2s ease-in-out;
352+
}
353+
354+
.tooltip:hover .tooltiptext {
355+
visibility: visible;
356+
opacity: 1;
357+
}

src/components/Footer.astro

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const footerTopOffset = footerOffset ? "var(--offset-lg)" : "0px";
2525

2626
<!-- Row 2: Left side -->
2727
<div class="footer-copy">
28-
© {new Date().getFullYear()} Studio Sun & Sea
28+
© {new Date().getFullYear()}
29+
<a href="https://eireneintentiocitta.hr">Eirene Intentio Citta d.o.o.</a>
30+
All rights reserved.
2931
</div>
3032

3133
<!-- Row 2: Right side -->

src/components/Header.astro

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
---
22
// src/components/Header.astro
33
import { ROUTES, LANGS, HEADER_ROUTE_KEYS, getLangRoot, getLangUrl } from "../data/routes.js";
4-
import { LANG_STORE_KEY } from "../data/constants.js";
4+
import { getSiteConfig, LANG_STORE_KEY } from "../data/config.ts";
55
import MindbodyLogin from "./widgets/MindbodyLoginLinkV1.astro";
66
7+
const site = getSiteConfig();
8+
79
const { lang, page } = Astro.props;
810
---
911

@@ -13,7 +15,7 @@ const { lang, page } = Astro.props;
1315
<div class="header-brand">
1416
<a class="brand" href={getLangRoot(lang)}>
1517
<img class="aspect-square" src="/favicon/favicon-48.png" alt="Studio Sun & Sea Logo" />
16-
Studio Sun & Sea
18+
{site.name}
1719
</a>
1820
</div>
1921

src/components/Hero.astro

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,41 @@
11
---
2-
const { lang } = Astro.props;
2+
import { getSiteConfig } from "../data/config.ts";
3+
4+
const site = getSiteConfig();
5+
const { lang } = Astro.props as { lang?: "en" | "de" };
36
47
const TEXT = {
5-
en: {
6-
title: "Breathe. Flow. Relax.",
7-
subtitle: "Mindful movement for a calm, connected life.",
8-
cta: "View Schedule",
9-
ctaHref: "/en/schedule-overview",
8+
brand: {
9+
en: {
10+
title: "Breathe. Flow. Relax.",
11+
subtitle: "Mindful movement for a calm, connected life.",
12+
cta: "View Schedule",
13+
ctaHref: "/en/schedule-overview",
14+
},
15+
de: {
16+
title: "Atme. Fließe. Entspanne.",
17+
subtitle: "Achtsame Bewegung für ein ruhiges, verbundenes Leben.",
18+
cta: "Stundenplan ansehen",
19+
ctaHref: "/de/schedule-overview",
20+
},
1021
},
11-
de: {
12-
title: "Atme. Fließe. Entspanne.",
13-
subtitle: "Achtsame Bewegung für ein ruhiges, verbundenes Leben.",
14-
cta: "Stundenplan ansehen",
15-
ctaHref: "/de/schedule-overview",
22+
corp: {
23+
en: {
24+
title: "Peace · Intention · Consciousness",
25+
subtitle: "Mindful movement for a calm, connected life.",
26+
cta: "Who we are?",
27+
ctaHref: "/en/about",
28+
},
29+
de: {
30+
title: "Frieden · Intention · Geist",
31+
subtitle: "Achtsame Bewegung für ein ruhiges, verbundenes Leben.",
32+
cta: "Wer sind wir?",
33+
ctaHref: "/de/about",
34+
},
1635
},
1736
};
1837
19-
const copy = TEXT[lang] ?? TEXT.en;
38+
const copy = TEXT[site.mode]?.[lang ?? "en"] || TEXT.brand[lang ?? "en"];
2039
---
2140

2241
<section class="hero">

src/components/Hreflang.astro

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
---
2+
// src/components/Hreflang.astro
23
import { HREFLANG } from "../data/routes.js";
4+
import { getSiteConfig } from "../data/config.ts";
5+
36
const { page } = Astro.props;
47
const urls = HREFLANG[page];
5-
const base = "https://studiosunandsea.com";
8+
const base = getSiteConfig().canonical;
69
---
710

811
<link rel="alternate" hreflang="en" href={base + urls.en} />

src/components/NextSteps.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { NEXT_STEPS_ROUTE_KEYS, ROUTES } from "../data/routes.js";
44
const { lang = "en", page = null } = Astro.props;
55
66
// Filter out the current page
7-
const stepKeys = NEXT_STEPS_ROUTE_KEYS.filter(key => key !== page);
7+
const stepKeys = (NEXT_STEPS_ROUTE_KEYS ?? []).filter(key => key !== page);
88
---
99

1010
<section class="next-steps">

0 commit comments

Comments
 (0)