Skip to content

Verify About image upload #3

Verify About image upload

Verify About image upload #3

name: Finalize About PR
on:
push:
branches: [agent/about-trust-page-v1]
permissions:
contents: write
jobs:
finalize:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: agent/about-trust-page-v1
fetch-depth: 0
- name: Merge main and finalize
shell: bash
run: |
set -euo pipefail
git fetch origin main
git merge --no-edit origin/main
python -m pip install --quiet Pillow
python - <<'PY'
from pathlib import Path
from PIL import Image,ImageEnhance,ImageFilter
import base64,re
R=Path('.')
d=''.join((R/f'assets/img/about/owner-photo.part-{i}.txt').read_text().strip() for i in range(1,5))
src=R/'assets/img/about/.src.jpg'; src.write_bytes(base64.b64decode(d))
out=R/'assets/img/about/tetiana-financial-stream-ceo.webp'
with Image.open(src) as im:
im=im.convert('RGB'); w,h=im.size; r=w/h
if r>.8:
nw=round(h*.8); x=(w-nw)//2; im=im.crop((x,0,x+nw,h))
elif r<.8:
nh=round(w/.8); y=(h-nh)//2; im=im.crop((0,y,w,y+nh))
im=im.resize((1200,1500),Image.Resampling.LANCZOS)
im=ImageEnhance.Contrast(im).enhance(1.025)
im=ImageEnhance.Color(im).enhance(1.015)
im=im.filter(ImageFilter.UnsharpMask(1.25,82,3))
im.save(out,'WEBP',quality=84,method=6)
src.unlink()
logoH='<picture class="brand-logo-picture"><source srcset="/assets/brand/financial-stream/logo-primary-web.webp" type="image/webp"><img class="logo-image" src="/assets/brand/financial-stream/logo-primary-web.png" alt="Financial Stream LLC logo" width="640" height="203" decoding="async"></picture>'
logoF='<picture class="brand-logo-picture"><source srcset="/assets/brand/financial-stream/logo-primary-web.webp" type="image/webp"><img class="footer-logo" src="/assets/brand/financial-stream/logo-primary-web.png" alt="Financial Stream LLC" width="640" height="203" decoding="async"></picture>'
def page(path,ru=False):
p=Path(path); s=p.read_text()
s=re.sub(r'<img class="logo-image" src="/assets/brand/financial-stream/logo-primary-web\.png" alt="Financial Stream LLC" width="640" height="203">',logoH,s,count=1)
s=re.sub(r'<img class="footer-logo" src="/assets/brand/financial-stream/logo-primary-web\.png" alt="Financial Stream LLC" width="640" height="203">',logoF,s,count=1)
s=re.sub(r'<script src="(?:\.\./)+assets/js/about-photo\.js"></script>','',s)
if not ru:
old='<img src="../assets/img/about/owner-photo-fallback.svg" width="480" height="600" alt="Tetiana Horb, CEO of Financial Stream LLC, seated in a professional office" data-owner-photo>'
new='<picture><source srcset="../assets/img/about/tetiana-financial-stream-ceo.webp" type="image/webp"><img src="../assets/img/about/tetiana-financial-stream-ceo.webp" width="1200" height="1500" fetchpriority="high" decoding="async" alt="Tetiana Horb, CEO of Financial Stream LLC, seated in a professional office setting"></picture>'
s=s.replace(old,new).replace('<div class="header-actions"><a href="/ru/about/">RU</a><a class="btn btn-primary"','<div class="header-actions"><a class="btn btn-primary"')
s=s.replace('<h3>Tetiana Horb</h3>','<h2 class="about-owner-note__name">Tetiana Horb</h2>',1)
mark='</section><section class="about-section"><div class="container"><div class="about-section__heading fade-in"><div class="eyebrow">Why Financial Stream exists</div>'
note='</section><section class="about-section about-section--ceo-note"><div class="container"><div class="about-note fade-in"><div class="about-note__head"><div><div class="eyebrow">Leadership principle</div><h2>A note from the CEO</h2></div><div class="about-note__identity"><strong>Tetiana Horb</strong><span>CEO, Financial Stream LLC</span></div></div><p>Financial Stream is built around organized records, clear communication, and practical next steps. Every engagement begins with understanding the client’s actual situation before deciding what needs to happen next.</p><small>Company principle. This is not presented as a personal quotation.</small></div></div>'+mark
if 'A note from the CEO' not in s:s=s.replace(mark,note,1)
who='Tetiana Horb'
else:
old='<img src="../../assets/img/about/owner-photo-fallback.svg" width="480" height="600" alt="Татьяна Горб, CEO Financial Stream LLC, в профессиональной офисной обстановке" data-owner-photo>'
new='<picture><source srcset="../../assets/img/about/tetiana-financial-stream-ceo.webp" type="image/webp"><img src="../../assets/img/about/tetiana-financial-stream-ceo.webp" width="1200" height="1500" fetchpriority="high" decoding="async" alt="Татьяна Горб, CEO Financial Stream LLC, в профессиональной офисной обстановке"></picture>'
s=s.replace(old,new).replace('<div class="header-actions"><a href="/about/">EN</a><a class="btn btn-primary"','<div class="header-actions"><a class="btn btn-primary"')
s=s.replace('<h3>Татьяна Горб</h3>','<h2 class="about-owner-note__name">Татьяна Горб</h2>',1)
mark='</section><section class="about-section"><div class="container"><div class="about-section__heading fade-in"><div class="eyebrow">Зачем существует Financial Stream</div>'
note='</section><section class="about-section about-section--ceo-note"><div class="container"><div class="about-note fade-in"><div class="about-note__head"><div><div class="eyebrow">Принцип руководства</div><h2>Слово руководителя</h2></div><div class="about-note__identity"><strong>Татьяна Горб</strong><span>CEO, Financial Stream LLC</span></div></div><p>Работа Financial Stream строится вокруг порядка в документах, понятной коммуникации и практических следующих шагов. Сначала важно разобраться в реальной ситуации клиента, а затем определить, что именно необходимо сделать дальше.</p><small>Принцип работы компании. Текст не оформлен как личная цитата.</small></div></div>'+mark
if 'Слово руководителя' not in s:s=s.replace(mark,note,1)
who='Татьяна Горб'
needle='"areaServed":"US","availableLanguage":["English","Russian"]'
value='"areaServed":"US","address":{"@type":"PostalAddress","addressLocality":"Federal Way","addressRegion":"WA","addressCountry":"US"},"availableLanguage":["English","Russian"],"employee":{"@type":"Person","name":"'+who+'","jobTitle":"CEO"}'
s=s.replace(needle,value,1); p.write_text(s)
page('about/index.html'); page('ru/about/index.html',True)
def home(path,href,label,services,navtitle):
p=Path(path); s=p.read_text(); name='Services' if label=='About' else 'Услуги'
a=f'<a href="{services}">{name}</a>'; b=a+f'\n <a href="{href}">{label}</a>'
if f'<a href="{href}">{label}</a>' not in s:s=s.replace(a,b,2)
h=f'<h3 class="footer-title">{navtitle}</h3>\n <ul class="footer-links">'
if s.count(f'<a href="{href}">{label}</a>')<3:s=s.replace(h,h+f'\n <li><a href="{href}">{label}</a></li>',1)
p.write_text(s)
home('index.html','/about/','About','/services/','Navigation')
home('ru/index.html','/ru/about/','О нас','/ru/services/','Навигация')
PY
cat >> assets/css/about.css <<'CSS'
.about-page .about-hero__copy,.about-page .about-intro-grid>*,.about-page .about-section__heading,.about-page .about-service-card>div,.about-page .about-note__head>*{min-width:0}.about-page .about-portrait__frame picture{display:block;width:100%;height:100%}.about-page .about-portrait__frame picture img{width:100%;height:100%;object-fit:cover;object-position:50% 34%}.about-page .about-owner-note__name{margin:18px 0 8px;font-size:clamp(1.75rem,3vw,2.6rem)}.about-section--ceo-note{padding:clamp(68px,8vw,112px) 0}.about-note{padding:clamp(30px,5vw,62px);border:1px solid rgba(183,154,102,.28);border-radius:30px;background:linear-gradient(135deg,rgba(255,255,255,.98),rgba(242,238,231,.72));box-shadow:0 24px 64px rgba(7,29,47,.09)}.about-note__head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:28px;align-items:end}.about-note h2{font-size:clamp(2.2rem,4.5vw,4.5rem)}.about-note__identity{display:grid;gap:3px;padding:14px 18px;border-left:2px solid #b79a66}.about-note__identity strong{color:#0a2033}.about-note__identity span{color:#64727e;font-size:.86rem}.about-note>p{max-width:920px;margin-top:30px;color:#253b4c;font-size:clamp(1.18rem,2vw,1.65rem);line-height:1.62}.about-note>small{display:block;margin-top:18px;color:#6c7781}.about-service-card:focus-visible{outline:3px solid rgba(29,111,157,.42);outline-offset:4px}.about-page .site-header{transition:transform .24s ease}.about-page .site-header.is-hidden-mobile{transform:translateY(-110%)}
@media(max-width:900px){.about-page .site-header__inner>.header-actions{display:flex;gap:8px}.about-page .site-header__inner>.header-actions .lang-switch{display:flex!important}.about-page .site-header__inner>.header-actions>.btn{display:none!important}.about-page .site-header__panel .header-actions>a:not(.btn),.about-page .site-header__panel .lang-switch{display:none!important}.about-page .site-header__panel .header-actions{justify-content:stretch}.about-page .site-header__panel .header-actions .btn{width:100%}.about-note__head{grid-template-columns:1fr;align-items:start}}
@media(max-width:430px){.about-page .container{width:calc(100% - 28px)}.about-page .logo-image{width:min(154px,44vw);height:auto}.about-page .lang-switch a{min-width:40px;min-height:40px;padding:8px 10px}.about-page .menu-toggle{min-width:44px;min-height:42px;padding-inline:10px}.about-page .about-hero h1{overflow-wrap:anywhere}.about-page .about-hero__actions .btn,.about-page .about-final__actions .btn{width:100%;white-space:normal;text-align:center}.about-page .about-service-card{grid-template-columns:auto minmax(0,1fr)}.about-page .about-service-card__arrow{display:none}}
CSS
rm -f assets/js/about-photo.js assets/img/about/owner-photo.part-{1,2,3,4}.txt assets/img/about/owner-photo-fallback.svg .github/workflows/about-finalize.yml
python - <<'PY'
from pathlib import Path
from PIL import Image
for f in ['about/index.html','ru/about/index.html']:
s=Path(f).read_text(); assert s.count('<h1')==1 and s.count('about-service-card')>=6 and s.count('class="lang-switch"')==1
assert 'CEO, Financial Stream LLC' in s and 'about-photo.js' not in s and 'owner-photo.part-' not in s and 'owner-photo-fallback.svg' not in s
assert 'Practicing Accountant' not in s and 'practicing accountant' not in s
with Image.open('assets/img/about/tetiana-financial-stream-ceo.webp') as im: assert im.size==(1200,1500) and im.format=='WEBP'
assert Path('index.html').read_text().count('href="/about/">About</a>')>=3
assert Path('ru/index.html').read_text().count('href="/ru/about/">О нас</a>')>=3
assert '/about/' in Path('sitemap.xml').read_text() and '/ru/about/' in Path('sitemap.xml').read_text()
PY
if git diff --name-only origin/main...HEAD | grep -E '(^|/)blog/|article'; then exit 1; fi
git config user.name "Financial Stream Automation"
git config user.email "actions@users.noreply.github.com"
git add -A
git commit -m "Finalize bilingual About trust pages"
git push origin HEAD:agent/about-trust-page-v1