Testimonails and Introscript updates

This commit is contained in:
2026-05-03 11:16:53 +12:00
parent 751c2d7e98
commit f27e0fed07
13 changed files with 191 additions and 23 deletions
+3 -4
View File
@@ -156,11 +156,10 @@ nginx/goodwalk.co.nz.svelte.conf.example
```
Important:
- The normal `deploy.ps1` flow does not deploy or reload the shared nginx stack.
- Copy the updated nginx config to `/docker/nginx/conf.d/goodwalk.co.nz.conf` and reload nginx once.
- The repo example now uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.
- `deploy.ps1` now copies the repo nginx config to `/docker/nginx/conf.d/goodwalk.co.nz.conf` and reloads the shared nginx container as part of deployment.
- The repo nginx config uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.
Then reload nginx:
Manual nginx commands, if you ever need them:
```bash
docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -t
+20 -1
View File
@@ -20,6 +20,10 @@ $SshConfigPath = Join-Path $LocalProjectPath 'ssh-config'
$RemoteDeploymentPath = '/docker/goodwalk-svelte'
$ComposeFileName = 'docker-compose.prod.yml'
$DockerProjectName = 'goodwalk-svelte'
$NginxConfigSource = 'nginx/goodwalk.co.nz.svelte.conf.example'
$NginxConfigTarget = '/docker/nginx/conf.d/goodwalk.co.nz.conf'
$NginxComposeFile = '/docker/nginx/docker-compose.yml'
$NginxProjectName = 'nginx'
# Optional deployment settings.
$VerifyUrl = 'https://www.goodwalk.co.nz/api/health'
@@ -161,6 +165,10 @@ Assert-NotBlank -Name 'LocalProjectPath' -Value $LocalProjectPath
Assert-NotBlank -Name 'RemoteDeploymentPath' -Value $RemoteDeploymentPath
Assert-NotBlank -Name 'ComposeFileName' -Value $ComposeFileName
Assert-NotBlank -Name 'DockerProjectName' -Value $DockerProjectName
Assert-NotBlank -Name 'NginxConfigSource' -Value $NginxConfigSource
Assert-NotBlank -Name 'NginxConfigTarget' -Value $NginxConfigTarget
Assert-NotBlank -Name 'NginxComposeFile' -Value $NginxComposeFile
Assert-NotBlank -Name 'NginxProjectName' -Value $NginxProjectName
if (-not [string]::IsNullOrWhiteSpace($Service)) {
$Service = $Service.Trim()
@@ -196,6 +204,8 @@ Write-Host "[deploy] Local project path: $LocalProjectPath"
Write-Host "[deploy] Remote deployment path: $RemoteDeploymentPath"
Write-Host "[deploy] Remote compose file: $ComposeFileName"
Write-Host "[deploy] Docker project name: $DockerProjectName"
Write-Host "[deploy] Shared nginx config: $NginxConfigTarget"
Write-Host "[deploy] Shared nginx compose file: $NginxComposeFile"
Write-Host "[deploy] SSH target: $sshTarget"
Write-Host "[deploy] SSH config: $SshConfigPath"
if (-not [string]::IsNullOrWhiteSpace($Service)) {
@@ -212,6 +222,7 @@ Write-Host ' - Only the top-level Goodwalk compose project will be updated.'
Write-Host ' - Legacy WordPress/onboarding compose files are not used.'
Write-Host ' - Remote .env files are preserved because they are not uploaded.'
Write-Host ' - No global Docker prune/stop/delete commands are used.'
Write-Host ' - Shared nginx will be updated and reloaded with the Docker-DNS-based config.'
if (-not $Force) {
$confirmation = Read-Host "Type DEPLOY to continue with the remote path '$RemoteDeploymentPath'"
@@ -253,7 +264,15 @@ try {
'--compose-file',
$ComposeFileName,
'--project-name',
$DockerProjectName
$DockerProjectName,
'--nginx-source',
$NginxConfigSource,
'--nginx-target',
$NginxConfigTarget,
'--nginx-compose-file',
$NginxComposeFile,
'--nginx-project-name',
$NginxProjectName
) + $(if (-not [string]::IsNullOrWhiteSpace($Service)) { @('--service', $Service) } else { @() }))
Write-Host ''
+1 -1
View File
@@ -380,7 +380,7 @@ def client_email(data: BookingSubmission) -> str:
style="max-width:600px;width:100%;border-radius:16px;overflow:hidden;
box-shadow:0 4px 24px rgba(0,0,0,0.08);">
{_logo_header(subtitle="Auckland’s favourite dog walking service")}
{_logo_header(subtitle="Professional dog walking services")}
<!-- Body -->
<tr>
+4 -4
View File
@@ -13,7 +13,7 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.2.11",
"@sveltejs/kit": "^2.17.1",
"@sveltejs/kit": "^2.59.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/svelte": "^5.3.1",
@@ -1271,9 +1271,9 @@
}
},
"node_modules/@sveltejs/kit": {
"version": "2.58.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.58.0.tgz",
"integrity": "sha512-kT9GCN8yJTkCK1W+Gi/bvGooWAM7y7WXP+yd+rf6QOIjyoK1ERPrMwSufXJUNu2pMWIqruhFvmz+LbOqsEmKmA==",
"version": "2.59.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.59.0.tgz",
"integrity": "sha512-WeJaGKvDf3uVQB4bnDHhM+BXCY34LC1v0HiPqnSpvNkjB54r8DAUP1rpk73s+5zprIirEKtUcVfgh6+fPODjzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
+1 -1
View File
@@ -17,7 +17,7 @@
},
"devDependencies": {
"@sveltejs/adapter-node": "^5.2.11",
"@sveltejs/kit": "^2.17.1",
"@sveltejs/kit": "^2.59.0",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/svelte": "^5.3.1",
+60
View File
@@ -6,12 +6,19 @@ DEPLOY_PATH=""
COMPOSE_FILE=""
PROJECT_NAME=""
SERVICE_NAME=""
NGINX_SOURCE=""
NGINX_TARGET=""
NGINX_COMPOSE_FILE=""
NGINX_PROJECT_NAME=""
usage() {
cat <<'EOF'
Usage:
deploy-remote.sh --archive <path> --deploy-path <path> --compose-file <name> --project-name <name>
deploy-remote.sh --archive <path> --deploy-path <path> --compose-file <name> --project-name <name> [--service <name>]
deploy-remote.sh --archive <path> --deploy-path <path> --compose-file <name> --project-name <name> \
[--service <name>] [--nginx-source <path>] [--nginx-target <path>] \
[--nginx-compose-file <path>] [--nginx-project-name <name>]
This script only updates the main Goodwalk compose project at the specified
deployment path. It does not touch unrelated Docker projects or global Docker
@@ -46,6 +53,22 @@ while [[ $# -gt 0 ]]; do
SERVICE_NAME="${2:-}"
shift 2
;;
--nginx-source)
NGINX_SOURCE="${2:-}"
shift 2
;;
--nginx-target)
NGINX_TARGET="${2:-}"
shift 2
;;
--nginx-compose-file)
NGINX_COMPOSE_FILE="${2:-}"
shift 2
;;
--nginx-project-name)
NGINX_PROJECT_NAME="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
@@ -66,6 +89,22 @@ fi
[[ "$DEPLOY_PATH" != "/" ]] || fail "Refusing to deploy to /"
[[ -f "$ARCHIVE_PATH" ]] || fail "Archive not found: $ARCHIVE_PATH"
nginx_args=("$NGINX_SOURCE" "$NGINX_TARGET" "$NGINX_COMPOSE_FILE" "$NGINX_PROJECT_NAME")
nginx_args_present=0
for value in "${nginx_args[@]}"; do
if [[ -n "$value" ]]; then
nginx_args_present=1
break
fi
done
if (( nginx_args_present )); then
[[ -n "$NGINX_SOURCE" ]] || fail "--nginx-source is required when nginx deployment is enabled"
[[ -n "$NGINX_TARGET" ]] || fail "--nginx-target is required when nginx deployment is enabled"
[[ -n "$NGINX_COMPOSE_FILE" ]] || fail "--nginx-compose-file is required when nginx deployment is enabled"
[[ -n "$NGINX_PROJECT_NAME" ]] || fail "--nginx-project-name is required when nginx deployment is enabled"
fi
if docker compose version >/dev/null 2>&1; then
COMPOSE_CMD=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
@@ -89,6 +128,12 @@ echo "[deploy-remote] Docker project: $PROJECT_NAME"
if [[ -n "$SERVICE_NAME" ]]; then
echo "[deploy-remote] Target service: $SERVICE_NAME"
fi
if (( nginx_args_present )); then
echo "[deploy-remote] Nginx config source: $NGINX_SOURCE"
echo "[deploy-remote] Nginx config target: $NGINX_TARGET"
echo "[deploy-remote] Nginx compose file: $NGINX_COMPOSE_FILE"
echo "[deploy-remote] Nginx project: $NGINX_PROJECT_NAME"
fi
echo "[deploy-remote] Staging archive in: $STAGING_DIR"
mkdir -p "$DEPLOY_PATH"
@@ -171,4 +216,19 @@ if [[ -z "$SERVICE_NAME" || "$SERVICE_NAME" == "app" || "$SERVICE_NAME" == "db"
"${COMPOSE_CMD[@]}" -p "$PROJECT_NAME" -f "$COMPOSE_FILE" exec -T app node scripts/sync-homepage-content.mjs
fi
if (( nginx_args_present )); then
[[ -f "$DEPLOY_PATH/$NGINX_SOURCE" ]] || fail "Nginx config missing from deployment payload: $DEPLOY_PATH/$NGINX_SOURCE"
[[ -f "$NGINX_COMPOSE_FILE" ]] || fail "Nginx compose file was not found on the server: $NGINX_COMPOSE_FILE"
echo "[deploy-remote] Updating shared nginx config to avoid stale container IPs"
mkdir -p "$(dirname "$NGINX_TARGET")"
cp "$DEPLOY_PATH/$NGINX_SOURCE" "$NGINX_TARGET"
echo "[deploy-remote] Validating nginx configuration"
"${COMPOSE_CMD[@]}" -p "$NGINX_PROJECT_NAME" -f "$NGINX_COMPOSE_FILE" exec -T nginx nginx -t
echo "[deploy-remote] Reloading shared nginx"
"${COMPOSE_CMD[@]}" -p "$NGINX_PROJECT_NAME" -f "$NGINX_COMPOSE_FILE" exec -T nginx nginx -s reload
fi
echo "[deploy-remote] Remote deployment finished"
+16 -4
View File
@@ -10,9 +10,21 @@
<div id="intro">
<div class="intro-inner">
<div class="intro-trust-badge">
<div class="intro-trust-mark" aria-hidden="true">
<Icon name="fab fa-google" />
</div>
<a
class="intro-trust-mark intro-trust-mark-link"
href={intro.reviewCta.href}
target="_blank"
rel="noopener"
aria-label="Read our Google reviews"
>
<img
class="intro-google-logo"
src="/images/google-g-logo.svg"
alt=""
width="28"
height="29"
/>
</a>
<div class="intro-trust-copy">
<p>{intro.text}</p>
@@ -24,7 +36,7 @@
{/each}
</div>
<a href={intro.reviewCta.href} target="_blank" rel="noopener">
<a class="intro-trust-cta" href={intro.reviewCta.href} target="_blank" rel="noopener">
{intro.reviewCta.label}
</a>
</div>
+1 -1
View File
@@ -67,7 +67,7 @@
<div class="modal-divider"></div>
<p class="modal-sub">
In the meantime, feel free to follow along on Instagram for daily walks and happy dogs.
In the meantime, feel free to follow along on Instagram for daily walks and happy dogs!
</p>
<button class="modal-btn" type="button" on:click={onClose}>
@@ -8,9 +8,9 @@
export let testimonials: TestimonialContent[];
export let heading = 'Why people choose us!';
export let blurb =
'Real dogs, real routines, trusted by happy owners. Follow along on Instagram to see the Tiny Gang out on their daily adventures.';
"Happy owners, even happier dogs. Our Auckland dog walking clients love what the Tiny Gang brings to their dog's routine — and you can see why. Follow along on Instagram for daily adventures, wagging tails and the odd zoomie";
export let instagramHref = 'https://www.instagram.com/goodwalk.nz/';
export let instagramLabel = '@goodwalk.nz';
export let instagramLabel = 'goodwalk.nz';
type TestimonialSlide = TestimonialContent & { imageUrl: string };
+2 -2
View File
@@ -50,8 +50,8 @@ export const homepageContent: HomePageContent = {
title: 'Happy pets,',
subtitle: 'happy humans',
body:
'Offering tailored pack walks for small and medium dogs, and one-on-one walks for large breeds. Our walkers give personalised attention to each dog, easing stress, anxiety and ensuring a quality experience. Our expertise in small-medium breeds ensures tailored care for their unique needs. Join our',
emphasis: 'TINY GANG!',
'Professional dog walking services in Auckland for small, medium and large breeds. Our experienced walkers provide tailored pack walks for smaller dogs and one-on-one walks for larger breeds - giving every dog the personalised attention they deserve. We specialise in understanding the unique needs of small-to-medium breeds, helping to ease stress and anxiety while keeping tails wagging. Ready to join our',
emphasis: 'TINY GANG?',
cta: { label: 'Book now', href: '#newlead', variant: 'green' },
imageUrl: '/images/auckland-dog-walking-happy-dogs-happy-humans.webp',
imageAlt: 'Woman cuddling a dog for Goodwalk Auckland dog walking services'
+5 -1
View File
@@ -299,6 +299,10 @@
font-size: 21px;
}
.intro-google-logo {
width: 24px;
}
#intro p {
font-size: 17px;
line-height: 1.45;
@@ -312,7 +316,7 @@
gap: 10px;
}
#intro a {
.intro-trust-cta {
gap: 8px;
padding: 8px 14px;
font-size: 15px;
+70 -2
View File
@@ -67,6 +67,7 @@ section {
.intro-trust-mark {
display: inline-flex;
position: relative;
align-items: center;
justify-content: center;
width: 56px;
@@ -75,9 +76,50 @@ section {
background: #fff;
color: #e00706;
font-size: 24px;
overflow: hidden;
box-shadow: inset 0 0 0 1px rgba(14, 27, 41, 0.08);
}
.intro-trust-mark-link {
text-decoration: none;
isolation: isolate;
transition:
transform 0.22s cubic-bezier(0.22, 1, 0.36, 1),
box-shadow 0.22s ease;
}
.intro-trust-mark-link::after {
content: '';
position: absolute;
inset: -30% 35%;
background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.2) 30%, rgba(255, 255, 255, 0.92) 50%, rgba(255, 255, 255, 0.2) 70%, transparent 100%);
transform: translateX(-220%) rotate(18deg);
opacity: 0;
pointer-events: none;
animation: introGoogleShine 4.8s ease-in-out infinite;
}
.intro-trust-mark-link:hover,
.intro-trust-mark-link:focus-visible {
transform: translateY(-1px) scale(1.04);
box-shadow:
inset 0 0 0 1px rgba(14, 27, 41, 0.08),
0 10px 24px rgba(17, 20, 24, 0.12);
}
.intro-trust-mark-link:focus-visible {
outline: 2px solid rgba(10, 48, 78, 0.28);
outline-offset: 3px;
}
.intro-google-logo {
display: block;
position: relative;
z-index: 1;
width: 28px;
height: auto;
}
.intro-trust-copy {
min-width: 0;
}
@@ -107,7 +149,7 @@ section {
font-size: 14px;
}
#intro a {
.intro-trust-cta {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -121,11 +163,37 @@ section {
box-shadow: inset 0 0 0 1px rgba(14, 27, 41, 0.08);
}
#intro a .icon {
.intro-trust-cta .icon {
color: #e00706;
font-size: 20px;
}
@keyframes introGoogleShine {
0%,
64%,
100% {
transform: translateX(-220%) rotate(18deg);
opacity: 0;
}
72% {
opacity: 1;
}
84% {
transform: translateX(220%) rotate(18deg);
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.intro-trust-mark-link,
.intro-trust-mark-link::after {
animation: none;
transition: none;
}
}
#promise,
#testimonials,
#info {
+6
View File
@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 262">
<path fill="#4285F4" d="M255.68 133.53c0-8.89-.8-17.43-2.29-25.63H130.8v48.48h70.06c-3.02 16.31-12.2 30.12-25.99 39.35v32.65h41.95c24.54-22.6 38.86-55.92 38.86-94.85Z"/>
<path fill="#34A853" d="M130.8 261.1c35.1 0 64.53-11.63 86.04-31.55l-41.95-32.65c-11.63 7.79-26.53 12.38-44.09 12.38-33.88 0-62.58-22.88-72.83-53.62H14.6v33.67c21.39 42.42 65.29 71.77 116.2 71.77Z"/>
<path fill="#FBBC05" d="M57.97 155.65c-2.61-7.79-4.09-16.11-4.09-24.65s1.48-16.86 4.09-24.65V72.68H14.6C5.28 91.24 0 110.62 0 131s5.28 39.76 14.6 58.32l43.37-33.67Z"/>
<path fill="#EA4335" d="M130.8 52.72c19.08 0 36.23 6.57 49.72 19.48l37.29-37.29C195.28 13.35 165.87 0 130.8 0 79.89 0 35.99 29.35 14.6 72.68l43.37 33.67c10.25-30.74 38.95-53.63 72.83-53.63Z"/>
</svg>

After

Width:  |  Height:  |  Size: 809 B