Compare commits

..
Author SHA1 Message Date
DeCentN2Madness 96d3c138f6 refactor(migration): remove obsolete mirror extraction tooling
- delete extraction scripts that depended on the removed local mirror
- remove stale extract npm scripts and migration-brief references
- drop the old mirror ignore rule from .gitignore
- update reports and redirect reasons to use live-source wording
2026-07-13 12:49:58 -07:00
DeCentN2Madness 6648d1d7d5 fix(seo): noindex staging builds by default
- add PUBLIC_ALLOW_INDEXING as an explicit production indexing opt-in
- emit robots meta noindex,nofollow unless indexing is enabled
- generate robots.txt from the same indexing flag
- document staging SEO behavior for migration preview hosts
2026-07-13 12:48:14 -07:00
DeCentN2Madness 9c391c8c05 refactor(component): rename contact obfuscation component 2026-07-02 15:14:51 -07:00
DeCentN2Madness 77b83f5d21 feat(page): match live contact page layout 2026-07-02 15:13:52 -07:00
DeCentN2Madness 8c9c581cc0 feat(brand): add and switch to cog favicon 2026-07-02 13:31:04 -07:00
DeCentN2Madness 46090e9159 chore(docs): remove local mirror references, use live site only
Deleted the www.azinstitute4autism.com mirror directory and scrubbed all
references to it from AGENTS.md, MIGRATION_BRIEF.md, www/README.md, and
www/original/README.md. The live public site is now the sole source of
truth with no local mirror fallback.
2026-07-02 13:31:04 -07:00
DeCentN2Madness fd8e12f925 feat(component): add email obfuscation component 2026-07-02 13:31:04 -07:00
DeCentN2Madness b73e92a8a4 chore(img): add higher resolution image to social club page 2026-06-30 20:20:34 -07:00
DeCentN2Madness a3f7f90fdc fix(layout): allow images up to 300x300 in services page contents 2026-06-30 20:14:17 -07:00
DeCentN2Madness a39caf1a34 fix(content): clarify aba therapy section heading 2026-06-30 15:31:53 -07:00
DeCentN2Madness 38c1f78d4f chore(ai): 🔨 move codex command flag to --profile from --profile-2 2026-06-30 15:11:30 -07:00
DeCentN2Madness 5cbe055c34 fix(styles): adjust service page image margin and prose heading spacing
Removes bottom margin from floated service page images (pages.css) and
tightens h2/h3 top margin in prose from 2em to 1.75em (blog.css).
2026-06-25 20:59:40 -07:00
DeCentN2Madness 2f208aa6e4 fix(content): add center prop to MDX page buttons
Adds center to every <Button> in content MDX files that previously relied
on the removed .button-center global class. Also includes minor content
cleanups in the same files: eyebrow markup for section labels in
aba-therapy.mdx, and removal of extra blank lines between list items in
learner-social-club.mdx.
2026-06-25 20:59:11 -07:00
DeCentN2Madness c6202d2ac6 refactor(button): consolidate button styles into Button.astro
Extends Button.astro with a center prop, native <button> element support
(type, disabled, aria-describedby), harmonised padding (.65rem), and
transition. Removes global .button, .button-small, .button-light, and
.button-center rules from components.css, layout.css, and typography.css.
Converts all inline class="button" usages across Header, HomeHero,
HomeFinancialHelp, HomeServicesIntro, FormShell, TeamPage, CareersPage,
and FaqPage to the <Button> component. Updates three scoped style
selectors to :global() to reach the child component's elements.
2026-06-25 20:59:02 -07:00
DeCentN2Madness a3f666c974 refactor(styles): move service-page rules into a dedicated pages stylesheet
- keep blog.css focused on blog/article styling only
- move the existing .service-page rules unchanged into pages.css
- import pages.css from the shared global stylesheet
- preserve the current service-page layout and responsive behavior
2026-06-22 11:08:22 -07:00
DeCentN2Madness 4a7045a1cb refactor(cleanup): remove unused components and stale docs
- delete components that no longer have any references in the current source tree
- remove the stale Link component example from the README
- drop the leftover service-page heading rule from the blog stylesheet
- keep the repo aligned with the current component graph instead of historical leftovers
2026-06-20 12:07:06 -07:00
DeCentN2Madness a048d395f7 refactor(typography): standardize eyebrow labels across page shells
- consolidate the shared eyebrow label styling into the global typography layer
- replace the old script-label usage in page hero, home hero, FAQ, and team shells
- keep the next heading flush under the label across all affected page types
2026-06-20 12:05:24 -07:00
DeCentN2Madness 9398321fac refactor(components): separate page shells from reusable components
Additional info:
  - move page-specific shells into src/components/pages/
  - keep reusable building blocks and home sections in their existing component folders
  - update PageLayout and the home route imports to the new page-shell paths
  - preserve current page behavior while making the component tree easier to navigate
2026-06-19 21:03:27 -07:00
DeCentN2Madness d348174f95 fix(typography): improve global link colour and hover state
Changes the base link rule from a plain blue primary colour to the
site's accent orange (--color-accent-strong) with no underline, matching
the live site's link treatment. Adds a :hover/:active state that shifts
to the lighter accent, and carves out a.button so CTA buttons keep their
primary-colour label text.
2026-06-17 14:22:47 -07:00
DeCentN2Madness d0d8222e40 feat(faqs): wire FaqPage component and reformat faqs.mdx content
PageLayout now imports FaqPage and routes the faqs slug through it,
passing the page content as a slot (accordion and search are handled by
the component). Also passes subtitle="FAQs" to PageHero for the split
title/subtitle hero treatment.

faqs.mdx is cleaned up to match what FaqPage.astro expects as input:
- removes the old Button import and the duplicate h2 headings that are
  now rendered by the component itself
- reformats all answers from loose markdown text to explicit HTML
  elements (p, ul, ol, h4, h5) so the accordion parser receives
  well-formed nodes rather than flat text runs
2026-06-17 14:22:37 -07:00
DeCentN2Madness ed2bda5c02 feat(page-hero): add optional subtitle prop with mobile heading backdrop
Extends PageHero with a subtitle?: string prop rendered as an h2 beneath
the h1. On image-backed heroes the heading group gets a semi-transparent
white backdrop (display: inline-block; background: #fffb) so the text
stays readable against busy photography at mobile widths. Subtitle h2
inherits the page-hero heading font at a slightly smaller fluid size.
2026-06-17 14:21:28 -07:00
DeCentN2Madness 96d829accb fix(faqs): add orange focus ring to search input matching live site
The live site applies border-color #ffbd59 (--color-accent) to the
search input on focus with no additional outline. Adds:

  .hs-search-field__input:focus { border-color: var(--color-accent); outline: none; }

Also applies button-center to the secondary CTA button and removes the
now-redundant text-align/max-width rules from .faq-cta-secondary
(centering is handled by the button-center utility).
2026-06-17 14:17:59 -07:00
DeCentN2Madness 67951fa031 refactor(faqs): replace decorative search icon with live site button-inline form
The original search field used a decorative <div> with an outline SVG
icon floating outside the <form> — a HubSpot pattern that made the icon
non-interactive and the label invisible only by luck.

Replaces it with the structure the live site actually uses:
- hs-search-field__bar--button-inline with a real <button type="button">
  containing the filled FA-style magnifying-glass SVG from the live page
- Flexbox form so the input and button are proper flex siblings rather
  than one element positioned over another
- Rectangular 4px-radius border matching the live widget (was pill 999px)
- Defines .sr-only locally so the label is correctly hidden
- Changes name from "term" to "q" and placeholder to "Search" to match
2026-06-17 14:16:57 -07:00
DeCentN2Madness c98a51795d feat(faqs): add FaqPage component with accordion, search, and CTA sections
Introduces FaqPage.astro, a client-side component that:
- Parses MDX-sourced h3/answer pairs into animated <details> accordions
  (single-open, smooth height transitions)
- Provides a live text filter that hides non-matching questions as the
  user types
- Includes a pill-shaped HubSpot-style search field with decorative icon
- Closes with two CTA bands (primary blue and secondary white)
2026-06-17 14:12:38 -07:00
79 changed files with 1686 additions and 1404 deletions
-3
View File
@@ -58,6 +58,3 @@ temp/
.DS_Store .DS_Store
Thumbs.db Thumbs.db
Desktop.ini Desktop.ini
# Read-only wget mirror used as migration source material
/www.azinstitute4autism.com/
+8 -32
View File
@@ -13,42 +13,20 @@ content only after verifying it against the live public site.
## Project ## Project
This repository contains a mirrored copy of the Arizona Institute for Autism website.
Raw mirror source:
```txt
./www.azinstitute4autism.com
```
New Astro site target: New Astro site target:
```txt ```txt
./www ./www
``` ```
The mirror was created with:
```sh
wget --mirror --page-requisites --adjust-extension --convert-links --no-parent https://www.azinstitute4autism.com
```
Do not modify, move, rename, or delete `./www.azinstitute4autism.com`.
Treat the mirror as read-only raw source material.
The live public website is the single source of truth: The live public website is the single source of truth:
```txt ```txt
https://www.azinstitute4autism.com https://www.azinstitute4autism.com
``` ```
Use the mirror as a convenient local extraction and inspection aid only. The Verify content, design, URLs, metadata, assets, and responsive behavior against
mirror may contain stale, missing, rewritten, or incorrectly downloaded the live public site before treating them as authoritative.
content and assets. Verify content, design, URLs, metadata, assets, and
responsive behavior against the live public site before treating them as
authoritative. When the live site and mirror disagree, follow the live site and
document material discrepancies.
## Primary goal ## Primary goal
@@ -221,10 +199,9 @@ Favor:
Before implementing a page family or shared component: Before implementing a page family or shared component:
1. Inspect the live page and its HTML, CSS, assets, and responsive behavior. 1. Inspect the live page and its HTML, CSS, assets, and responsive behavior.
2. Use the mirror to accelerate local extraction and inspection. 2. Resolve any discrepancy in favor of the live public site.
3. Resolve any discrepancy in favor of the live public site. 3. Record the source structure and important visual details.
4. Record the source structure and important visual details. 4. Identify which patterns are truly shared and which are page-specific.
5. Identify which patterns are truly shared and which are page-specific.
After implementation, compare the Astro output with the live public site at After implementation, compare the Astro output with the live public site at
representative desktop and mobile viewport widths. Check the full page, not representative desktop and mobile viewport widths. Check the full page, not
@@ -365,10 +342,9 @@ reports/migration-summary.md
Before large filesystem changes: Before large filesystem changes:
1. Inspect the live public site. 1. Inspect the live public site.
2. Inspect the mirror and identify relevant discrepancies. 2. Inspect the relevant source HTML, CSS, and assets in detail.
3. Inspect the relevant source HTML, CSS, and assets in detail. 3. Summarize the implementation and visual-validation plan.
4. Summarize the implementation and visual-validation plan. 4. Proceed methodically.
5. Proceed methodically.
At the end of a task, summarize: At the end of a task, summarize:
+20 -79
View File
@@ -7,21 +7,15 @@ brief provides detailed implementation guidance. If any wording here appears
to conflict with `AGENTS.md`, follow `AGENTS.md` and correct this brief before to conflict with `AGENTS.md`, follow `AGENTS.md` and correct this brief before
continuing. continuing.
This is a fidelity-first migration, not a redesign. The raw mirror is a This is a fidelity-first migration, not a redesign. The live public site is the
convenient local extraction and inspection aid, but the live public site is the
single content and visual source of truth. The `migration-foundation` branch single content and visual source of truth. The `migration-foundation` branch
may be consulted for nonvisual tooling and recovered content, but it must not may be consulted for nonvisual tooling and recovered content, but it must not
be used as the visual baseline. be used as the visual baseline.
## Task ## Task
Migrate the public Arizona Institute for Autism website from a mirrored HubSpot-generated static copy into a clean, maintainable Astro + TypeScript site. Migrate the public Arizona Institute for Autism website into a clean,
maintainable Astro + TypeScript site.
Raw mirrored source:
```txt
./www.azinstitute4autism.com
```
New Astro project target: New Astro project target:
@@ -29,12 +23,6 @@ New Astro project target:
./www ./www
``` ```
The raw mirror was created with:
```sh
wget --mirror --page-requisites --adjust-extension --convert-links --no-parent https://www.azinstitute4autism.com
```
There is no HubSpot export, no HubSpot CLI access, and no HubSpot API access. There is no HubSpot export, no HubSpot CLI access, and no HubSpot API access.
Use the live public website as the single source of truth: Use the live public website as the single source of truth:
@@ -43,15 +31,9 @@ Use the live public website as the single source of truth:
https://www.azinstitute4autism.com https://www.azinstitute4autism.com
``` ```
Use the local mirror as a convenient extraction and inspection aid. It may Verify content, design, URLs, metadata, assets, and responsive behavior against
contain stale, missing, rewritten, or incorrectly downloaded content and the live site. If the live site is temporarily unavailable, work that depends
assets. Verify content, design, URLs, metadata, assets, and responsive behavior on its authority must remain explicitly unverified.
against the live site. When the live site and mirror disagree, follow the live
site and document material discrepancies.
If the live site is temporarily unavailable, work that depends on its authority
must remain explicitly unverified rather than silently treating the mirror as
authoritative.
## High-level goal ## High-level goal
@@ -76,10 +58,6 @@ Create a new Astro site in `./www` that is:
Do not modify or delete: Do not modify or delete:
```txt
./www.azinstitute4autism.com
```
Do not depend on: Do not depend on:
- HubSpot CLI - HubSpot CLI
@@ -283,13 +261,12 @@ Do not use Tailwind.
For each page family or shared component: For each page family or shared component:
1. Inspect the live page, HTML, CSS, assets, and responsive behavior. 1. Inspect the live page, HTML, CSS, assets, and responsive behavior.
2. Use the mirror to accelerate local extraction and inspection. 2. Resolve discrepancies in favor of the live public site.
3. Resolve discrepancies in favor of the live public site. 3. Record important visual details and identify genuine shared patterns.
4. Record important visual details and identify genuine shared patterns. 4. Implement the page or component in maintainable Astro code.
5. Implement the page or component in maintainable Astro code. 5. Compare the complete rendered page with the live public site at representative
6. Compare the complete rendered page with the live public site at representative
desktop and mobile viewport widths. desktop and mobile viewport widths.
7. Fix material visual differences before marking it complete. 6. Fix material visual differences before marking it complete.
Document intentional visual deviations and their reasons in Document intentional visual deviations and their reasons in
`reports/migration-summary.md`. `reports/migration-summary.md`.
@@ -406,15 +383,11 @@ www/
rtl.css rtl.css
tools/ tools/
extract-site.mjs
crawl-live-site.mjs crawl-live-site.mjs
audit-links.mjs audit-links.mjs
generate-redirects.mjs generate-redirects.mjs
generate-sitemap.mjs generate-sitemap.mjs
original/
README.md
reports/ reports/
url-inventory.csv url-inventory.csv
asset-inventory.csv asset-inventory.csv
@@ -427,17 +400,10 @@ www/
migration-summary.md migration-summary.md
``` ```
The `original/README.md` file should explain that the raw source mirror lives outside the Astro project at:
```txt
../www.azinstitute4autism.com
```
Do not duplicate the entire raw mirror inside `./www` unless there is a specific reason.
## Initial inspection ## Initial inspection
Before creating or modifying files, inspect the mirror. Before creating or modifying files, inspect the live public site and current
project sources.
Look for: Look for:
@@ -687,9 +653,8 @@ src/styles/rtl.css
src/styles/global.css src/styles/global.css
``` ```
Extract the current site's visual language from the live public site, using the Extract the current site's visual language from the live public site. Tokens
mirrored CSS and HTML as a convenient local aid after checking for discrepancies. must encode source values; they must not introduce a replacement visual
Tokens must encode source values; they must not introduce a replacement visual
system. system.
Use design tokens such as: Use design tokens such as:
@@ -837,7 +802,7 @@ It should support:
- hreflang links where translation relationships are known - hreflang links where translation relationships are known
- JSON-LD/schema when extracted - JSON-LD/schema when extracted
Preserve metadata from the mirror wherever possible. Preserve metadata from the live site wherever possible.
Generate: Generate:
@@ -890,49 +855,27 @@ src/pages/es/[...slug].astro
Implement routing in a clean, maintainable way. Implement routing in a clean, maintainable way.
## Extraction scripts ## Migration utility scripts
Create: Create:
```txt ```txt
tools/extract-site.mjs
tools/crawl-live-site.mjs tools/crawl-live-site.mjs
tools/audit-links.mjs tools/audit-links.mjs
tools/generate-redirects.mjs tools/generate-redirects.mjs
tools/generate-sitemap.mjs tools/generate-sitemap.mjs
``` ```
### `extract-site.mjs`
This script should:
- scan the mirror
- identify HTML files
- infer URL paths
- identify page type
- identify blog posts
- identify listing pages
- extract title/meta/H1/body/main content
- extract canonical and Open Graph metadata
- extract schema/JSON-LD where present
- convert blog posts to Markdown where feasible
- create page Markdown where useful
- copy/normalize assets
- rewrite local asset references
- create initial reports
The script does not need to be perfect, but it should be useful and documented.
### `crawl-live-site.mjs` ### `crawl-live-site.mjs`
This script should: This script should:
- attempt to crawl the live site if internet is available - attempt to crawl the live site if internet is available
- discover URLs from sitemap and internal links - discover URLs from sitemap and internal links
- compare discovered URLs against the mirror - compare discovered URLs against the current site source and generated output
- document missing URLs/assets - document missing URLs/assets
- avoid aggressive crawling - avoid aggressive crawling
- respect the scope of `www.azinstitute4autism.com` - respect the live-site scope
### `audit-links.mjs` ### `audit-links.mjs`
@@ -1143,7 +1086,6 @@ Add scripts similar to:
"dev": "astro dev", "dev": "astro dev",
"build": "astro check && astro build", "build": "astro check && astro build",
"preview": "astro preview", "preview": "astro preview",
"extract": "node tools/extract-site.mjs",
"crawl": "node tools/crawl-live-site.mjs", "crawl": "node tools/crawl-live-site.mjs",
"audit:links": "node tools/audit-links.mjs", "audit:links": "node tools/audit-links.mjs",
"generate:sitemap": "node tools/generate-sitemap.mjs", "generate:sitemap": "node tools/generate-sitemap.mjs",
@@ -1165,7 +1107,6 @@ www/README.md
It should explain: It should explain:
- what the project is - what the project is
- where the raw mirror lives
- how the migration was performed - how the migration was performed
- how to install dependencies - how to install dependencies
- how to run local dev - how to run local dev
@@ -1241,7 +1182,7 @@ Proceed methodically:
2. Read `CLAUDE.md`, if using Claude Code. 2. Read `CLAUDE.md`, if using Claude Code.
3. Read this `MIGRATION_BRIEF.md`. 3. Read this `MIGRATION_BRIEF.md`.
4. Inspect the live public site. 4. Inspect the live public site.
5. Inspect `./www.azinstitute4autism.com` and identify relevant discrepancies. 5. Inspect the relevant live public site pages and identify discrepancies.
6. Summarize a concise implementation plan. 6. Summarize a concise implementation plan.
7. Scaffold Astro in `./www`. 7. Scaffold Astro in `./www`.
8. Build extraction/reporting scripts. 8. Build extraction/reporting scripts.
+1 -1
View File
@@ -9,7 +9,7 @@ if [[ "${1:-}" == "exec" ]]; then
fi fi
exec codex \ exec codex \
--profile-v2 azi4a2-autonomous \ --profile azi4a2-autonomous \
--strict-config \ --strict-config \
--config 'approval_policy="never"' \ --config 'approval_policy="never"' \
--config 'mcp_servers.playwright.default_tools_approval_mode="approve"' \ --config 'mcp_servers.playwright.default_tools_approval_mode="approve"' \
+1
View File
@@ -1 +1,2 @@
PUBLIC_AIA_API_BASE=https://api.azinstitute4autism.com PUBLIC_AIA_API_BASE=https://api.azinstitute4autism.com
PUBLIC_ALLOW_INDEXING=false
+8 -62
View File
@@ -1,8 +1,7 @@
# Arizona Institute for Autism Astro Site # Arizona Institute for Autism Astro Site
Static Astro + TypeScript migration of the public Arizona Institute for Autism Static Astro + TypeScript migration of the public Arizona Institute for Autism
website. The read-only source mirror is located at website.
`../www.azinstitute4autism.com`.
## Quick Start ## Quick Start
@@ -23,9 +22,6 @@ http://localhost:4321
The development server watches source files and refreshes the browser after The development server watches source files and refreshes the browser after
edits. Stop it with `Ctrl+C`. edits. Stop it with `Ctrl+C`.
Do **not** run `npm run extract` during normal editing. Extraction regenerates
migrated Markdown from the raw mirror and can overwrite editorial changes.
## Environment Setup ## Environment Setup
Requirements: Requirements:
@@ -42,19 +38,23 @@ cd www
npm install npm install
``` ```
Copy the example environment file when testing the like/view counter: Copy the example environment file when testing the like/view counter or staging
SEO behavior:
```sh ```sh
cp .env.example .env cp .env.example .env
``` ```
The default value is: The default values are:
```txt ```txt
PUBLIC_AIA_API_BASE=https://api.azinstitute4autism.com PUBLIC_AIA_API_BASE=https://api.azinstitute4autism.com
PUBLIC_ALLOW_INDEXING=false
``` ```
The site still renders when that API is unavailable. The site still renders when the AIA API is unavailable. Migration and staging
builds emit `noindex,nofollow` by default; set `PUBLIC_ALLOW_INDEXING=true`
only for production builds on the canonical domain.
## View And Build ## View And Build
@@ -198,15 +198,6 @@ Available `Button` variants are `filled` (default), `outlined`, and `light`.
Available sizes are `default` and `small`. A `_blank` target automatically adds Available sizes are `default` and `small`. A `_blank` target automatically adds
`rel="noopener noreferrer"`. `rel="noopener noreferrer"`.
Use the optional `Link` component only when an inline link needs an explicit
variant or target:
```mdx
import Link from '../../../components/Link.astro';
<Link href="/library" variant="strong">Browse the library</Link>
```
Normal Markdown links remain preferred for ordinary page and article content. Normal Markdown links remain preferred for ordinary page and article content.
### Front Matter CMS ### Front Matter CMS
@@ -331,51 +322,6 @@ Edit the component's `label`, `heading`, and `items` data in the post. Keep
answer. Shared FAQ markup, styling, interaction, and schema generation live in answer. Shared FAQ markup, styling, interaction, and schema generation live in
`src/components/FAQAccordion.astro`. `src/components/FAQAccordion.astro`.
## Mirror Extraction Workflow
The mirror is read-only source material. Never modify:
```txt
../www.azinstitute4autism.com
```
Only rerun extraction when intentionally refreshing migrated content from the
mirror. Commit or back up editorial changes first.
Dependency-free extraction:
```sh
npm run extract
```
Full Cheerio/Turndown extraction:
```sh
npm run extract:full
```
After extraction:
```sh
npm run extract:blog-footers
npm run generate:sitemap
npm run generate:redirects
npm run build
npm run audit:links
npm run audit:images
npm run audit:blog
```
Extraction regenerates content files, copied assets, and inventories. Review
the complete Git diff before accepting it. Extraction may recreate FAQ-bearing
posts and CTA-bearing pages as Markdown; restore their `FAQAccordion` and
`Button` MDX blocks before accepting the result. `npm run audit:blog` reports
plain Markdown FAQ sections.
`npm run extract:blog-footers` preserves the extracted previous/next and
similar-post relationships in `src/data/blog-footers.json`, then removes those
footer fragments from article prose so `BlogPostFooter.astro` can render them.
## Reports And Utilities ## Reports And Utilities
Migration reports are stored in `reports/`. Migration reports are stored in `reports/`.
-10
View File
@@ -1,10 +0,0 @@
# Raw Source Mirror
The read-only wget mirror used for this migration lives outside this Astro
project at:
```txt
../www.azinstitute4autism.com
```
Run `npm run extract` to regenerate content and inventories from that source.
-2
View File
@@ -10,8 +10,6 @@
"build": "astro build", "build": "astro build",
"build:sandbox": "NODE_OPTIONS=--require=./tools/localhost-dns.cjs astro build", "build:sandbox": "NODE_OPTIONS=--require=./tools/localhost-dns.cjs astro build",
"preview": "astro preview", "preview": "astro preview",
"extract": "node tools/extract-fallback.mjs",
"extract:full": "node tools/extract-site.mjs",
"extract:blog-footers": "node tools/extract-blog-footers.mjs", "extract:blog-footers": "node tools/extract-blog-footers.mjs",
"crawl:live": "node tools/crawl-live-site.mjs", "crawl:live": "node tools/crawl-live-site.mjs",
"audit:links": "node tools/audit-links.mjs", "audit:links": "node tools/audit-links.mjs",
+28
View File
@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 100 100"
width="420" height="420">
<defs>
<g id="tooth" transform="translate(50,50)" fill="#ff914d">
<path d="m0 50 h1 q8 0 8 -6 q0 -8 8 -10 h-20"/>
<path d="m0 50 h1 q8 0 8 -6 q0 -8 8 -10 h-20" transform="scale(-1,1)"/>
</g>
</defs>
<g id="gear">
<circle cx="50" cy="50" r="32" stroke="#ff914d" stroke-width="10" fill="none"/>
<g id="teeth">
<use xlink:href="#tooth" transform="rotate( -10 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 35 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 80 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 125 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 170 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 215 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 260 50 50 )"/>
<use xlink:href="#tooth" transform="rotate( 305 50 50 )"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 58 KiB

-3
View File
@@ -1,3 +0,0 @@
User-agent: *
Allow: /
Sitemap: https://www.azinstitute4autism.com/sitemap.xml
+8 -9
View File
@@ -1,14 +1,14 @@
# Cleanup Log # Cleanup Log
- Replaced HubSpot-generated wrappers, inline styles, scripts, analytics, and modules with reusable Astro components. - Replaced HubSpot-generated wrappers, inline styles, scripts, analytics, and modules with reusable Astro components.
- Preserved canonical clean URLs while excluding local mirror query-string and AMP duplicates. - Preserved canonical clean URLs while excluding HubSpot query-string and AMP duplicates.
- Consolidated responsive `hs-fs` image variants to canonical `hubfs` assets where available. - Consolidated responsive `hs-fs` image variants to canonical `hubfs` assets where available.
- Excluded mirrored HubSpot CSS and JavaScript from the new public asset package. - Excluded HubSpot CSS and JavaScript from the new public asset package.
- Self-hosted canonical images, SVGs, fonts, and PDFs from the mirror. - Self-hosted canonical images, SVGs, fonts, and PDFs where practical.
- Recreated navigation and footer from structured JSON. - Recreated navigation and footer from structured JSON.
- Recreated visible contact and consultation forms as static accessible HTML. - Recreated visible contact and consultation forms as static accessible HTML.
- Used the source palette: AIA blue `#254080`, dark blue, straw yellow, orange, and teal. - Used the source palette: AIA blue `#254080`, dark blue, straw yellow, orange, and teal.
- Used the live site's locally mirrored Playfair Display headings, Rubik body copy, and Caveat accent font. - Used self-hosted Playfair Display headings, Rubik body copy, and Caveat accent font.
- Added multilingual collection and route structure with Arabic RTL support. - Added multilingual collection and route structure with Arabic RTL support.
- Kept all extracted source content editable as Markdown. - Kept all extracted source content editable as Markdown.
- Replaced the initial generic rounded-card visual system with live-derived - Replaced the initial generic rounded-card visual system with live-derived
@@ -21,18 +21,17 @@
- Reorganized the homepage source into named `home:` frontmatter blocks so the - Reorganized the homepage source into named `home:` frontmatter blocks so the
content is easier to inspect and edit without changing the rendered layout. content is easier to inspect and edit without changing the rendered layout.
- Replaced the extracted linear team article with a dedicated live-derived team grid. - Replaced the extracted linear team article with a dedicated live-derived team grid.
- Repaired mirror-rewritten PDF, lightbox, CTA, and relative content links. - Repaired rewritten PDF, lightbox, CTA, and relative content links.
- Limited language-switcher choices to translations that have generated routes. - Limited language-switcher choices to translations that have generated routes.
- Verified and implemented the current production likes/views API contract. - Verified and implemented the current production likes/views API contract.
- Recovered 18 live page-banner assets that the wget mirror missed because - Recovered 18 live page-banner assets that HubSpot injected through malformed
HubSpot injected them through malformed inline `background-image` styles. inline `background-image` styles.
- Restored the live library banner and consultation form section background. - Restored the live library banner and consultation form section background.
- Added a mapped-page-imagery audit to prevent missing visual assets from - Added a mapped-page-imagery audit to prevent missing visual assets from
silently passing the source link audit. silently passing the source link audit.
- Removed duplicated article titles, author/date blocks, and featured images - Removed duplicated article titles, author/date blocks, and featured images
from all 65 blog Markdown bodies; these elements are rendered by the shared from all 65 blog Markdown bodies; these elements are rendered by the shared
blog-post layout. Updated both extractors and added a blog-content audit to blog-post layout. Added a blog-content audit to prevent recurrence.
prevent recurrence.
- Converted 19 FAQ-bearing blog posts to MDX and restored a reusable - Converted 19 FAQ-bearing blog posts to MDX and restored a reusable
`FAQAccordion.astro` component that owns the live-style accordion and `FAQAccordion.astro` component that owns the live-style accordion and
matching `FAQPage` JSON-LD. matching `FAQPage` JSON-LD.
+28 -12
View File
@@ -3,9 +3,9 @@
## Status ## Status
A maintainable Astro migration and substantial fidelity-first pass are A maintainable Astro migration and substantial fidelity-first pass are
implemented. The live public site, not the wget mirror, was used as the implemented. The live public site was used as the authority for the shared
authority for the shared shell, English and Spanish homepages, service-page shell, English and Spanish homepages, service-page family, team page, library
family, team page, library indexes, and blog-post family. indexes, and blog-post family.
## Migrated Content and Assets ## Migrated Content and Assets
@@ -15,9 +15,9 @@ family, team page, library indexes, and blog-post family.
- 167 self-hosted images, 20 font files, and two PDF downloads. - 167 self-hosted images, 20 font files, and two PDF downloads.
- Current June and May 2026 English library articles are included. - Current June and May 2026 English library articles are included.
The raw mirror remains untouched. HubSpot-generated wrappers, analytics, HubSpot-generated wrappers, analytics, scripts, CSS, query-language duplicates,
scripts, CSS, query-language duplicates, AMP variants, pagination, and author AMP variants, pagination, and author archive variants are not carried into the
archive variants are not carried into the Astro implementation. Astro implementation.
## Live-Source Fidelity Pass ## Live-Source Fidelity Pass
@@ -44,6 +44,9 @@ Implemented fidelity work includes:
- Restored the consultation form section's injected background image. - Restored the consultation form section's injected background image.
- Added a dedicated live-derived team card grid rather than presenting the - Added a dedicated live-derived team card grid rather than presenting the
extracted team content as a generic article. extracted team content as a generic article.
- Rebuilt the contact page around the live two-column content/form section and
full-width Leaflet map while retaining local clickable obfuscated phone
links.
- Rebuilt library indexes and blog-post presentation around the live sidebar, - Rebuilt library indexes and blog-post presentation around the live sidebar,
article list, byline, featured-image, and counter patterns. article list, byline, featured-image, and counter patterns.
- Converted FAQ-bearing posts to MDX and recreated their live-style accordions - Converted FAQ-bearing posts to MDX and recreated their live-style accordions
@@ -52,7 +55,7 @@ Implemented fidelity work includes:
links, fawn backgrounds, spacing, rounded presentation, and quote-mark SVG. links, fawn backgrounds, spacing, rounded presentation, and quote-mark SVG.
- Replaced generic oversized cards, rounded controls, and marketing heroes - Replaced generic oversized cards, rounded controls, and marketing heroes
with live-derived typography, palette, widths, spacing, and compact controls. with live-derived typography, palette, widths, spacing, and compact controls.
- Corrected material live/mirror discrepancies found during the pass, - Corrected material live-source discrepancies found during the pass,
including current homepage ESA copy, testimonial content, and ABA copy. including current homepage ESA copy, testimonial content, and ABA copy.
## URLs and Redirects ## URLs and Redirects
@@ -77,6 +80,12 @@ backend and spam-protection TODO comments. Submission is intentionally
disabled. Appointment and enrollment calls to action route to the static disabled. Appointment and enrollment calls to action route to the static
consultation page rather than retaining the production Jotform backend. consultation page rather than retaining the production Jotform backend.
## External Dependencies
- The contact page map intentionally matches the live Leaflet/OpenStreetMap
implementation and loads Leaflet from `unpkg.com` plus map tiles from
`tile.openstreetmap.org`.
## Multilingual ## Multilingual
- Spanish has the full live-derived homepage, translated service pages, - Spanish has the full live-derived homepage, translated service pages,
@@ -105,6 +114,9 @@ unavailable.
- Canonicals, Open Graph tags, Twitter card tags, semantic titles, and global - Canonicals, Open Graph tags, Twitter card tags, semantic titles, and global
organization JSON-LD are emitted by shared layouts. organization JSON-LD are emitted by shared layouts.
- Organization JSON-LD intentionally omits raw `telephone` and `email` fields;
visible contact details use the Astro obfuscation component to avoid exposing
plain email and phone targets in rendered HTML.
- Library-index canonicals and current visible page H1s are explicitly set. - Library-index canonicals and current visible page H1s are explicitly set.
- Extracted image alt text is retained where available. - Extracted image alt text is retained where available.
- Semantic landmarks, skip link, labeled forms, keyboard-operable navigation, - Semantic landmarks, skip link, labeled forms, keyboard-operable navigation,
@@ -125,11 +137,15 @@ unavailable.
- `npm run generate:sitemap`: passed; generated 97 URLs. - `npm run generate:sitemap`: passed; generated 97 URLs.
- `npm run generate:redirects`: passed. - `npm run generate:redirects`: passed.
- All migration `.mjs` tools and the sandbox DNS helper pass `node --check`. - All migration `.mjs` tools and the sandbox DNS helper pass `node --check`.
- The Astro compiler parsed all 33 `.astro` files successfully. - The Astro compiler parsed all 49 `.astro` files successfully.
- `npm run build`: blocked before compilation because this autonomous sandbox - `npm run build`: blocked before compilation because this autonomous sandbox
denies `/etc/hosts`, causing `getaddrinfo EAI_AGAIN localhost`. cannot resolve `localhost`, causing `getaddrinfo EAI_AGAIN localhost`.
- `npm run build:sandbox`: bypasses that DNS lookup and reaches Vite, then the - `npm run build:sandbox`: passed; generated 97 static pages.
sandbox rejects esbuild's required child process with `spawn EPERM`. - Live contact-page structure was inspected in browser at a 1280px desktop
viewport; local generated HTML was checked for the contact layout, Leaflet
assets, map container, and obfuscated clickable phone script. Local browser
rendering was blocked because the Playwright browser cannot reach shell
loopback servers and blocks `file:` URLs in this environment.
- Nix shell verification and `npm audit` retrieval were blocked by sandbox - Nix shell verification and `npm audit` retrieval were blocked by sandbox
proxy/cache network resets. proxy/cache network resets.
@@ -141,7 +157,7 @@ final production-build proof.
- Perform full-page desktop and mobile visual comparisons for page-specific - Perform full-page desktop and mobile visual comparisons for page-specific
layouts beyond the completed homepage, team, service, library, and article layouts beyond the completed homepage, team, service, library, and article
families. families.
- Editorially review extracted long-form content for remaining mirror artifacts, - Editorially review extracted long-form content for remaining extraction artifacts,
stale phone/email references, and heading hierarchy. stale phone/email references, and heading hierarchy.
- Review all source alt text, keyboard behavior, screen-reader output, and - Review all source alt text, keyboard behavior, screen-reader output, and
contrast with accessibility tooling. contrast with accessibility tooling.
+3 -3
View File
@@ -1,4 +1,4 @@
from,to,status,reason from,to,status,reason
"/aba","/aba-therapy",301,"Brief alias to preserved mirror URL" "/aba","/aba-therapy",301,"Brief legacy alias to preserved URL"
"/autismevaluations","/autism-evaluations",301,"Brief alias to preserved mirror URL" "/autismevaluations","/autism-evaluations",301,"Brief legacy alias to preserved URL"
"/learnersocialclub","/learner-social-club",301,"Brief alias to preserved mirror URL" "/learnersocialclub","/learner-social-club",301,"Brief legacy alias to preserved URL"
1 from to status reason
2 /aba /aba-therapy 301 Brief alias to preserved mirror URL Brief legacy alias to preserved URL
3 /autismevaluations /autism-evaluations 301 Brief alias to preserved mirror URL Brief legacy alias to preserved URL
4 /learnersocialclub /learner-social-club 301 Brief alias to preserved mirror URL Brief legacy alias to preserved URL
+2 -2
View File
@@ -18,8 +18,8 @@
## Cleanup ## Cleanup
- HubSpot `?hsLang=...` mirror duplicates are excluded from generated routes. - HubSpot `?hsLang=...` duplicates are excluded from generated routes.
- AMP mirror variants are excluded because Astro pages are responsive and static. - AMP variants are excluded because Astro pages are responsive and static.
- Blog pagination and author archive variants are not preserved as separate generated pages. - Blog pagination and author archive variants are not preserved as separate generated pages.
- Brief aliases `/aba`, `/autismevaluations`, and `/learnersocialclub` redirect to preserved source URLs. - Brief aliases `/aba`, `/autismevaluations`, and `/learnersocialclub` redirect to preserved source URLs.
+34 -11
View File
@@ -1,10 +1,14 @@
--- ---
interface Props { interface Props {
href: string; href?: string;
variant?: 'filled' | 'outlined' | 'light'; variant?: 'filled' | 'outlined' | 'light';
size?: 'default' | 'small'; size?: 'default' | 'small';
center?: boolean;
target?: '_blank' | '_self'; target?: '_blank' | '_self';
rel?: string; rel?: string;
type?: 'submit' | 'button' | 'reset';
disabled?: boolean;
'aria-describedby'?: string;
class?: string; class?: string;
} }
@@ -12,20 +16,28 @@ const {
href, href,
variant = 'filled', variant = 'filled',
size = 'default', size = 'default',
center = false,
target, target,
rel = target === '_blank' ? 'noopener noreferrer' : undefined, rel = target === '_blank' ? 'noopener noreferrer' : undefined,
type,
disabled,
'aria-describedby': ariaDescribedby,
class: className class: className
} = Astro.props; } = Astro.props;
const classes = [
'content-button',
`content-button--${variant}`,
{ 'content-button--small': size === 'small', 'content-button--center': center },
className
];
--- ---
<a {href ? (
class:list={['content-button', `content-button--${variant}`, { 'content-button--small': size === 'small' }, className]} <a class:list={classes} href={href} target={target} rel={rel}><slot /></a>
href={href} ) : (
target={target} <button class:list={classes} type={type} disabled={disabled} aria-describedby={ariaDescribedby}><slot /></button>
rel={rel} )}
>
<slot />
</a>
<style> <style>
.content-button { .content-button {
@@ -36,8 +48,9 @@ const {
display: inline-block; display: inline-block;
font-weight: 400; font-weight: 400;
line-height: 1.5; line-height: 1.5;
padding: .8rem 1.2rem; padding: .65rem 1.2rem;
text-decoration: none; text-decoration: none;
transition: .3s linear all;
} }
.content-button:hover, .content-button:hover,
@@ -65,6 +78,16 @@ const {
.content-button--small { .content-button--small {
font-size: .9rem; font-size: .9rem;
padding: .5rem 1rem; }
.content-button--center {
margin-block: 2.5rem;
margin-inline-start: 50%;
translate: -50%;
}
button.content-button {
cursor: pointer;
font: inherit;
} }
</style> </style>
-11
View File
@@ -1,11 +0,0 @@
<section class="cta-band">
<div class="container split">
<div><p class="eyebrow">Start the conversation</p><h2>Find the right support for your learner.</h2></div>
<a class="button button-light" href="/client-consultation">Schedule a Free Consultation</a>
</div>
</section>
<style>
.cta-band { background: var(--color-primary); color: white; padding-block: var(--space-xl); }
.cta-band h2, .cta-band .eyebrow { color: white; margin: 0; }
</style>
+84
View File
@@ -0,0 +1,84 @@
---
import Button from './Button.astro';
import ContactObfuscation from './ContactObfuscation.astro';
interface Props {
title?: string;
}
const { title = 'Contact AIA' } = Astro.props;
---
<form class="contact-form-card" method="post" action="">
<!-- TODO: Wire this form to Netlify Forms, a custom API endpoint, or another backend service. -->
<!-- TODO: Add spam protection before production launch. -->
<h3 class="contact-form-card__title">{title}</h3>
<div class="contact-form-card__fields">
<label>Parent or guardian name<input name="name" autocomplete="name" /></label>
<label>Email<input type="email" name="email" autocomplete="email" /></label>
<label>Phone<input type="tel" name="phone" autocomplete="tel" /></label>
<label>Service of interest<select name="service"><option>ABA Therapy</option><option>Autism Evaluation</option><option>Learner Social Club</option><option>Other</option></select></label>
<label>How can we help?<textarea name="message" rows="5"></textarea></label>
<Button type="submit" disabled aria-describedby="contact-form-note" class="contact-form-card__submit">Submit</Button>
<p id="contact-form-note" class="contact-form-card__note">Online submission is not yet connected. Please call <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />.</p>
</div>
</form>
<style>
.contact-form-card {
background: white;
border-radius: 4px;
box-shadow: 0 4px 4px 0 rgb(81 81 81 / 4%), 0 4px 16px 0 rgb(81 81 81 / 8%);
margin: 0 auto;
max-width: 600px;
overflow: hidden;
}
.contact-form-card__title {
border-bottom: 1px solid #f1f1f1;
margin: 0;
padding: 1.2rem 1.5rem;
text-align: center;
}
.contact-form-card__fields {
display: grid;
gap: 1rem;
padding: 1.5rem;
}
.contact-form-card label {
display: grid;
font-weight: 700;
gap: .4rem;
}
.contact-form-card input,
.contact-form-card select,
.contact-form-card textarea {
background: #fcf9f5;
border: 1px solid var(--color-border);
border-radius: 4px;
color: var(--color-primary);
font: inherit;
padding: .8rem;
width: 100%;
}
.contact-form-card textarea {
resize: vertical;
}
.contact-form-card :global(.contact-form-card__submit) {
justify-self: center;
max-width: 375px;
width: 100%;
}
.contact-form-card__note {
color: var(--color-muted);
font-size: .9rem;
margin: 0;
text-align: center;
}
</style>
@@ -0,0 +1,58 @@
---
interface Props {
email?: string;
phone?: string;
hrefValue?: string;
linkText?: string;
obfuscatedText?: string;
class?: string;
id?: string;
}
const {
email,
phone,
hrefValue,
linkText,
obfuscatedText,
class: className,
id
} = Astro.props;
if ((email ? 1 : 0) + (phone ? 1 : 0) !== 1) {
throw new Error('ContactObfuscation requires exactly one of email or phone.');
}
const contactType = email ? 'email' : 'phone';
const sourceValue = email ?? phone ?? '';
const linkValue = linkText ?? sourceValue;
const fallbackText = obfuscatedText ?? sourceValue;
const protocol = email ? 'mailto' : 'tel';
const telHrefValue = hrefValue ?? sourceValue.replace(/[^\d+]/g, '');
const targetValue = email ? (hrefValue ?? sourceValue) : telHrefValue;
const encode = (value: string) => Array.from(value, (character) => character.charCodeAt(0));
const encodedTarget = encode(targetValue);
const encodedText = encode(linkValue);
const spanId = id ?? `${contactType}-obfuscation-${Math.random().toString(36).slice(2, 10)}`;
---
<span id={spanId} class={className}>{fallbackText}</span><script type="text/javascript" define:vars={{ encodedTarget, encodedText, protocol, spanId }}>
(() => {
const contactSpan = document.getElementById(spanId);
if (!contactSpan) return;
const decode = (encodedValue) => encodedValue
.map((characterCode) => String.fromCharCode(characterCode))
.join('');
const target = decode(encodedTarget);
const text = decode(encodedText);
const link = document.createElement('a');
link.href = `${protocol}:${target}`;
link.textContent = text;
contactSpan.textContent = '';
contactSpan.appendChild(link);
})();
</script>
+3 -2
View File
@@ -1,4 +1,5 @@
--- ---
import ContactObfuscation from './ContactObfuscation.astro';
import site from '../data/site.json'; import site from '../data/site.json';
const year = new Date().getFullYear(); const year = new Date().getFullYear();
const { lang = 'en' } = Astro.props; const { lang = 'en' } = Astro.props;
@@ -31,11 +32,11 @@ const labels = lang === 'es'
<div class="footer-contact"> <div class="footer-contact">
<div class="footer-contact-item"> <div class="footer-contact-item">
<img src="/assets/images/phone-blue.svg" alt="" aria-hidden="true" width="24" height="24" /> <img src="/assets/images/phone-blue.svg" alt="" aria-hidden="true" width="24" height="24" />
<a href={`tel:${site.phone.replace(/\D/g, '')}`}>{site.phone}</a> <ContactObfuscation phone={site.phone} hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />
</div> </div>
<div class="footer-contact-item"> <div class="footer-contact-item">
<img src="/assets/images/envelope-blue.svg" alt="" aria-hidden="true" width="24" height="24" /> <img src="/assets/images/envelope-blue.svg" alt="" aria-hidden="true" width="24" height="24" />
<a href={`mailto:${site.email}`}>{site.email}</a> <ContactObfuscation email={site.email} obfuscatedText="moc.msitua4etutitsniza@ofni" />
</div> </div>
<div class="footer-contact-item"> <div class="footer-contact-item">
<img src="/assets/images/location-blue.svg" alt="" aria-hidden="true" width="24" height="24" /> <img src="/assets/images/location-blue.svg" alt="" aria-hidden="true" width="24" height="24" />
+4 -2
View File
@@ -1,4 +1,6 @@
--- ---
import Button from './Button.astro';
import ContactObfuscation from './ContactObfuscation.astro';
const { title = 'Schedule Your Free Consultation', showBackground = false } = Astro.props; const { title = 'Schedule Your Free Consultation', showBackground = false } = Astro.props;
--- ---
<section class:list={['form-section', { 'form-section-background': showBackground }]} aria-labelledby="form-title"> <section class:list={['form-section', { 'form-section-background': showBackground }]} aria-labelledby="form-title">
@@ -12,8 +14,8 @@ const { title = 'Schedule Your Free Consultation', showBackground = false } = As
<label>Phone<input type="tel" name="phone" autocomplete="tel" /></label> <label>Phone<input type="tel" name="phone" autocomplete="tel" /></label>
<label>Service of interest<select name="service"><option>ABA Therapy</option><option>Autism Evaluation</option><option>Learner Social Club</option><option>Other</option></select></label> <label>Service of interest<select name="service"><option>ABA Therapy</option><option>Autism Evaluation</option><option>Learner Social Club</option><option>Other</option></select></label>
<label>How can we help?<textarea name="message" rows="5"></textarea></label> <label>How can we help?<textarea name="message" rows="5"></textarea></label>
<button class="button" type="submit" disabled aria-describedby="form-note">Submit</button> <Button type="submit" disabled aria-describedby="form-note">Submit</Button>
<p id="form-note" class="form-note">Online submission is not yet connected. Please call (480) 687-7099.</p> <p id="form-note" class="form-note">Online submission is not yet connected. Please call <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />.</p>
</form> </form>
</div> </div>
</section> </section>
+3 -2
View File
@@ -1,4 +1,5 @@
--- ---
import Button from './Button.astro';
import LanguageSwitcher from './LanguageSwitcher.astro'; import LanguageSwitcher from './LanguageSwitcher.astro';
import MainNav from './MainNav.astro'; import MainNav from './MainNav.astro';
import MobileNav from './MobileNav.astro'; import MobileNav from './MobileNav.astro';
@@ -21,7 +22,7 @@ const utility = lang === 'es'
<MainNav lang={lang} /> <MainNav lang={lang} />
<MobileNav lang={lang} /> <MobileNav lang={lang} />
<LanguageSwitcher /> <LanguageSwitcher />
<a class="button button-small" href="/tour">Tour AIA</a> <Button href="/tour" size="small">Tour AIA</Button>
</div> </div>
</header> </header>
@@ -33,7 +34,7 @@ const utility = lang === 'es'
.header-inner { align-items: center; display: flex; gap: 1.4rem; min-height: 110px; } .header-inner { align-items: center; display: flex; gap: 1.4rem; min-height: 110px; }
.brand img { width: 150px; } .brand img { width: 150px; }
@media (max-width: 950px) { @media (max-width: 950px) {
.header-inner > .button { display: none; } .header-inner > :global(.content-button) { display: none; }
} }
@media (max-width: 760px) { @media (max-width: 760px) {
.utility-inner { justify-content: center; } .utility-inner { justify-content: center; }
-13
View File
@@ -1,13 +0,0 @@
---
const logos = ['aetna.png', 'bluecrossblueshield-logo-1.webp', 'logo-ahcccs.webp', 'logo-optum.webp', 'logo-tricare-1.webp', 'united-healthcare-logo-1.webp'];
---
<section class="insurance-strip" aria-labelledby="insurance-title">
<div class="container"><h2 id="insurance-title">Insurance partners</h2><div class="logo-row">{logos.map((logo) => <img src={`/assets/images/${logo}`} alt="" loading="lazy" />)}</div></div>
</section>
<style>
.insurance-strip { background: white; border-block: 1px solid var(--color-border); padding-block: var(--space-lg); text-align: center; }
.insurance-strip h2 { font-size: 1.4rem; }
.logo-row { align-items: center; display: flex; flex-wrap: wrap; justify-content: space-around; }
.logo-row img { filter: grayscale(1); max-height: 55px; max-width: 130px; }
</style>
-42
View File
@@ -1,42 +0,0 @@
---
interface Props {
href: string;
variant?: 'default' | 'strong';
target?: '_blank' | '_self';
rel?: string;
class?: string;
}
const {
href,
variant = 'default',
target,
rel = target === '_blank' ? 'noopener noreferrer' : undefined,
class: className
} = Astro.props;
---
<a
class:list={['content-link', { 'content-link--strong': variant === 'strong' }, className]}
href={href}
target={target}
rel={rel}
>
<slot />
</a>
<style>
.content-link {
color: var(--color-accent-strong);
text-decoration: none;
}
.content-link:hover,
.content-link:focus-visible {
color: var(--color-accent);
}
.content-link--strong {
font-weight: 700;
}
</style>
-8
View File
@@ -1,8 +0,0 @@
---
const { title = 'Scottsdale', address = '8901 E Raintree Dr Ste 160, Scottsdale, AZ 85260' } = Astro.props;
---
<article class="card location-card"><h3>{title}</h3><p>{address}</p><a class="text-link" href={`https://maps.google.com/?q=${encodeURIComponent(address)}`}>Get directions</a></article>
<style>
.location-card { padding: var(--space-lg); }
</style>
+11 -4
View File
@@ -1,33 +1,40 @@
--- ---
interface Props { interface Props {
title: string; title: string;
subtitle?: string;
image?: string; image?: string;
eyebrow?: string; eyebrow?: string;
constrain?: boolean; constrain?: boolean;
} }
const { title, image, eyebrow, constrain = false } = Astro.props; const { title, subtitle, image, eyebrow, constrain = false } = Astro.props;
--- ---
<header class:list={['page-hero', { 'page-hero--image': image, 'page-hero--constrained': image && constrain }]} style={image ? `--hero-image: url("${image}")` : undefined}> <header class:list={['page-hero', { 'page-hero--image': image, 'page-hero--constrained': image && constrain }]} style={image ? `--hero-image: url("${image}")` : undefined}>
<div class="container"> <div class="container">
<div class="page-hero__heading">
{eyebrow {eyebrow
? <div class="page-hero__copy"><p class="script-label">{eyebrow}</p><h1>{title}</h1></div> ? <div class="page-hero__copy"><p class="eyebrow">{eyebrow}</p><h1>{title}</h1>{subtitle && <h2>{subtitle}</h2>}</div>
: <h1>{title}</h1> : <><h1>{title}</h1>{subtitle && <h2>{subtitle}</h2>}</>
} }
</div>
</div> </div>
</header> </header>
<style> <style>
.page-hero { background: var(--color-tint); padding-block: 4rem; text-align: center; } .page-hero { background: var(--color-tint); padding-block: 4rem; text-align: center; }
.page-hero__heading { display: inline-block; }
.page-hero h1 { margin: 0; } .page-hero h1 { margin: 0; }
.page-hero h2 { color: var(--color-primary); font-family: var(--font-heading); font-size: clamp(2rem, 4vw, 2.5rem); font-weight: 400; line-height: 1.15; margin: .5rem 0 0; }
.page-hero--image { background-image: var(--hero-image); background-position: center; background-repeat: no-repeat; background-size: cover; max-height: 420px; padding-block: 0; text-align: left; } .page-hero--image { background-image: var(--hero-image); background-position: center; background-repeat: no-repeat; background-size: cover; max-height: 420px; padding-block: 0; text-align: left; }
.page-hero--image > .container { padding-block: 10rem; } .page-hero--image > .container { padding-block: 10rem; }
.page-hero--image h1 { max-width: 600px; } .page-hero--image h1 { max-width: 600px; }
.page-hero--image h2 { max-width: 600px; }
.page-hero__copy { max-width: 600px; } .page-hero__copy { max-width: 600px; }
.page-hero--constrained { background-image: var(--hero-image), linear-gradient(var(--color-tint), var(--color-tint)); background-clip: content-box, border-box; background-origin: content-box, border-box; background-position: center, center; background-repeat: no-repeat, repeat; background-size: cover, auto; padding-inline: max(0px, calc((100% - var(--container-w)) / 2)); } .page-hero--constrained { background-image: var(--hero-image), linear-gradient(var(--color-tint), var(--color-tint)); background-clip: content-box, border-box; background-origin: content-box, border-box; background-position: center, center; background-repeat: no-repeat, repeat; background-size: cover, auto; padding-inline: max(0px, calc((100% - var(--container-w)) / 2)); }
@media (max-width: 760px) { @media (max-width: 760px) {
.page-hero__heading { background: #fffb; padding: 2rem; }
.page-hero--image > .container { padding-block: 6.25rem; } .page-hero--image > .container { padding-block: 6.25rem; }
.page-hero--image { text-align: center; } .page-hero--image { text-align: center; }
.page-hero--image h1, .page-hero__copy { margin-inline: auto; } .page-hero--image h1, .page-hero--image h2, .page-hero__copy { margin-inline: auto; }
} }
</style> </style>
+12 -1
View File
@@ -6,12 +6,23 @@ interface Props {
image?: string; image?: string;
lang?: string; lang?: string;
type?: 'website' | 'article'; type?: 'website' | 'article';
robots?: string;
} }
const { title, description = '', canonical, image, lang = 'en', type = 'website' } = Astro.props; const {
title,
description = '',
canonical,
image,
lang = 'en',
type = 'website',
robots
} = Astro.props;
const defaultRobots = import.meta.env.PUBLIC_ALLOW_INDEXING === 'true' ? 'index,follow' : 'noindex,nofollow';
const absoluteImage = image ? new URL(image, Astro.site ?? Astro.url).href : undefined; const absoluteImage = image ? new URL(image, Astro.site ?? Astro.url).href : undefined;
--- ---
<title>{title}</title> <title>{title}</title>
<meta name="description" content={description} /> <meta name="description" content={description} />
<meta name="robots" content={robots ?? defaultRobots} />
{canonical && <link rel="canonical" href={canonical} />} {canonical && <link rel="canonical" href={canonical} />}
<meta property="og:type" content={type} /> <meta property="og:type" content={type} />
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
-7
View File
@@ -1,7 +0,0 @@
---
const { title, description, href, image } = Astro.props;
---
<article class="card service-card">
{image && <img src={image} alt="" loading="lazy" />}
<div class="card-body"><h3><a href={href}>{title}</a></h3><p>{description}</p><a class="text-link" href={href}>Learn more</a></div>
</article>
@@ -1,4 +1,5 @@
--- ---
import Button from '../Button.astro';
import type { FinancialHelpSection } from '../../types/home-sections'; import type { FinancialHelpSection } from '../../types/home-sections';
interface Props { section: FinancialHelpSection } interface Props { section: FinancialHelpSection }
const { section } = Astro.props; const { section } = Astro.props;
@@ -7,6 +8,6 @@ const { section } = Astro.props;
<div class="container"> <div class="container">
<h2>{section.heading}</h2> <h2>{section.heading}</h2>
<p>{section.body}</p> <p>{section.body}</p>
<a class="button" href={section.cta.href}>{section.cta.label}</a> <Button href={section.cta.href}>{section.cta.label}</Button>
</div> </div>
</section> </section>
+4 -3
View File
@@ -1,4 +1,5 @@
--- ---
import Button from '../Button.astro';
import type { HeroSection } from '../../types/home-sections'; import type { HeroSection } from '../../types/home-sections';
interface Props { section: HeroSection } interface Props { section: HeroSection }
const { section } = Astro.props; const { section } = Astro.props;
@@ -6,10 +7,10 @@ const { section } = Astro.props;
<section class="home-hero"> <section class="home-hero">
<div class="container home-hero-grid"> <div class="container home-hero-grid">
<div> <div>
<p class="script-label">{section.eyebrow}</p> <p class="eyebrow">{section.eyebrow}</p>
<h1 set:html={section.heading} /> <h1 set:html={section.heading} />
<p>{section.body}</p> <p>{section.body}</p>
<a class="button" href={section.cta.href}>{section.cta.label}</a> <Button href={section.cta.href}>{section.cta.label}</Button>
</div> </div>
<img src={`/assets/images/${section.image}`} alt={section.imageAlt} loading="eager" /> <img src={`/assets/images/${section.image}`} alt={section.imageAlt} loading="eager" />
</div> </div>
@@ -19,7 +20,7 @@ const { section } = Astro.props;
.home-hero { background: var(--color-tint); overflow: hidden; } .home-hero { background: var(--color-tint); overflow: hidden; }
.home-hero-grid { align-items: end; display: grid; grid-template-columns: 1fr .9fr; min-height: 520px; padding-top: 4rem; } .home-hero-grid { align-items: end; display: grid; grid-template-columns: 1fr .9fr; min-height: 520px; padding-top: 4rem; }
.home-hero-grid > div { align-self: center; padding-bottom: 4rem; } .home-hero-grid > div { align-self: center; padding-bottom: 4rem; }
.home-hero-grid p:not(.script-label) { max-width: 570px; } .home-hero-grid p:not(.eyebrow) { max-width: 570px; }
.home-hero-grid img { align-self: end; justify-self: end; max-height: 500px; object-fit: contain; } .home-hero-grid img { align-self: end; justify-self: end; max-height: 500px; object-fit: contain; }
@media (max-width: 760px) { @media (max-width: 760px) {
.home-hero-grid { grid-template-columns: 1fr; padding-top: 3rem; text-align: center; } .home-hero-grid { grid-template-columns: 1fr; padding-top: 3rem; text-align: center; }
@@ -1,4 +1,5 @@
--- ---
import Button from '../Button.astro';
import type { ServicesIntroSection } from '../../types/home-sections'; import type { ServicesIntroSection } from '../../types/home-sections';
interface Props { section: ServicesIntroSection } interface Props { section: ServicesIntroSection }
const { section } = Astro.props; const { section } = Astro.props;
@@ -31,7 +32,7 @@ const { section } = Astro.props;
<div> <div>
<h2 class="no-balance">{section.commitmentsHeading}</h2> <h2 class="no-balance">{section.commitmentsHeading}</h2>
<ul class="source-list two-column-list">{section.commitments.map((item) => <li>{item}</li>)}</ul> <ul class="source-list two-column-list">{section.commitments.map((item) => <li>{item}</li>)}</ul>
<a class="button" href={section.commitmentsCta.href}>{section.commitmentsCta.label}</a> <Button href={section.commitmentsCta.href}>{section.commitmentsCta.label}</Button>
</div> </div>
<img class="gear-photo gear-photo-right" src={`/assets/images/${section.commitmentsImage}`} alt={section.commitmentsImageAlt} /> <img class="gear-photo gear-photo-right" src={`/assets/images/${section.commitmentsImage}`} alt={section.commitmentsImageAlt} />
</div> </div>
@@ -1,4 +1,5 @@
--- ---
import Button from '../Button.astro';
const indeedUrl = 'https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs'; const indeedUrl = 'https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs';
const benefits = [ const benefits = [
@@ -41,7 +42,7 @@ const careerCards = [
<h2>Join the AIA Team</h2> <h2>Join the AIA Team</h2>
<p>Apply to join the Arizona Institute for Autism (AIA) team today. We are on a mission to improve special education and strengthen communities throughout Arizona.</p> <p>Apply to join the Arizona Institute for Autism (AIA) team today. We are on a mission to improve special education and strengthen communities throughout Arizona.</p>
<p>Our talented and passionate employees are a critical piece to the high-quality Autism services we provide along with our commitment to behavioral health, school solutions, and community outreach.</p> <p>Our talented and passionate employees are a critical piece to the high-quality Autism services we provide along with our commitment to behavioral health, school solutions, and community outreach.</p>
<a class="button button-center" href={indeedUrl} target="_blank" rel="noopener noreferrer">View Open Positions</a> <Button href={indeedUrl} target="_blank" center>View Open Positions</Button>
</section> </section>
<!-- Our Benefits --> <!-- Our Benefits -->
@@ -129,7 +130,7 @@ const careerCards = [
<img src="/assets/images/logo-BACB.png" alt="BACB logo" loading="lazy" /> <img src="/assets/images/logo-BACB.png" alt="BACB logo" loading="lazy" />
</div> </div>
</div> </div>
<a class="button button-center" href={indeedUrl} target="_blank" rel="noopener noreferrer">View Open Positions</a> <Button href={indeedUrl} target="_blank" center>View Open Positions</Button>
</div> </div>
</section> </section>
@@ -175,7 +176,7 @@ const careerCards = [
</div> </div>
))} ))}
</div> </div>
<a class="button button-center" href={indeedUrl} target="_blank" rel="noopener noreferrer">View Open Positions</a> <Button href={indeedUrl} target="_blank" center>View Open Positions</Button>
</div> </div>
</section> </section>
+111
View File
@@ -0,0 +1,111 @@
---
import ContactForm from '../ContactForm.astro';
interface Props {
title: string;
}
const { title } = Astro.props;
---
<section class="contact-page">
<div class="container contact-page__grid">
<div class="contact-page__copy">
<slot />
</div>
<ContactForm title={title} />
</div>
</section>
<section class="contact-map-section" aria-label="Map showing Arizona Institute for Autism in Scottsdale">
<div id="aia-contact-map" class="contact-map"></div>
</section>
<script is:inline src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script is:inline>
(() => {
const mapElement = document.getElementById('aia-contact-map');
if (!mapElement || !window.L) return;
const map = window.L.map(mapElement).setView([33.63, -111.88756], 12);
const tiles = window.L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 19
});
tiles.on('tileload', (event) => {
if (event.tile && !event.tile.alt) {
event.tile.alt = 'OpenStreetMap tile showing area around Arizona Institute for Autism in Scottsdale, AZ';
}
});
tiles.addTo(map);
window.L.marker([33.617746, -111.88756]).addTo(map).bindPopup(`
<span style="display:block;text-align:center">
<b>Arizona Institute for Autism</b><br>
<img alt="Arizona Institute for Autism" src="/assets/images/aia-logo.svg" width="94">
</span>
`).openPopup();
})();
</script>
<style>
.contact-page {
background: white;
padding-block: 100px;
}
.contact-page__grid {
align-items: start;
display: grid;
gap: clamp(2rem, 5vw, 4rem);
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.contact-page__copy {
color: var(--color-primary);
text-align: left;
}
.contact-page__copy :global(h2) {
margin: 0 0 25px;
}
.contact-page__copy :global(p) {
margin: 0 0 25px;
}
.contact-page__copy :global(.content-button) {
margin-bottom: 40px;
}
.contact-map-section {
background: white;
margin: 0;
padding: 0;
}
.contact-map {
height: 360px;
width: 100%;
}
@media (max-width: 992px) {
.contact-page {
padding-block: 50px;
}
}
@media (max-width: 767px) {
.contact-page__grid {
grid-template-columns: 1fr;
}
.contact-page__copy :global(.content-button) {
display: table;
margin-inline: auto;
}
}
</style>
+609
View File
@@ -0,0 +1,609 @@
---
import Button from '../Button.astro';
---
<article class="faq-page">
<div class="faq-source container source-page">
<slot />
</div>
<section class="faq-search container-narrow">
<div class="hs-search-field hs-search-field--initialized">
<div class="hs-search-field__bar hs-search-field__bar--button-inline">
<form class="hs-search-field__form" action="/search">
<label class="sr-only" for="faq-search-input">Search FAQs</label>
<input
id="faq-search-input"
type="search"
class="hs-search-field__input"
name="q"
autocomplete="off"
placeholder="Search"
data-faq-search
/>
<button class="hs-search-field__button" type="button" aria-label="Search">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" aria-hidden="true" width="18" height="18">
<path d="M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z" fill="#254080"/>
</svg>
</button>
</form>
</div>
</div>
</section>
<section class="faq-accordion" aria-labelledby="faq-questions-heading">
<div class="container-narrow faq-accordion__inner">
<h2 id="faq-questions-heading">Questions &amp; Answers</h2>
<div class="faq-list" data-faq-list></div>
</div>
</section>
<section class="faq-cta faq-cta-primary">
<div class="container-narrow">
<p class="eyebrow">Still have questions?</p>
<h2>Reach Out to Learn More</h2>
<p>We hope this FAQ gives you a clear picture of how Applied Behavior Analysis (ABA) therapy at the Arizona Institute for Autism can support your childs growth. If you have more questions or would like to <a href="/client-consultation">schedule an assessment</a>, please reach out. Our team is here to guide you and your learner every step of the way!</p>
</div>
</section>
<section class="faq-cta faq-cta-secondary">
<div class="container-narrow">
<h2>Need Support in Getting an Autism Diagnosis?</h2>
<p>To meet diagnostic criteria for ASD, a child must have persistent deficits in each of three areas of social communication and interaction plus at least two of four types of restricted repetitive behaviors. Consult with a Client Advocate today to receive individual and family support!</p>
<Button href="/client-consultation" center>Request an Appointment</Button>
</div>
</section>
</article>
<script>
const initFaqPage = () => {
const root = document.querySelector('.faq-page');
const source = root?.querySelector('.faq-source.source-page');
const list = root?.querySelector('[data-faq-list]');
const search = root?.querySelector('[data-faq-search]');
if (!(root instanceof HTMLElement) || !(source instanceof HTMLElement) || !(list instanceof HTMLElement) || !(search instanceof HTMLInputElement)) {
return;
}
const nodes = [...source.childNodes];
const firstQuestionIndex = nodes.findIndex((node) => node.nodeType === Node.ELEMENT_NODE && node.tagName === 'H3');
if (firstQuestionIndex === -1) {
return;
}
let index = firstQuestionIndex;
let openedFirst = false;
while (index < nodes.length) {
const node = nodes[index];
if (!(node instanceof HTMLElement) || node.tagName !== 'H3') {
index += 1;
continue;
}
const details = document.createElement('details');
details.className = 'faq';
details.open = !openedFirst;
const summary = document.createElement('summary');
const title = document.createElement('h3');
title.textContent = node.textContent?.trim() || '';
const icon = document.createElement('span');
icon.className = 'faq-icon';
icon.setAttribute('aria-hidden', 'true');
summary.append(title, icon);
details.appendChild(summary);
const answer = document.createElement('div');
answer.className = 'faq-answer interactive-faq-with-seo-schema-integration__list__answer';
const answerInner = document.createElement('div');
answerInner.className = 'faq-answer__inner';
index += 1;
while (index < nodes.length && !(nodes[index] instanceof HTMLElement && nodes[index].tagName === 'H3')) {
const answerNode = nodes[index];
if (answerNode.nodeType === Node.TEXT_NODE) {
const text = answerNode.textContent?.trim();
if (text) {
const paragraph = document.createElement('p');
paragraph.textContent = text;
answerInner.appendChild(paragraph);
}
} else {
answerInner.appendChild(answerNode.cloneNode(true));
}
answerNode.remove();
index += 1;
}
answer.appendChild(answerInner);
details.appendChild(answer);
list.appendChild(details);
openedFirst = true;
}
for (let i = firstQuestionIndex; i < nodes.length; i += 1) {
nodes[i].remove();
}
const faqItems = [...list.querySelectorAll('details.faq')];
const closeTimers = new WeakMap();
const closeHandlers = new WeakMap();
const getAnswer = (item) => item.querySelector('.interactive-faq-with-seo-schema-integration__list__answer');
const getAnswerInner = (item) => item.querySelector('.faq-answer__inner');
const setClosedStyles = (answer) => {
answer.style.height = '0px';
answer.style.opacity = '0';
answer.style.transform = 'translateY(-.35rem)';
};
const setOpenStyles = (answer) => {
answer.style.opacity = '1';
answer.style.transform = 'translateY(0)';
};
faqItems.forEach((item, index) => {
const answer = getAnswer(item);
if (!answer) {
return;
}
if (index === 0 && item.open) {
answer.style.height = 'auto';
setOpenStyles(answer);
delete item.dataset.state;
} else if (!item.open) {
answer.style.height = '0px';
setClosedStyles(answer);
}
});
const closeItem = (item) => {
if (!item.open || item.dataset.state === 'closing') {
return;
}
item.dataset.state = 'closing';
const answer = getAnswer(item);
const answerInner = getAnswerInner(item);
if (answer && answerInner) {
const priorHandler = closeHandlers.get(item);
if (priorHandler) {
answer.removeEventListener('transitionend', priorHandler);
}
answer.style.height = `${answerInner.scrollHeight}px`;
answer.offsetHeight; // force reflow
setClosedStyles(answer);
const onTransitionEnd = (event) => {
if (event.target !== answer || event.propertyName !== 'height') {
return;
}
item.removeAttribute('open');
delete item.dataset.state;
answer.style.height = '0px';
answer.removeEventListener('transitionend', onTransitionEnd);
closeHandlers.delete(item);
closeTimers.delete(item);
};
closeHandlers.set(item, onTransitionEnd);
answer.addEventListener('transitionend', onTransitionEnd);
}
const timer = window.setTimeout(() => {
const answerStillOpen = answer && answer.offsetHeight > 0;
if (!answerStillOpen) {
return;
}
item.removeAttribute('open');
delete item.dataset.state;
if (answer) {
answer.style.height = '0px';
}
closeHandlers.delete(item);
closeTimers.delete(item);
}, 360);
closeTimers.set(item, timer);
};
const openItem = (item) => {
if (item.open && item.dataset.state !== 'closing') {
return;
}
const timer = closeTimers.get(item);
if (timer) {
window.clearTimeout(timer);
closeTimers.delete(item);
}
const priorHandler = closeHandlers.get(item);
const answer = getAnswer(item);
if (priorHandler && answer) {
answer.removeEventListener('transitionend', priorHandler);
closeHandlers.delete(item);
}
item.setAttribute('open', '');
item.dataset.state = 'opening';
const answerInner = getAnswerInner(item);
if (answer && answerInner) {
answer.style.height = '0px';
setClosedStyles(answer);
answer.offsetHeight; // force reflow
window.requestAnimationFrame(() => {
answer.style.height = `${answerInner.scrollHeight}px`;
setOpenStyles(answer);
});
const onTransitionEnd = (event) => {
if (event.target !== answer || event.propertyName !== 'height') {
return;
}
if (item.dataset.state === 'opening') {
answer.style.height = 'auto';
delete item.dataset.state;
}
answer.removeEventListener('transitionend', onTransitionEnd);
};
answer.addEventListener('transitionend', onTransitionEnd);
}
};
faqItems.forEach((item) => {
const summary = item.querySelector('summary');
summary?.addEventListener('click', (event) => {
event.preventDefault();
const willOpen = !item.open;
faqItems.forEach((other) => {
if (other !== item) {
closeItem(other);
}
});
if (willOpen) {
openItem(item);
} else {
closeItem(item);
}
});
});
const applyFilter = () => {
const query = search.value.trim().toLowerCase();
faqItems.forEach((item) => {
const text = item.textContent?.toLowerCase() || '';
item.hidden = Boolean(query) && !text.includes(query);
});
};
search.addEventListener('input', applyFilter);
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initFaqPage, { once: true });
} else {
initFaqPage();
}
</script>
<style>
.faq-page {
padding-bottom: 0;
}
.faq-source {
padding-block: 4rem 1rem;
}
.faq-search {
margin-bottom: 1.5rem;
padding-block: 1rem 0.75rem;
}
.sr-only {
clip: rect(0, 0, 0, 0);
border: 0;
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
}
.hs-search-field {
margin-inline: auto;
width: min(780px, 100%);
}
.hs-search-field--initialized {
display: block;
}
.hs-search-field__bar {
display: block;
width: 100%;
}
.hs-search-field__form {
display: flex;
margin: 0;
width: 100%;
}
.hs-search-field__input {
appearance: none;
background: #fff;
border: 2px solid rgba(37, 64, 128, .2);
border-radius: 4px;
color: var(--color-primary);
flex: 1;
font: inherit;
line-height: 1.5;
min-height: 3.125rem;
min-width: 0;
padding: .9rem 1.25rem;
box-shadow: 0 1px 2px rgba(37, 64, 128, .06);
}
.hs-search-field__input::placeholder {
color: var(--color-muted);
opacity: 1;
}
.hs-search-field__input:focus {
border-color: var(--color-accent);
outline: none;
}
.hs-search-field__button {
align-items: center;
background: #fff;
border: 2px solid rgba(37, 64, 128, .2);
border-radius: 4px;
box-shadow: 0 1px 2px rgba(37, 64, 128, .06);
cursor: pointer;
display: flex;
flex: 0 0 auto;
justify-content: center;
margin-left: 2px;
min-height: 3.125rem;
opacity: .85;
padding-inline: 1rem;
}
.hs-search-field__button:hover {
opacity: 1;
}
.faq-accordion {
background: var(--color-tint);
padding-block: 2rem 4rem;
}
.faq-accordion__inner {
margin-inline: auto;
}
.faq-accordion h2 {
color: var(--color-primary);
font-family: var(--font-heading);
font-size: clamp(2rem, 4vw, 3rem);
margin: 0 0 1.75rem;
text-align: center;
}
:global(.faq-list) {
padding: 1.5rem 1.25rem 1rem;
}
:global(.faq-list .faq) {
background: transparent;
border-bottom: 1px solid var(--color-accent-strong);
padding: 0;
}
:global(.faq-list .faq:last-child) {
border-bottom: 0;
}
:global(.faq-list .faq[hidden]) {
display: none;
}
:global(.faq-list summary) {
align-items: center;
cursor: pointer;
display: flex;
gap: 1.5rem;
justify-content: space-between;
list-style: none;
padding: .875rem 0;
}
:global(.faq-list summary::-webkit-details-marker) {
display: none;
}
:global(.faq-list summary h3) {
color: var(--color-primary);
font-family: var(--font-body);
font-size: 1rem;
font-weight: 700;
line-height: 1.625;
margin: 0;
}
:global(.faq-list .faq-icon) {
flex: 0 0 auto;
display: block;
height: 12px;
margin-inline-start: auto;
position: relative;
width: 12px;
}
:global(.faq-list .faq-icon::after) {
border-bottom: 1px solid var(--color-accent-strong);
border-right: 1px solid var(--color-accent-strong);
content: "";
display: block;
height: 12px;
transform: translateY(-50%) rotate(45deg);
transform-origin: center;
transition: transform 300ms ease;
width: 12px;
}
:global(.faq-list details[open] .faq-icon::after) {
transform: rotate(-135deg);
}
:global(.faq-list .interactive-faq-with-seo-schema-integration__list__answer) {
height: 0;
margin-bottom: 0;
opacity: 0;
transform: translateY(-.35rem);
overflow: hidden;
transition: height .3s ease, margin-bottom .3s ease, opacity .3s ease, transform .3s ease;
}
:global(.faq-list .faq[open] .interactive-faq-with-seo-schema-integration__list__answer) {
margin-bottom: .85rem;
opacity: 1;
transform: translateY(0);
}
:global(.faq-list .faq-answer__inner) {
padding-bottom: .25rem;
}
:global(.faq-list .faq-answer p) {
margin: 0 0 1rem;
line-height: 1.7;
}
:global(.faq-list .faq-answer p:last-child) {
margin-bottom: 0;
}
:global(.faq-list .faq-answer__inner h4),
:global(.faq-list .faq-answer__inner h5) {
color: var(--color-primary);
font-family: var(--font-heading);
font-weight: 700;
margin-top: 0;
text-wrap: balance;
}
:global(.faq-list .faq-answer__inner h4) {
font-size: 2rem;
line-height: 2.5rem;
margin-bottom: 1.25rem;
}
:global(.faq-list .faq-answer__inner h5) {
font-size: 1.5rem;
line-height: 2rem;
margin-bottom: 1.25rem;
}
:global(.faq-list .faq-answer__inner :where(ul, ol)) {
margin-block: 0 1.5rem;
padding-inline-start: 2.5rem;
}
:global(.faq-list .faq-answer__inner :where(ul, ol) :where(ul, ol)) {
margin-block: .25rem 0;
}
:global(.faq-list .faq-answer__inner li) {
line-height: 1.625;
margin-block: 0;
padding-inline-start: .15rem;
}
:global(.faq-list .faq-answer__inner li > p) {
margin-block: 0;
}
:global(.faq-list .faq-answer__inner ul > li::marker) {
color: var(--color-accent-strong);
}
:global(.faq-list .faq-answer__inner ol > li::marker) {
color: var(--color-primary);
}
.faq-cta-primary {
background: var(--color-primary);
color: #fff;
padding-block: 3.5rem;
}
.faq-cta-primary .eyebrow {
color: #f9b34d;
}
.faq-cta-primary h2,
.faq-cta-primary p {
color: #fff;
}
.faq-cta-primary h2 {
font-size: clamp(1.8rem, 4vw, 2.8rem);
margin-bottom: .75rem;
}
.faq-cta-secondary {
background: #fff;
padding-block: 3.5rem 4rem;
}
.faq-cta-secondary h2 {
color: var(--color-primary);
font-size: clamp(1.8rem, 4vw, 2.8rem);
margin-bottom: .75rem;
}
.faq-cta-secondary :global(.content-button) {
margin-top: 1.5rem;
}
@media (min-width: 768px) {
.faq-source {
padding-top: 4.5rem;
}
.faq-search {
margin-bottom: 2rem;
padding-block-end: 1rem;
}
.faq-list {
padding: 2.5rem 2rem 1.5rem;
}
.faq-accordion h2 {
margin-bottom: 2rem;
}
}
</style>
@@ -1,17 +1,17 @@
--- ---
import { getEntry } from 'astro:content'; import { getEntry } from 'astro:content';
import BaseLayout from '../layouts/BaseLayout.astro'; import BaseLayout from '../../layouts/BaseLayout.astro';
import HomeBenefits from './home/HomeBenefits.astro'; import HomeBenefits from '../home/HomeBenefits.astro';
import HomeDirector from './home/HomeDirector.astro'; import HomeDirector from '../home/HomeDirector.astro';
import HomeEsa from './home/HomeEsa.astro'; import HomeEsa from '../home/HomeEsa.astro';
import HomeFinancialHelp from './home/HomeFinancialHelp.astro'; import HomeFinancialHelp from '../home/HomeFinancialHelp.astro';
import HomeHero from './home/HomeHero.astro'; import HomeHero from '../home/HomeHero.astro';
import HomeInsurance from './home/HomeInsurance.astro'; import HomeInsurance from '../home/HomeInsurance.astro';
import HomeProcess from './home/HomeProcess.astro'; import HomeProcess from '../home/HomeProcess.astro';
import HomeServicesIntro from './home/HomeServicesIntro.astro'; import HomeServicesIntro from '../home/HomeServicesIntro.astro';
import HomeSkills from './home/HomeSkills.astro'; import HomeSkills from '../home/HomeSkills.astro';
import HomeTestimonials from './home/HomeTestimonials.astro'; import HomeTestimonials from '../home/HomeTestimonials.astro';
import type { HomePageContent, HomeSection } from '../types/home-sections'; import type { HomePageContent, HomeSection } from '../../types/home-sections';
interface Props { lang?: string } interface Props { lang?: string }
const { lang = 'en' } = Astro.props; const { lang = 'en' } = Astro.props;
@@ -1,5 +1,5 @@
--- ---
import Button from './Button.astro'; import Button from '../Button.astro';
--- ---
<style> <style>
@@ -1,4 +1,6 @@
--- ---
import Button from '../Button.astro';
import ContactObfuscation from '../ContactObfuscation.astro';
const groups = [ const groups = [
{ {
title: 'Board Certified Behavioral Analysts & Psychologists', title: 'Board Certified Behavioral Analysts & Psychologists',
@@ -40,7 +42,7 @@ const groups = [
<article class="team-page"> <article class="team-page">
<section class="team-intro container-narrow"> <section class="team-intro container-narrow">
<h2>Our Clinical Team</h2> <h2>Our Clinical Team</h2>
<p class="script-label">Arizona Institute for Autism<br />Scottsdale, Arizona</p> <p class="eyebrow">Arizona Institute for Autism<br />Scottsdale, Arizona</p>
<p>AIA's clinical team consists of experienced professionals and paraprofessionals as well as Board Certified Behavior Analysts (BCBA) and Psychologists who have diverse experience and expertise.</p> <p>AIA's clinical team consists of experienced professionals and paraprofessionals as well as Board Certified Behavior Analysts (BCBA) and Psychologists who have diverse experience and expertise.</p>
</section> </section>
{groups.map((group) => ( {groups.map((group) => (
@@ -64,18 +66,18 @@ const groups = [
))} ))}
<section class="team-careers"> <section class="team-careers">
<div class="container-narrow"> <div class="container-narrow">
<p class="script-label">Join the AIA Team!</p> <p class="eyebrow">Join the AIA Team!</p>
<h2>Employment Opportunities</h2> <h2>Employment Opportunities</h2>
<p>Apply online to join the AIA team! At the Arizona Institute for Autism (AIA) we are on a mission to improve special education and strengthen communities throughout Arizona.</p> <p>Apply online to join the AIA team! At the Arizona Institute for Autism (AIA) we are on a mission to improve special education and strengthen communities throughout Arizona.</p>
<p>Our talented and passionate employees are a critical piece to the high-quality ABA therapy we provide along with our commitment to behavioral health, school solutions, and community outreach. For questions regarding open positions, please contact us at <a href="mailto:hr@azinstitute4autism.com">hr@azinstitute4autism.com</a>.</p> <p>Our talented and passionate employees are a critical piece to the high-quality ABA therapy we provide along with our commitment to behavioral health, school solutions, and community outreach. For questions regarding open positions, please contact us at <ContactObfuscation email="hr@azinstitute4autism.com" obfuscatedText="hr [at] abaclinicaz [dot] com" class="team-email" />.</p>
<a class="button" href="/careers">View Open Positions</a> <Button href="/careers">View Open Positions</Button>
</div> </div>
</section> </section>
</article> </article>
<style> <style>
.team-intro { padding-block: 4rem; text-align: center; } .team-intro { padding-block: 4rem; text-align: center; }
.team-intro .script-label { font-size: 1.8rem; } .team-intro .eyebrow { font-size: 1.8rem; }
.team-group { padding-block: 2rem 4rem; text-align: center; } .team-group { padding-block: 2rem 4rem; text-align: center; }
.team-group h2 { margin: 0 auto 1rem; max-width: 760px; } .team-group h2 { margin: 0 auto 1rem; max-width: 760px; }
.team-group__tagline { font-size: 1.125rem; margin: 0 auto 2rem; } .team-group__tagline { font-size: 1.125rem; margin: 0 auto 2rem; }
@@ -87,7 +89,8 @@ const groups = [
.team-member h3 { font-family: var(--font-body); font-size: .8rem; margin-bottom: 0; } .team-member h3 { font-family: var(--font-body); font-size: .8rem; margin-bottom: 0; }
.team-member p { font-size: .85rem; margin: 0; } .team-member p { font-size: .85rem; margin: 0; }
.team-careers { padding-block: 5rem; } .team-careers { padding-block: 5rem; }
.team-careers .button { margin-left: 50%; margin-top: 4rem; translate: -50%; } .team-careers :global(.content-button) { margin-left: 50%; margin-top: 4rem; translate: -50%; }
.team-email { font-weight: 700; }
@media (max-width: 950px) { @media (max-width: 950px) {
.team-member { flex-basis: min(100%, 227px); } .team-member { flex-basis: min(100%, 227px); }
} }
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Applied Behavior Analysis (ABA) is an evidence-based approach that utilizes the principles of behavior analysis to modify maladaptive behaviors and enhance socially significant behaviors. It is often employed for children with Autism Spectrum Disorder (ASD). ABA aims to teach a variety of skills, such as communication, social interactions, and daily skills, all within a safe, engaging, and fun environment conducive to therapeutic success. It also helps children minimize disruptive behaviors that may impede their learning, while prioritizing the child's individual autonomy. Applied Behavior Analysis (ABA) is an evidence-based approach that utilizes the principles of behavior analysis to modify maladaptive behaviors and enhance socially significant behaviors. It is often employed for children with Autism Spectrum Disorder (ASD). ABA aims to teach a variety of skills, such as communication, social interactions, and daily skills, all within a safe, engaging, and fun environment conducive to therapeutic success. It also helps children minimize disruptive behaviors that may impede their learning, while prioritizing the child's individual autonomy.
ABA therapy is highly beneficial for children with an autism diagnosis because it is tailored to each child's unique needs, optimizing outcomes. Skills are taught in a manner that maximizes the child's receptivity; this is achieved by breaking the skills into smaller, achievable targets. Furthermore, skills are generalized by teaching them across different settings and individuals. When a child begins receiving ABA therapy, progress is continuously monitored through ongoing data collection. This data is analyzed to ensure the efficacy of the intervention, and observations are made to guarantee that the child is learning effectively. An essential goal of ABA is not just short-term behavioral modification, but also the generalization and maintenance of learned skills over time. ABA therapy provides tools for managing challenging behaviors such as aggression, self-injury, or disruption. By understanding the function of these behaviors, suitable replacements can be taught, aiding the child's overall improvement. ABA therapy is highly beneficial for children with an autism diagnosis because it is tailored to each child's unique needs, optimizing outcomes. Skills are taught in a manner that maximizes the child's receptivity; this is achieved by breaking the skills into smaller, achievable targets. Furthermore, skills are generalized by teaching them across different settings and individuals. When a child begins receiving ABA therapy, progress is continuously monitored through ongoing data collection. This data is analyzed to ensure the efficacy of the intervention, and observations are made to guarantee that the child is learning effectively. An essential goal of ABA is not just short-term behavioral modification, but also the generalization and maintenance of learned skills over time. ABA therapy provides tools for managing challenging behaviors such as aggression, self-injury, or disruption. By understanding the function of these behaviors, suitable replacements can be taught, aiding the child's overall improvement.
@@ -21,4 +23,4 @@ Parental participation is a critical component of ABA Therapy. Parents and careg
At the Arizona Institute for Autism, our focus is on the learner. Our services are designed to meet individual needs, working collaboratively with a team of clinicians and parents. This approach aims to improve the quality of life for children with autism and their families. At the Arizona Institute for Autism, our focus is on the learner. Our services are designed to meet individual needs, working collaboratively with a team of clinicians and parents. This approach aims to improve the quality of life for children with autism and their families.
For more information on ABA therapy services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). If you are looking for more applied behavioral analysis and ASD diagnosis tips, check out [more articles](../library) from AIAs clinical director, Rula Diab! For more information on ABA therapy services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more applied behavioral analysis and ASD diagnosis tips, check out [more articles](../library) from AIAs clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Toilet training a child with autism can be a complex process that requires patience, consistency, and tailored strategies. Applied Behavior Analysis (ABA) offers effective techniques to support this journey. Here's a structured approach to facilitate toilet training for children with autism: Toilet training a child with autism can be a complex process that requires patience, consistency, and tailored strategies. Applied Behavior Analysis (ABA) offers effective techniques to support this journey. Here's a structured approach to facilitate toilet training for children with autism:
## 1. Assess Readiness ## 1. Assess Readiness
@@ -61,4 +63,4 @@ Engage with therapists or specialists experienced in ABA to develop and refine y
By implementing these strategies with patience and consistency, you can support your child with autism in achieving successful toilet training. By implementing these strategies with patience and consistency, you can support your child with autism in achieving successful toilet training.
For more information about ABA therapy services offered by AIA or to book your free consultation, visit our Arizona Institute for Autism website at [www.azinstitute4autism.com](../index), call [(480) 687-7099](tel:+14806877099), or email info@azinstitute4autism.com. If you are looking for more applied behavioral analysis and ASD diagnosis and treatment tips, check out more [blog posts](../library) from AIAs clinical director, Rula Diab! For more information about ABA therapy services offered by AIA or to book your free consultation, visit our Arizona Institute for Autism website at [www.azinstitute4autism.com](../index), call <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more applied behavioral analysis and ASD diagnosis and treatment tips, check out more [blog posts](../library) from AIAs clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Hello AIA families, Hello AIA families,
Happy April, a.k.a World Autism Month! Happy April, a.k.a World Autism Month!
@@ -45,4 +47,4 @@ Celebrate and support neurodiversity and inclusion with our AIA family by attend
## Additional questions? ## Additional questions?
If you have questions about AIA's World Autism Community Day of Celebration or are interested in providing a sensory-friendly booth, contact kelly@azinstitute4autism.com. If you have questions about AIA's World Autism Community Day of Celebration or are interested in providing a sensory-friendly booth, contact <ContactObfuscation email="kelly@azinstitute4autism.com" obfuscatedText="kelly [at] azinstitute4autism [dot] com" />.
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
As a parent of a child diagnosed with [autism spectrum disorder](https://www.autismspeaks.org/what-autism), you may experience challenges when it comes to mealtime. Many children on the spectrum struggle with [sensory and food sensitivities](https://www.eatright.org/health/health-conditions/intellectual-and-developmental-disabilities/nutrition-for-your-child-with-autism-spectrum-disorder-asd), making it difficult to find foods that they prefer. With Thanksgiving quickly approaching, you may be wondering if there are any recipes that your child may enjoy for the holiday. Well good news- you are in the right place! For this months blog, I will be sharing an easy, delicious Thanksgiving recipe that you and your child will both enjoy- Pumpkin Dump Cake! This recipe is a great twist on the classic pumpkin pie. As a parent of a child diagnosed with [autism spectrum disorder](https://www.autismspeaks.org/what-autism), you may experience challenges when it comes to mealtime. Many children on the spectrum struggle with [sensory and food sensitivities](https://www.eatright.org/health/health-conditions/intellectual-and-developmental-disabilities/nutrition-for-your-child-with-autism-spectrum-disorder-asd), making it difficult to find foods that they prefer. With Thanksgiving quickly approaching, you may be wondering if there are any recipes that your child may enjoy for the holiday. Well good news- you are in the right place! For this months blog, I will be sharing an easy, delicious Thanksgiving recipe that you and your child will both enjoy- Pumpkin Dump Cake! This recipe is a great twist on the classic pumpkin pie.
This recipe is super easy to follow, and the best part is that your child can help you! Being able to help prepare their food often makes it more enticing for them to eat. It also teaches your child [fundamental life skills](https://www.purdueglobal.edu/blog/psychology/cooking-activities-help-children-autism/), such as how to cook, make decisions, and how to follow directions, as well as strengthening their fine motor skills. Giving your child the opportunity to help you with this recipe can make it more enjoyable for the both of you! This recipe is super easy to follow, and the best part is that your child can help you! Being able to help prepare their food often makes it more enticing for them to eat. It also teaches your child [fundamental life skills](https://www.purdueglobal.edu/blog/psychology/cooking-activities-help-children-autism/), such as how to cook, make decisions, and how to follow directions, as well as strengthening their fine motor skills. Giving your child the opportunity to help you with this recipe can make it more enjoyable for the both of you!
@@ -73,4 +75,4 @@ If you have any leftovers, they can be stored for up to 4 days in the fridge or
This recipe is simple, easy, and delicious! We hope that you encourage your child to help you prepare the cake and have a great time while doing it. Enjoy! This recipe is simple, easy, and delicious! We hope that you encourage your child to help you prepare the cake and have a great time while doing it. Enjoy!
For more information on aba therapy services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at (480) 707-2195, or email info@azinstitute4autism.com. If you are looking for more applied behavioral analysis and asd diagnosis tips, check out AIAs clinical director, Rula Diab, monthly [blog posts](../library)! For more information on aba therapy services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at <ContactObfuscation phone="(480) 707-2195" hrefValue="+14807072195" obfuscatedText="5912-707 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more applied behavioral analysis and asd diagnosis tips, check out AIAs clinical director, Rula Diab, monthly [blog posts](../library)!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
If you are the parent of a child with autism spectrum disorder, you probably know how difficult mealtime can be. Many children with an autism diagnosis tend to have sensory processing disorder, which can make it difficult for them to enjoy certain foods due to the texture, consistency, temperature, etc. Your child may only prefer a small variety of foods, which often leaves their diet lacking the essential nutrients they need. In this blog series, I will be sharing sensory-friendly recipes and tips to hopefully make mealtime easy and fun for your kiddo! These recipes will help broaden your childs horizons when it comes to food and nutrition. If you are the parent of a child with autism spectrum disorder, you probably know how difficult mealtime can be. Many children with an autism diagnosis tend to have sensory processing disorder, which can make it difficult for them to enjoy certain foods due to the texture, consistency, temperature, etc. Your child may only prefer a small variety of foods, which often leaves their diet lacking the essential nutrients they need. In this blog series, I will be sharing sensory-friendly recipes and tips to hopefully make mealtime easy and fun for your kiddo! These recipes will help broaden your childs horizons when it comes to food and nutrition.
For this blog, I will be sharing an easy recipe that most kids love- Pancakes! This recipe can be modified to your childs liking, as its important to gradually introduce new foods and ingredients. Use ingredients that your child prefers in order to make it more enticing and enjoyable! For this blog, I will be sharing an easy recipe that most kids love- Pancakes! This recipe can be modified to your childs liking, as its important to gradually introduce new foods and ingredients. Use ingredients that your child prefers in order to make it more enticing and enjoyable!
@@ -89,4 +91,4 @@ Your kiddo may not want plain pancakes, which is perfectly fine! There are a few
Feel free to vary the recipe however you want and give your kiddo the opportunity to choose which toppings or fillings they want. Mealtime should be fun and enjoyable, so allowing your child to help you or pick their preferred ingredients can make eating more enticing for them. I hope you and your child enjoy this sensory-friendly pancake recipe! Feel free to vary the recipe however you want and give your kiddo the opportunity to choose which toppings or fillings they want. Mealtime should be fun and enjoyable, so allowing your child to help you or pick their preferred ingredients can make eating more enticing for them. I hope you and your child enjoy this sensory-friendly pancake recipe!
For more information on aba therapy services offered by AIA or to book your free consultation, visit our [contact page](../contact), call us at [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). If you are looking for more applied behavioral analysis and asd diagnosis tips, check out AIAs clinical director, Rula Diab, monthly blog posts! For more information on aba therapy services offered by AIA or to book your free consultation, visit our [contact page](../contact), call us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more applied behavioral analysis and asd diagnosis tips, check out AIAs clinical director, Rula Diab, monthly blog posts!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Children may exhibit maladaptive behaviors for various reasons, often driven by underlying functions. To address these behaviors, Applied Behavior clinicians use the [ABC model](https://www.iidc.indiana.edu/irca/articles/observing-behavior-using-a-b-c-data), a structured approach that helps identify patterns and triggers. This model involves observing a child's behavior in their natural environment, focusing on three key elements: the Antecedent (what happens before the behavior), the Behavior itself, and the Consequence (what follows the behavior). By carefully analyzing these factors, clinicians gain insights into why certain behaviors occur. Children may exhibit maladaptive behaviors for various reasons, often driven by underlying functions. To address these behaviors, Applied Behavior clinicians use the [ABC model](https://www.iidc.indiana.edu/irca/articles/observing-behavior-using-a-b-c-data), a structured approach that helps identify patterns and triggers. This model involves observing a child's behavior in their natural environment, focusing on three key elements: the Antecedent (what happens before the behavior), the Behavior itself, and the Consequence (what follows the behavior). By carefully analyzing these factors, clinicians gain insights into why certain behaviors occur.
Once the ABC data is collected, it guides clinicians in developing effective intervention strategies. By understanding the cause-and-effect relationship of behaviors, they can implement targeted consequences that reduce maladaptive behaviors while reinforcing positive alternatives. This process not only helps in decreasing unwanted actions but also encourages healthier coping mechanisms, fostering long-term behavioral improvements. Once the ABC data is collected, it guides clinicians in developing effective intervention strategies. By understanding the cause-and-effect relationship of behaviors, they can implement targeted consequences that reduce maladaptive behaviors while reinforcing positive alternatives. This process not only helps in decreasing unwanted actions but also encourages healthier coping mechanisms, fostering long-term behavioral improvements.
@@ -35,6 +37,6 @@ BCBA clinicians use [consequence interventions](https://specialconnections.ku.ed
## Looking for more information? ## Looking for more information?
For more information on services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at [(480) 687-7099](tel:+14806877099), or email [hello@azinstitute4autism.com](mailto:hello@azinstitute4autism.com). For more information on services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="hello@azinstitute4autism.com" obfuscatedText="hello [at] azinstitute4autism [dot] com" />.
If you are looking for tips, check out more monthly [blog posts](../library) from AIA's clinical director, Rula Diab! If you are looking for tips, check out more monthly [blog posts](../library) from AIA's clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Critical thinking is an important skill our children need to learn. It enables a child to generate the ability for a higher level of conceptual thinking and appropriately solve problems in their everyday life. Critical thinking is an important skill our children need to learn. It enables a child to generate the ability for a higher level of conceptual thinking and appropriately solve problems in their everyday life.
Children with Autism may lack the ability to appropriately communicate their feelings or sometimes tend to engage in repetitive ways of rigid thinking and repetitive behaviors. When they are faced with challenges, moments of frustration occur when no clear expectations are provided to our children regarding their daily schedule, and the activities they are required to engage in throughout the day. Children with Autism may lack the ability to appropriately communicate their feelings or sometimes tend to engage in repetitive ways of rigid thinking and repetitive behaviors. When they are faced with challenges, moments of frustration occur when no clear expectations are provided to our children regarding their daily schedule, and the activities they are required to engage in throughout the day.
@@ -33,4 +35,4 @@ Applied Behavior Analysis is “*the process of systematically applying interven
It is okay for our children to make errors, however, as caregivers and parents, we should create learning opportunities for our children, give them the emotional support they need and model proper responses. It is okay for our children to make errors, however, as caregivers and parents, we should create learning opportunities for our children, give them the emotional support they need and model proper responses.
For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to [hello@azinsitute4autism.com](mailto:hello@azinsitute4autism.com) or contact us directly from our contact page. For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to <ContactObfuscation email="hello@azinsitute4autism.com" obfuscatedText="hello [at] azinsitute4autism [dot] com" /> or contact us directly from our contact page.
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Generalization is a crucial aspect of learning, ensuring that skills and behaviors extend beyond the initial learning environment. Without generalization, individuals may struggle to apply what theyve learned to new situations, limiting the effectiveness of their education or therapy. Generalization is a crucial aspect of learning, ensuring that skills and behaviors extend beyond the initial learning environment. Without generalization, individuals may struggle to apply what theyve learned to new situations, limiting the effectiveness of their education or therapy.
In behavioral science, generalization refers to the process by which a learned behavior is applied across different stimuli, responses, or settings. In behavioral science, generalization refers to the process by which a learned behavior is applied across different stimuli, responses, or settings.
@@ -39,6 +41,6 @@ Understanding the three primary types of generalization—stimulus, response, an
## Looking for more information? ## Looking for more information?
For more information on services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). For more information on services offered by AIA, or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />.
If you are looking for more tips, check our [monthly blog posts](../library) from AIAs clinical director, Rula Diab! If you are looking for more tips, check our [monthly blog posts](../library) from AIAs clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
The Arizona Institute for Autism is thrilled to announce its transformation into an Integrated ABA Model, an approach that brings together clinicians and educators to provide exceptional intervention, learning experience, and individualized support for learners with autism. This model incorporates evidence-based interventions, ensuring a comprehensive approach tailored to each child's abilities, interests, and learning style. The Arizona Institute for Autism is thrilled to announce its transformation into an Integrated ABA Model, an approach that brings together clinicians and educators to provide exceptional intervention, learning experience, and individualized support for learners with autism. This model incorporates evidence-based interventions, ensuring a comprehensive approach tailored to each child's abilities, interests, and learning style.
By doing so, we aim to create a more effective and engaging treatment and learning process, addressing the diverse needs of each of our learners. Research has consistently demonstrated that effective ABA therapy can profoundly and positively impact children with autism, leading to long-lasting improvements in various areas of development. The Integrated ABA Model comprehensive nature enhances the potential for long-lasting improvements in various areas of development. By doing so, we aim to create a more effective and engaging treatment and learning process, addressing the diverse needs of each of our learners. Research has consistently demonstrated that effective ABA therapy can profoundly and positively impact children with autism, leading to long-lasting improvements in various areas of development. The Integrated ABA Model comprehensive nature enhances the potential for long-lasting improvements in various areas of development.
@@ -25,4 +27,4 @@ Our approach focuses on teaching children to apply the skills they acquire durin
At the Arizona Institute for Autism, we are committed to empowering children with autism, maximizing their potential for growth and development, and paving the way for a brighter future filled with endless possibilities. At the Arizona Institute for Autism, we are committed to empowering children with autism, maximizing their potential for growth and development, and paving the way for a brighter future filled with endless possibilities.
For more information on services offered by AIA or to book your free consultation, visit [https://www.azinstitute4autism.com](../index), call us at [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). If you are looking for more tips, check out monthly [blog posts](../library) from AIA's clinical director, Rula Diab! For more information on services offered by AIA or to book your free consultation, visit [https://www.azinstitute4autism.com](../index), call us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more tips, check out monthly [blog posts](../library) from AIA's clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Children with Autism may have difficulty communicating their needs and wants. Struggling to express their needs and escaping an unpreferred situation can all result in a child feeling frustrated. Not having control over their environment can often lead to aggressive and unengaging behaviors. Children with Autism may have difficulty communicating their needs and wants. Struggling to express their needs and escaping an unpreferred situation can all result in a child feeling frustrated. Not having control over their environment can often lead to aggressive and unengaging behaviors.
Communicating with our kiddos when they are engaging in challenging behaviors can be difficult. It is important to understand that behaviors are just an expression of distress. Understanding the function of your child's aggressive behavior can direct you to determine the proper ways to support your kiddos to communicate those needs appropriately and functionally. Communicating with our kiddos when they are engaging in challenging behaviors can be difficult. It is important to understand that behaviors are just an expression of distress. Understanding the function of your child's aggressive behavior can direct you to determine the proper ways to support your kiddos to communicate those needs appropriately and functionally.
@@ -33,4 +35,4 @@ The best strategy for parents to manage aggressive behavior outburst are the fol
- Use less verbal interaction and use more visuals to help to de-escalate the challenging behavior. - Use less verbal interaction and use more visuals to help to de-escalate the challenging behavior.
For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to hello@azinsitute4autism.com or contact us directly at www.azinstitute4autism.com/contactus. For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to <ContactObfuscation email="hello@azinsitute4autism.com" obfuscatedText="hello [at] azinsitute4autism [dot] com" /> or contact us directly at www.azinstitute4autism.com/contactus.
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
The start of a new year is often associated with feelings of joy and optimism. It is also a time for parents of children with autism to reflect on their child's progress and set goals for the future. Here are some important factors to keep in mind for New Year 2024 when it comes to Applied Behavioral Analysis (ABA) therapy and holiday time: The start of a new year is often associated with feelings of joy and optimism. It is also a time for parents of children with autism to reflect on their child's progress and set goals for the future. Here are some important factors to keep in mind for New Year 2024 when it comes to Applied Behavioral Analysis (ABA) therapy and holiday time:
- Take the time to review and celebrate the progress your child has made in the past year. Discuss any areas that need further development with your licensed Behavioral Analyst (BCBA) to ensure continued growth. - Take the time to review and celebrate the progress your child has made in the past year. Discuss any areas that need further development with your licensed Behavioral Analyst (BCBA) to ensure continued growth.
@@ -25,4 +27,4 @@ The start of a new year is often associated with feelings of joy and optimism. I
The New Year symbolizes growth and development, and that applies to children with autism as well. Take this time to reflect, plan, and prioritize the well-being of both the child receiving therapy and their caregivers. The New Year symbolizes growth and development, and that applies to children with autism as well. Take this time to reflect, plan, and prioritize the well-being of both the child receiving therapy and their caregivers.
For more information about ABA therapy services offered by AIA or to book your free consultation, visit our Arizona Institute for Autism website at [www.azinstitute4autism.com](../index), call [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). If you are looking for more applied behavioral analysis and ASD diagnosis and treatment tips, check out more [blog posts](../library) from AIAs clinical director, Rula Diab! For more information about ABA therapy services offered by AIA or to book your free consultation, visit our Arizona Institute for Autism website at [www.azinstitute4autism.com](../index), call <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more applied behavioral analysis and ASD diagnosis and treatment tips, check out more [blog posts](../library) from AIAs clinical director, Rula Diab!
@@ -13,8 +13,10 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
The New Year can be challenging for children with Autism and may lead to distress. Different factors affect the ability of children with autism to cope during those times. The inability to deal with changes and disruption in routines and cope with unclear expectations can be stressful. Additionally, sensory overload including loud music, bright lighting, strong smells, etc. may cause children to feel uncomfortable. The New Year can be challenging for children with Autism and may lead to distress. Different factors affect the ability of children with autism to cope during those times. The inability to deal with changes and disruption in routines and cope with unclear expectations can be stressful. Additionally, sensory overload including loud music, bright lighting, strong smells, etc. may cause children to feel uncomfortable.
To decrease stress as much as possible during the holiday time, it is important to provide your child with visual Support (i.e., visual schedules) for the purpose of preparing your child to manage changes in schedule and minimize disruption and triggers. Additionally, social stories can be great visual support to clarify activities and events during the holidays along with using a reinforcer system (i.e., Token System) to handle behaviors before it happens. To decrease stress as much as possible during the holiday time, it is important to provide your child with visual Support (i.e., visual schedules) for the purpose of preparing your child to manage changes in schedule and minimize disruption and triggers. Additionally, social stories can be great visual support to clarify activities and events during the holidays along with using a reinforcer system (i.e., Token System) to handle behaviors before it happens.
For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to [hello@azinsitute4autism.com](mailto:hello@azinsitute4autism.com) or contact us directly from our contact page. For more information on how to manage aggressive behavior and proper communication, connect with us by sending your messages and questions to <ContactObfuscation email="hello@azinsitute4autism.com" obfuscatedText="hello [at] azinsitute4autism [dot] com" /> or contact us directly from our contact page.
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Children can get overwhelmed, frustrated, and sensory overloaded at any time because of different needs, which can result in a child engaging in challenging behaviors. However, the common thing among all children is that they are in need of support with their communication skills. Different strategies can be used to prevent or minimize challenging behavior, including: Children can get overwhelmed, frustrated, and sensory overloaded at any time because of different needs, which can result in a child engaging in challenging behaviors. However, the common thing among all children is that they are in need of support with their communication skills. Different strategies can be used to prevent or minimize challenging behavior, including:
- Being proactive, instead of reacting to a childs behavior. Using proactive strategies that have the most significant impact can help in teaching children the skills they need to convey their needs/wants. Proactive strategies include Communication Skills, Coping Skills, Manding Skills, Attending Skills, etc. Waiting until the child is engaging in disruptive behaviors and then intervening is not beneficial, nor teachable for the child. - Being proactive, instead of reacting to a childs behavior. Using proactive strategies that have the most significant impact can help in teaching children the skills they need to convey their needs/wants. Proactive strategies include Communication Skills, Coping Skills, Manding Skills, Attending Skills, etc. Waiting until the child is engaging in disruptive behaviors and then intervening is not beneficial, nor teachable for the child.
@@ -23,4 +25,4 @@ Children can get overwhelmed, frustrated, and sensory overloaded at any time bec
- Allow your child to make a choice in the type of the activity or task presented (e.g., “Do you want to read a book about a cat or a book about a dog?”) or the place to engage in the activity (e.g. “Do you like to play with Lego inside or outside”). - Allow your child to make a choice in the type of the activity or task presented (e.g., “Do you want to read a book about a cat or a book about a dog?”) or the place to engage in the activity (e.g. “Do you like to play with Lego inside or outside”).
For more information on how to reduce behavior management, schedule a consultation with us today at [(480) 687-7099](tel:+14806877099) or reach out via our [contact form](../contact). For more information on how to reduce behavior management, schedule a consultation with us today at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" /> or reach out via our [contact form](../contact).
@@ -13,10 +13,12 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Children with autism often engage in repetitive behaviors as a way to cope with sensory overload. These behaviors can manifest in various ways including repetitive motor behaviors. Repetitive behaviors can affect children's learning experiences, social interactions, and engagement in daily activities. Children with autism often engage in repetitive behaviors as a way to cope with sensory overload. These behaviors can manifest in various ways including repetitive motor behaviors. Repetitive behaviors can affect children's learning experiences, social interactions, and engagement in daily activities.
As each child is unique and often requires tailored support, it's essential to comprehend each childs needs and preferences also offering alternative and functional ways for them to engage in these behaviors. Such adaptations can help children be more engaged throughout the day, as well as offer them a constructive outlet for emotional expression and self-soothing. The goal is to teach a child alternative behaviors that serve the same purpose but are more adaptable during structured environments. This allows for better focus and participation during activities requiring attention, while still giving them the coping mechanisms they need. Changing their surroundings can also reduce triggers that lead to repetitive behaviors. Therefore, it helps children to regulate their emotions in a socially acceptable manner, while still meeting their behavioral and emotional needs. As each child is unique and often requires tailored support, it's essential to comprehend each childs needs and preferences also offering alternative and functional ways for them to engage in these behaviors. Such adaptations can help children be more engaged throughout the day, as well as offer them a constructive outlet for emotional expression and self-soothing. The goal is to teach a child alternative behaviors that serve the same purpose but are more adaptable during structured environments. This allows for better focus and participation during activities requiring attention, while still giving them the coping mechanisms they need. Changing their surroundings can also reduce triggers that lead to repetitive behaviors. Therefore, it helps children to regulate their emotions in a socially acceptable manner, while still meeting their behavioral and emotional needs.
## Looking for more information? ## Looking for more information?
For more information on services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at [(480) 687-7099](tel:+14806877099), or email [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). If you are looking for more tips, check out monthly [blog posts](../library) from AIAs clinical director, Rula Diab! For more information on services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), contact us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />. If you are looking for more tips, check out monthly [blog posts](../library) from AIAs clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Parenting a child with autism is an immensely rewarding experience, but it also presents unique challenges. To provide the best support, it is crucial to navigate our children's development while comprehending their needs. Parenting a child with autism is an immensely rewarding experience, but it also presents unique challenges. To provide the best support, it is crucial to navigate our children's development while comprehending their needs.
In this blog post, we will delve into essential insights and practical tips to help parents better understand and support their child with autism. In this blog post, we will delve into essential insights and practical tips to help parents better understand and support their child with autism.
@@ -41,6 +43,6 @@ Remember, each child with autism is unique. By educating yourself, seeking suppo
## Looking for more information? ## Looking for more information?
For more information on services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), call us at [(480) 687-7099](tel:+14806877099), or email [hello@azinstitute4autism.com](mailto:hello@azinstitute4autism.com). For more information on services offered by AIA or to book your free consultation, visit us at [https://www.azinstitute4autism.com](../index), call us at <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, or email <ContactObfuscation email="hello@azinstitute4autism.com" obfuscatedText="hello [at] azinstitute4autism [dot] com" />.
If you are looking for more tips, check out [monthly blog posts](../library) from AIAs clinical director, Rula Diab! If you are looking for more tips, check out [monthly blog posts](../library) from AIAs clinical director, Rula Diab!
@@ -13,6 +13,8 @@ tags: []
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
La generalización es un aspecto crucial del aprendizaje, ya que garantiza que las habilidades y los comportamientos se extiendan más allá del entorno de aprendizaje inicial. Sin generalización, los individuos pueden tener dificultades para aplicar lo que han aprendido a nuevas situaciones, limitando la efectividad de su educación o terapia. La generalización es un aspecto crucial del aprendizaje, ya que garantiza que las habilidades y los comportamientos se extiendan más allá del entorno de aprendizaje inicial. Sin generalización, los individuos pueden tener dificultades para aplicar lo que han aprendido a nuevas situaciones, limitando la efectividad de su educación o terapia.
En la ciencia del comportamiento, la generalización se refiere al proceso por el cual una conducta aprendida se aplica a diferentes estímulos, respuestas o entornos. En la ciencia del comportamiento, la generalización se refiere al proceso por el cual una conducta aprendida se aplica a diferentes estímulos, respuestas o entornos.
@@ -39,6 +41,6 @@ Comprender los tres tipos principales de generalización (estímulo, respuesta y
## ¿Buscas más información? ## ¿Buscas más información?
Para más información sobre los servicios ofrecidos por AIA, o para reservar su consulta gratuita, visítenos en [https://www.azinstitute4autism.com](../../index), contáctenos en [(480) 687-7099](tel:+14806877099), o correo electrónico [info@azinstitute4autism.com](mailto:info@azinstitute4autism.com). Para más información sobre los servicios ofrecidos por AIA, o para reservar su consulta gratuita, visítenos en [https://www.azinstitute4autism.com](../../index), contáctenos en <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />, o correo electrónico <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />.
Si buscas más consejos, ¡consulta las [publicaciones mensuales de nuestro blog](../../library) de la directora clínica de AIA, Rula Diab! Si buscas más consejos, ¡consulta las [publicaciones mensuales de nuestro blog](../../library) de la directora clínica de AIA, Rula Diab!
+5 -5
View File
@@ -16,9 +16,9 @@ The Arizona Institute for Autism offers a variety of evidence-based, clinical se
Our ABA Therapy programs address the comprehensive needs of each learner, equipping children with the skills necessary to become independent learners. Our ABA Therapy programs address the comprehensive needs of each learner, equipping children with the skills necessary to become independent learners.
### Services We Offer ### Behavioral Services We Offer
Individual Learning <p class="eyebrow">Individual Learning</p>
#### ABA Therapy 1:1 Program #### ABA Therapy 1:1 Program
@@ -28,7 +28,7 @@ The ABA Therapy 1:1 program, designed for children aged 2 to 8 years, adopts an
Our ABA therapy focuses on improving socially significant behaviors by using positive reinforcement, systematic teaching, and data-driven methods. AIA Clinicians focus on tailoring our services to accommodate the unique neurodevelopmental profiles of each learner. Our ABA therapy focuses on improving socially significant behaviors by using positive reinforcement, systematic teaching, and data-driven methods. AIA Clinicians focus on tailoring our services to accommodate the unique neurodevelopmental profiles of each learner.
Group Learning <p class="eyebrow">Group Learning</p>
#### ABA Therapy 1:2 Academic Readiness Program #### ABA Therapy 1:2 Academic Readiness Program
@@ -38,7 +38,7 @@ The ABA Therapy 1:2 Academic Readiness Program is specifically designed for chil
The primary developmental milestones emphasized in this program include social, communication, cognitive, social-emotional, executive functioning, and motor skills. Throughout the Academic Readiness Program, your child will engage in a variety of structured electives such as speech therapy, recreational therapy, and music therapy. These electives, including circle time, arts and crafts, music, play, and other group interactions, that are designed to support skills development in these key areas. The primary developmental milestones emphasized in this program include social, communication, cognitive, social-emotional, executive functioning, and motor skills. Throughout the Academic Readiness Program, your child will engage in a variety of structured electives such as speech therapy, recreational therapy, and music therapy. These electives, including circle time, arts and crafts, music, play, and other group interactions, that are designed to support skills development in these key areas.
Family Education <p class="eyebrow">Family Education</p>
#### Parent Consultation Program #### Parent Consultation Program
@@ -50,7 +50,7 @@ Our goal is to empower families with the knowledge, tools, and support they need
These consultations provide parents with personalized guidance, training, and strategies tailored to their childs unique needs. These consultations provide parents with personalized guidance, training, and strategies tailored to their childs unique needs.
<Button href="https://form.jotform.com/231638510219149" target="_blank">Make an Appointment</Button> <Button href="https://form.jotform.com/231638510219149" target="_blank" center>Make an Appointment</Button>
## About Rula Diab, Chief Clinical Director, BCBA, LBA ## About Rula Diab, Chief Clinical Director, BCBA, LBA
@@ -50,4 +50,4 @@ ADOS is a structured evaluation tool used by our specialists to assess behaviors
This evaluation involves observing how your child interacts with various play-based social scenarios. For younger children, this may include activities like playing with blocks or having a snack, while older children who communicate verbally may participate in conversations about daily activities, such as attending school. This evaluation involves observing how your child interacts with various play-based social scenarios. For younger children, this may include activities like playing with blocks or having a snack, while older children who communicate verbally may participate in conversations about daily activities, such as attending school.
<Button href="https://form.jotform.com/231638510219149" target="_blank">Make an Appointment</Button> <Button href="https://form.jotform.com/231638510219149" target="_blank" center>Make an Appointment</Button>
+3 -3
View File
@@ -16,7 +16,7 @@ Apply to join the Arizona Institute for Autism (AIA) team today. We are on a mis
Our talented and passionate employees are a critical piece to the high-quality Autism services we provide along with our commitment to behavioral health, school solutions, and community outreach. Our talented and passionate employees are a critical piece to the high-quality Autism services we provide along with our commitment to behavioral health, school solutions, and community outreach.
<Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank">View Open Positions</Button> <Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank" center>View Open Positions</Button>
### Our Benefits ### Our Benefits
@@ -108,7 +108,7 @@ Work someone you love. Begin your journey with Arizona's leading ABA Integrated
![logo-BACB](/assets/images/logo-BACB.png) ![logo-BACB](/assets/images/logo-BACB.png)
<Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank">View Open Positions</Button> <Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank" center>View Open Positions</Button>
## Benefits of Working at Arizona Institute for Autism ## Benefits of Working at Arizona Institute for Autism
@@ -170,4 +170,4 @@ Take a fresh and innovative approach as a member of the Corporate team. Take on
Our specialty interns help shape the future of our center carefully curated clinical, operations, advocacy, people, and other departments. Our specialty interns help shape the future of our center carefully curated clinical, operations, advocacy, people, and other departments.
<Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank">View Open Positions</Button> <Button href="https://www.indeed.com/cmp/Arizona-Institute-For-Autism/jobs" target="_blank" center>View Open Positions</Button>
@@ -7,24 +7,25 @@ lang: "en"
translationKey: "contact" translationKey: "contact"
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
import Button from '../../../components/Button.astro';
## Schedule a Tour ## Schedule a Tour
Reach out to one of our expert Client Advocates to see if ABA-integrated therapy is right for your learner. Reach out to one of our expert Client Advocates to see if ABA-integrated therapy is right for your learner.
Schedule Tour <Button href="/tour">Schedule Tour</Button>
## Reach Out ## Reach Out
If you have questions about any of our services and programs, feel free to use the contact form on this page. You may also call or email using the following information. If you have questions about any of our services and programs, feel free to use the contact form on this page. You may also call or email using the following information.
General Inquiries: 9907-786 (084) **General Inquiries:** <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />
Billing Inquiries: 9240-807 (206) **Billing Inquiries:** <ContactObfuscation phone="(602) 708-0429" hrefValue="+16027080429" obfuscatedText="9240-807 (206)" />
Email: moc.msitua4etutitsniza@ofni **Email:** <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="moc.msitua4etutitsniza@ofni" />
Address: 8901 E. Raintree Drive, St #160 Scottsdale, AZ 85260 **Address:** 8901 E. Raintree Drive, St #160 Scottsdale, AZ 85260
Hours: Monday - Friday, 8am - 6pm MST **Hours:** Monday - Friday, 8am - 6pm MST
### Contact AIA
@@ -7,6 +7,8 @@ lang: "en"
translationKey: "donate-autism-giveback" translationKey: "donate-autism-giveback"
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
## Ways to Giveback ## Ways to Giveback
Every act of generosity, no matter how big or small, makes a difference at the Arizona Institute for Autism. Whether you donate items directly, support our Amazon iGiveback Wishlist, or contribute to our 501(c)(3) public charity, your support helps improve the lives of children with autism, their families, and the communities around them. Every act of generosity, no matter how big or small, makes a difference at the Arizona Institute for Autism. Whether you donate items directly, support our Amazon iGiveback Wishlist, or contribute to our 501(c)(3) public charity, your support helps improve the lives of children with autism, their families, and the communities around them.
@@ -21,7 +23,7 @@ Visit AIAs Amazon iGiveback Wishlist today, pick an item (or two!), and help
### Host a Fundraiser ### Host a Fundraiser
Would you like to host a fundraiser to benefit the Arizona Institute for Autism? Please contact us at moc.msitua4etutitsniza@ofni and a member of our team will be in touch to discuss next steps! All potential third party events will be evaluated in terms of their alignment with Arizona Institute for Autism's mission. Would you like to host a fundraiser to benefit the Arizona Institute for Autism? Please contact us at <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="moc.msitua4etutitsniza@ofni" /> and a member of our team will be in touch to discuss next steps! All potential third party events will be evaluated in terms of their alignment with Arizona Institute for Autism's mission.
## Community 4 Autism ## Community 4 Autism
File diff suppressed because it is too large Load Diff
@@ -9,6 +9,7 @@ draft: false
--- ---
import Button from '../../../components/Button.astro'; import Button from '../../../components/Button.astro';
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
## Learner Social Club ## Learner Social Club
@@ -19,13 +20,9 @@ Every child needs opportunities to have fun, make friends, and build social conn
Our integrative wellness enrichment services include: Our integrative wellness enrichment services include:
- Music - Music
- Art - Art
- Games - Games
- Dance - Dance
- Recreational activities - Recreational activities
These thoughtfully designed activities help nurture your learners mind and body, providing holistic wellness and saving you valuable time. These thoughtfully designed activities help nurture your learners mind and body, providing holistic wellness and saving you valuable time.
@@ -35,21 +32,17 @@ These thoughtfully designed activities help nurture your learners mind and bo
To ensure the best experience for your learner, please keep the following in mind: To ensure the best experience for your learner, please keep the following in mind:
- Potty Training: Learners must be potty-trained before enrolling. - Potty Training: Learners must be potty-trained before enrolling.
- Wipes: Pack wipes for your learner. These can be stored at our clinic. - Wipes: Pack wipes for your learner. These can be stored at our clinic.
- Snack & Water: Send your learner with a snack and water. These items can also be stored on-site. - Snack & Water: Send your learner with a snack and water. These items can also be stored on-site.
- Pause/Cancellation Notice: Please provide AIA staff with at least a 30-day notice if you plan to pause or cancel your Learner Social Club services. - Pause/Cancellation Notice: Please provide AIA staff with at least a 30-day notice if you plan to pause or cancel your Learner Social Club services.
### Program Schedule & Ages Served ### Program Schedule & Ages Served
![stem-sped-social-learners](/assets/images/stem-sped-social-learners.webp) ![stem-sped-social-learners](/assets/images/stem-sped-social-learners.webp)
The Learner Social Club currently serves youth learners aged 817 years . Our flexible scheduling options currently include: The Learner Social Club currently serves youth learners aged 817 years. Our flexible scheduling options currently include:
- 2 days/week (Monday, Wednesday): 4:00 PM 6:00 PM - 2 days/week (Monday, Wednesday): 4:00 PM 6:00 PM
- 1 day/week (Wednesday only): 4:00 PM 6:00 PM - 1 day/week (Wednesday only): 4:00 PM 6:00 PM
### Payment Information ### Payment Information
@@ -58,6 +51,6 @@ The Learner Social Club currently serves youth learners aged 817 years . Our
Interested in Trying Out Our Program? Interested in Trying Out Our Program?
Get a 1-Day Trial Pass by emailing us at info [at] azinstitute4autism [dot] com . Get a 1-Day Trial Pass by emailing us at <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />.
<Button href="https://form.jotform.com/231638510219149" target="_blank">Enroll Now</Button> <Button href="https://form.jotform.com/231638510219149" target="_blank" center>Enroll Now</Button>
@@ -7,6 +7,8 @@ lang: "en"
translationKey: "privacy-policy" translationKey: "privacy-policy"
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
Last updated: February 19, 2025 Last updated: February 19, 2025
## Introduction ## Introduction
@@ -123,10 +125,10 @@ We may update this privacy policy periodically. All changes will be posted on th
If you have any questions or concerns about this privacy policy or wish to exercise your privacy rights, please contact us at: If you have any questions or concerns about this privacy policy or wish to exercise your privacy rights, please contact us at:
- Email: info@azinstitute4autism.com - Email: <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />
- Address: 8901 E. Raintree Drive, Suite #160 Scottsdale Arizona 85260 - Address: 8901 E. Raintree Drive, Suite #160 Scottsdale Arizona 85260
- Phone: [(480) 687-7099](tel:+14806877099) - Phone: <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />
By using our website and services, you confirm that you have read, understood, and agree to the terms outlined in this privacy policy. By using our website and services, you confirm that you have read, understood, and agree to the terms outlined in this privacy policy.
@@ -7,6 +7,8 @@ lang: "en"
translationKey: "schedule-consultation" translationKey: "schedule-consultation"
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
We're here for you! We're here for you!
A Client Advocate from Arizona Institute for Autism will contact you within one business day upon submission of this form. A Client Advocate from Arizona Institute for Autism will contact you within one business day upon submission of this form.
@@ -37,13 +39,13 @@ Along with ABA therapy for children and teens diagnosed with autism, our support
![stem sped tech kids](/assets/images/stem-sped-tech-kids_446x.jpg) ![call us to schedule a free consultation](/assets/images/phone-1.svg) Phone ![stem sped tech kids](/assets/images/stem-sped-tech-kids_446x.jpg) ![call us to schedule a free consultation](/assets/images/phone-1.svg) Phone
(480) 687-7099 <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />
![email for more information](/assets/images/mail.svg) ![email for more information](/assets/images/mail.svg)
Email Email
info@abaclinicaz.com <ContactObfuscation email="info@abaclinicaz.com" obfuscatedText="info [at] abaclinicaz [dot] com" />
![located in scottsdale](/assets/images/map-pin.svg) ![located in scottsdale](/assets/images/map-pin.svg)
@@ -7,24 +7,25 @@ lang: "es"
translationKey: "contact" translationKey: "contact"
draft: false draft: false
--- ---
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
import Button from '../../../components/Button.astro';
## Programar una visita ## Programar una visita
Comuníquese con uno de nuestros defensores de clientes expertos para ver si la terapia integrada con ABA es adecuada para su alumno. Comuníquese con uno de nuestros defensores de clientes expertos para ver si la terapia integrada con ABA es adecuada para su alumno.
Programar visita <Button href="/tour">Programar visita</Button>
## Comunícate ## Comunícate
Si tiene preguntas sobre alguno de nuestros servicios y programas, no dude en utilizar el formulario de contacto de esta página. También puede llamar o enviar un correo electrónico utilizando la siguiente información. Si tiene preguntas sobre alguno de nuestros servicios y programas, no dude en utilizar el formulario de contacto de esta página. También puede llamar o enviar un correo electrónico utilizando la siguiente información.
Consultas generales: 9907-786 (084) **Consultas generales:** <ContactObfuscation phone="(480) 687-7099" hrefValue="+14806877099" obfuscatedText="9907-786 (084)" />
Consultas de facturación: 9240-807 (206) **Consultas de facturación:** <ContactObfuscation phone="(602) 708-0429" hrefValue="+16027080429" obfuscatedText="9240-807 (206)" />
Correo electrónico: moc.msitua4etutitsniza@ofni **Correo electrónico:** <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="moc.msitua4etutitsniza@ofni" />
Dirección: 8901 E. Raintree Drive, St #160 Scottsdale, AZ 85260 **Dirección:** 8901 E. Raintree Drive, St #160 Scottsdale, AZ 85260
Horas: Lunes - Viernes, 8am - 6pm MST **Horas:** Lunes - Viernes, 8am - 6pm MST
### Contactar a AIA
@@ -9,6 +9,7 @@ draft: false
--- ---
import Button from '../../../components/Button.astro'; import Button from '../../../components/Button.astro';
import ContactObfuscation from '../../../components/ContactObfuscation.astro';
## Learner Social Club ## Learner Social Club
@@ -46,7 +47,7 @@ Para garantizar la mejor experiencia para su hijo/a, tenga en cuenta lo siguient
![estudiantes participando en actividades sociales y STEM](/assets/images/stem-sped-social-learners.webp) ![estudiantes participando en actividades sociales y STEM](/assets/images/stem-sped-social-learners.webp)
Learner Social Club actualmente atiende a jóvenes de 8 a 17 años . Nuestras opciones de horario flexible actualmente incluyen: Learner Social Club actualmente atiende a jóvenes de 8 a 17 años. Nuestras opciones de horario flexible actualmente incluyen:
- 2 días/semana (lunes y miércoles): 4:00 p. m. 6:00 p. m. - 2 días/semana (lunes y miércoles): 4:00 p. m. 6:00 p. m.
@@ -58,6 +59,6 @@ Learner Social Club actualmente atiende a jóvenes de 8 a 17 años . Nuestras op
¿Le interesa probar nuestro programa? ¿Le interesa probar nuestro programa?
Obtenga un pase de prueba de 1 día enviándonos un correo electrónico a info [at] azinstitute4autism [dot] com . Obtenga un pase de prueba de 1 día enviándonos un correo electrónico a <ContactObfuscation email="info@azinstitute4autism.com" obfuscatedText="info [at] azinstitute4autism [dot] com" />.
<Button href="https://form.jotform.com/231638510219149" target="_blank">Enroll Now</Button> <Button href="https://form.jotform.com/231638510219149" target="_blank">Enroll Now</Button>
+3 -3
View File
@@ -12,8 +12,7 @@ const organizationSchema = {
'@type': 'MedicalOrganization', '@type': 'MedicalOrganization',
name: site.name, name: site.name,
url: site.url, url: site.url,
telephone: site.phone, // Contact details are rendered through ContactObfuscation to avoid plain text in HTML.
email: site.email,
address: { address: {
'@type': 'PostalAddress', '@type': 'PostalAddress',
streetAddress: '8901 E Raintree Dr Ste 160', streetAddress: '8901 E Raintree Dr Ste 160',
@@ -30,8 +29,9 @@ const organizationSchema = {
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<link rel="icon" href="/assets/images/aia-logo.svg" /> <link rel="icon" href="/assets/images/favicon.svg" />
<Seo title={title} description={description} canonical={canonical} image={image} lang={lang} type={type} /> <Seo title={title} description={description} canonical={canonical} image={image} lang={lang} type={type} />
<slot name="head" />
<script type="application/ld+json" set:html={JSON.stringify(organizationSchema)} /> <script type="application/ld+json" set:html={JSON.stringify(organizationSchema)} />
</head> </head>
<body> <body>
+13 -6
View File
@@ -1,14 +1,16 @@
--- ---
import BaseLayout from './BaseLayout.astro'; import BaseLayout from './BaseLayout.astro';
import FormShell from '../components/FormShell.astro'; import FormShell from '../components/FormShell.astro';
import TeamPage from '../components/TeamPage.astro'; import TeamPage from '../components/pages/TeamPage.astro';
import AboutPage from '../components/AboutPage.astro'; import AboutPage from '../components/pages/AboutPage.astro';
import ServicesPage from '../components/ServicesPage.astro'; import ServicesPage from '../components/pages/ServicesPage.astro';
import CareersPage from '../components/CareersPage.astro'; import CareersPage from '../components/pages/CareersPage.astro';
import ContactPage from '../components/pages/ContactPage.astro';
import FaqPage from '../components/pages/FaqPage.astro';
import PageHero from '../components/PageHero.astro'; import PageHero from '../components/PageHero.astro';
import { pageHeroImages } from '../data/page-visuals'; import { pageHeroImages } from '../data/page-visuals';
const { entry } = Astro.props; const { entry } = Astro.props;
const showForm = ['client-consultation', 'contact', 'schedule-consultation', 'referrals'].includes(entry.data.slug); const showForm = ['client-consultation', 'schedule-consultation', 'referrals'].includes(entry.data.slug);
const serviceTitles: Record<string, Record<string, string>> = { const serviceTitles: Record<string, Record<string, string>> = {
en: { en: {
'aba-therapy': 'Behavioral', 'aba-therapy': 'Behavioral',
@@ -52,7 +54,8 @@ const isService = Boolean(serviceTitles[entry.data.lang]?.[entry.data.slug]);
const heroImage = pageHeroImages[entry.data.slug]; const heroImage = pageHeroImages[entry.data.slug];
--- ---
<BaseLayout title={entry.data.title} description={entry.data.description} canonical={entry.data.canonical} image={entry.data.featuredImage || heroImage} lang={entry.data.lang}> <BaseLayout title={entry.data.title} description={entry.data.description} canonical={entry.data.canonical} image={entry.data.featuredImage || heroImage} lang={entry.data.lang}>
<PageHero title={bannerTitle} image={heroImage} constrain /> {entry.data.slug === 'contact' && <Fragment slot="head"><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" /></Fragment>}
<PageHero title={bannerTitle} subtitle={entry.data.slug === 'faqs' ? 'FAQs' : undefined} image={heroImage} constrain />
{entry.data.slug === 'team' && entry.data.lang === 'en' {entry.data.slug === 'team' && entry.data.lang === 'en'
? <TeamPage /> ? <TeamPage />
: entry.data.slug === 'about' && entry.data.lang === 'en' : entry.data.slug === 'about' && entry.data.lang === 'en'
@@ -61,6 +64,10 @@ const heroImage = pageHeroImages[entry.data.slug];
? <ServicesPage /> ? <ServicesPage />
: entry.data.slug === 'careers' && entry.data.lang === 'en' : entry.data.slug === 'careers' && entry.data.lang === 'en'
? <CareersPage /> ? <CareersPage />
: entry.data.slug === 'faqs' && entry.data.lang === 'en'
? <FaqPage><slot /></FaqPage>
: entry.data.slug === 'contact'
? <ContactPage title={bannerTitle}><slot /></ContactPage>
: <article class:list={['prose', 'source-page', 'container', { 'service-page': isService }]}><slot /></article>} : <article class:list={['prose', 'source-page', 'container', { 'service-page': isService }]}><slot /></article>}
{showForm && <FormShell title={bannerTitle} showBackground={entry.data.slug === 'client-consultation'} />} {showForm && <FormShell title={bannerTitle} showBackground={entry.data.slug === 'client-consultation'} />}
</BaseLayout> </BaseLayout>
+1 -1
View File
@@ -1,4 +1,4 @@
--- ---
import HomePage from '../../components/HomePage.astro'; import HomePage from '../../components/pages/HomePage.astro';
--- ---
<HomePage lang="es" /> <HomePage lang="es" />
+1 -1
View File
@@ -1,4 +1,4 @@
--- ---
import HomePage from '../components/HomePage.astro'; import HomePage from '../components/pages/HomePage.astro';
--- ---
<HomePage lang="en" /> <HomePage lang="en" />
+23
View File
@@ -0,0 +1,23 @@
const allowIndexing = import.meta.env.PUBLIC_ALLOW_INDEXING === 'true';
const body = allowIndexing
? [
'User-agent: *',
'Allow: /',
'Sitemap: https://www.azinstitute4autism.com/sitemap.xml',
''
].join('\n')
: [
'User-agent: *',
'Allow: /',
'# Staging and migration builds emit meta robots noindex,nofollow.',
''
].join('\n');
export function GET() {
return new Response(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8'
}
});
}
+1 -7
View File
@@ -1,5 +1,5 @@
.prose { padding-block: var(--space-xl); } .prose { padding-block: var(--space-xl); }
.prose h2, .prose h3 { margin-top: 2em; } .prose h2, .prose h3 { margin-top: 1.75em; }
.prose img { border-radius: var(--radius-md); margin-block: var(--space-lg); } .prose img { border-radius: var(--radius-md); margin-block: var(--space-lg); }
.prose a { overflow-wrap: anywhere; text-decoration: none; } .prose a { overflow-wrap: anywhere; text-decoration: none; }
.prose p a, .prose td a { color: var(--color-accent-strong); text-decoration: none; } .prose p a, .prose td a { color: var(--color-accent-strong); text-decoration: none; }
@@ -9,15 +9,9 @@
.blog-post-body blockquote p { color: var(--color-primary); margin: 0 0 1.55rem; } .blog-post-body blockquote p { color: var(--color-primary); margin: 0 0 1.55rem; }
.source-page { max-width: 980px; } .source-page { max-width: 980px; }
.source-page > h2:first-of-type { margin-top: 0; } .source-page > h2:first-of-type { margin-top: 0; }
.service-page > p > img, .service-page > img { float: right; margin: .5rem 0 1.5rem 2rem; max-height: 230px; max-width: 300px; object-fit: cover; }
.service-page h3 { font-size: 2rem; }
.service-page h3 + p { color: var(--color-accent-strong); font-family: var(--font-accent); font-size: 1.5rem; margin-bottom: -.8rem; }
.blog-post-body { max-width: 960px; } .blog-post-body { max-width: 960px; }
.blog-post-body p { margin-bottom: 1.55rem; } .blog-post-body p { margin-bottom: 1.55rem; }
.blog-post-body table { border: 1px solid #d7d9e3; border-collapse: collapse; display: table; margin: 0 0 1.4rem; width: 100%; } .blog-post-body table { border: 1px solid #d7d9e3; border-collapse: collapse; display: table; margin: 0 0 1.4rem; width: 100%; }
.blog-post-body td, .blog-post-body th { border: 1px solid #d7d9e3; padding: 10px; } .blog-post-body td, .blog-post-body th { border: 1px solid #d7d9e3; padding: 10px; }
.blog-post-body th { background: var(--color-primary); color: #fff; } .blog-post-body th { background: var(--color-primary); color: #fff; }
.blog-post-body td { background: #fff; color: var(--color-primary); } .blog-post-body td { background: #fff; color: var(--color-primary); }
@media (max-width: 700px) {
.service-page > p > img, .service-page > img { float: none; margin: 1.5rem 0; max-width: 100%; width: 100%; }
}
-4
View File
@@ -1,7 +1,3 @@
.button { background: var(--color-accent); border: 2px solid var(--color-accent); border-radius: 4px; color: var(--color-primary); display: inline-block; padding: .65rem 1.2rem; text-decoration: none; transition: .3s linear all; }
.button:hover { background: transparent; border-color: var(--color-accent-strong); color: var(--color-primary); }
.button-small { font-size: .9rem; }
.button-light { background: white; color: var(--color-primary-dark); }
.card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; } .card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
.card img { aspect-ratio: 16/10; object-fit: cover; width: 100%; } .card img { aspect-ratio: 16/10; object-fit: cover; width: 100%; }
.card-body { padding: var(--space-lg); } .card-body { padding: var(--space-lg); }
+1
View File
@@ -4,3 +4,4 @@
@import './components.css'; @import './components.css';
@import './forms.css'; @import './forms.css';
@import './blog.css'; @import './blog.css';
@import './pages.css';
-1
View File
@@ -9,7 +9,6 @@ img { display: block; height: auto; max-width: 100%; }
.section-tint, .page-header { background: var(--color-tint); } .section-tint, .page-header { background: var(--color-tint); }
.section-heading { margin-bottom: var(--space-lg); max-width: 700px; } .section-heading { margin-bottom: var(--space-lg); max-width: 700px; }
.split { align-items: center; display: flex; gap: var(--space-lg); justify-content: space-between; } .split { align-items: center; display: flex; gap: var(--space-lg); justify-content: space-between; }
.button-center { margin-block: 2.5rem; margin-inline-start: 50%; translate: -50%; }
.card-grid { display: grid; gap: var(--space-lg); grid-template-columns: repeat(3, minmax(0, 1fr)); } .card-grid { display: grid; gap: var(--space-lg); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.skip-link { background: white; left: 1rem; padding: .75rem; position: fixed; top: -10rem; z-index: 100; } .skip-link { background: white; left: 1rem; padding: .75rem; position: fixed; top: -10rem; z-index: 100; }
.skip-link:focus { top: 1rem; } .skip-link:focus { top: 1rem; }
+5
View File
@@ -0,0 +1,5 @@
.service-page > p > img, .service-page > img { float: right; margin: .5rem 0 0 2rem; max-height: 300px; max-width: 300px; object-fit: cover; }
.service-page h3 { font-size: 2rem; }
@media (max-width: 700px) {
.service-page > p > img, .service-page > img { float: none; margin: 1.5rem 0; max-width: 100%; width: 100%; }
}
+17 -7
View File
@@ -3,16 +3,26 @@
@font-face { font-family: Rubik; src: url('/assets/fonts/Rubik/regular.woff2') format('woff2'); font-display: swap; } @font-face { font-family: Rubik; src: url('/assets/fonts/Rubik/regular.woff2') format('woff2'); font-display: swap; }
@font-face { font-family: Rubik; src: url('/assets/fonts/Rubik/700.woff2') format('woff2'); font-weight: 700; font-display: swap; } @font-face { font-family: Rubik; src: url('/assets/fonts/Rubik/700.woff2') format('woff2'); font-weight: 700; font-display: swap; }
body { color: var(--color-text); font-family: var(--font-body); font-size: 16px; line-height: 1.625; } body { color: var(--color-text); font-family: var(--font-body); font-size: 16px; line-height: 1.625; }
h1, h2, h3 { color: var(--color-primary); font-family: var(--font-heading); line-height: 1.15; text-wrap: balance; } h1, h2, h3, h4 { color: var(--color-primary); font-family: var(--font-heading); line-height: 1.15; text-wrap: balance; }
.no-balance { text-wrap: auto; } .no-balance { text-wrap: auto; }
h1 { font-size: clamp(2.5rem, 5vw, 3rem); line-height: 1.12; margin: 0 0 var(--space-md); } h1 { font-size: clamp(2.5rem, 5vw, 3rem); line-height: 1.12; margin: 0 0 var(--space-md); }
h2 { font-size: clamp(2rem, 4vw, 2.4rem); line-height: 1.25; } h2 { font-size: clamp(2rem, 4vw, 2.4rem); line-height: 1.25; }
h3 { font-size: clamp(1.5rem, 3vw, 2rem); } h3 { font-size: clamp(1.8rem, 3.4vw, 2rem); }
a { color: var(--color-primary); } h4 { font-size: clamp(1.5rem, 3vw, 1.8rem); }
.eyebrow { color: var(--color-secondary); font-size: .8rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; } a, a:visited { color: var(--color-accent-strong); text-decoration: none; }
.lede, .hero-copy { color: var(--color-muted); font-size: 1.25rem; } a:hover, a:active { color: var(--color-accent); }
.script-label { color: var(--color-accent-strong); font-family: var(--font-accent); font-size: 2rem; margin: 0; }
.script-label + h2 { margin-top: 0; }
.eyebrow {
margin: 0;
color: var(--color-accent-strong);
font-family: var(--font-accent);
font-size: 2rem;
}
.eyebrow + :is(h1, h2, h3, h4, h5, h6) {
margin-block-start: 0;
}
.prose :where(ul, ol) { .prose :where(ul, ol) {
margin-block: 0 1.5rem; margin-block: 0 1.5rem;
-220
View File
@@ -1,220 +0,0 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const mirror = path.resolve(root, '../www.azinstitute4autism.com');
const content = path.join(root, 'src/content');
const assets = path.join(root, 'public/assets');
const reports = path.join(root, 'reports');
const site = 'https://www.azinstitute4autism.com';
const mkdir = (value) => fs.mkdir(value, { recursive: true });
const quote = (value = '') => JSON.stringify(String(value).replace(/\s+/g, ' ').trim());
const csv = (value = '') => `"${String(value).replaceAll('"', '""')}"`;
const blogPreamble = /^# .+\n\n!\[[^\]]*\]\(\/assets\/images\/rula-diab-avatar\.jpg\)\n\n[^\n]+\n\n[^\n]+\n\n!\[[^\]]*\]\([^)]+\)\n\n/;
async function walk(dir, prefix = '') {
const output = [];
for (const entry of await fs.readdir(dir, { withFileTypes: true })) {
const relative = path.join(prefix, entry.name);
if (entry.isDirectory()) output.push(...await walk(path.join(dir, entry.name), relative));
else output.push(relative);
}
return output;
}
function logical(file) {
return file.replace(/(?:\.html)?\?(?:hsLang=[^.]+|hs_amp=true)\.html$/, '.html');
}
function selectCanonical(files) {
const map = new Map();
for (const file of files) {
if (!file.endsWith('.html') || file.includes('hs_amp=true') || /\/(?:page|author)\//.test(file)) continue;
const target = logical(file);
const key = `${target.startsWith('ar/') ? 'ar' : target.startsWith('es/') ? 'es' : 'en'}:${target}`;
if (!map.has(key) || (!file.includes('?') && map.get(key).includes('?'))) map.set(key, file);
}
return [...map.values()];
}
function decode(value = '') {
return value
.replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code)))
.replace(/&#x([\da-f]+);/gi, (_, code) => String.fromCodePoint(parseInt(code, 16)))
.replaceAll('&amp;', '&').replaceAll('&quot;', '"').replaceAll('&#39;', "'")
.replaceAll('&lt;', '<').replaceAll('&gt;', '>').replaceAll('&nbsp;', ' ');
}
function text(value = '') {
return decode(value.replace(/<[^>]+>/g, ' ')).replace(/\s+/g, ' ').trim();
}
function normalizeHref(value = '') {
return decode(value)
.replace(/^https?:\/\/www\.azinstitute4autism\.com/, '')
.replace(/(?:\.html)?(?:%3F|\?)(?:hsLang=[^.#]+|hs_amp=true)(?:\.html)?$/, '')
.replace(/\.html$/, '')
.replace(/^index$/, '/');
}
function inline(value = '') {
return text(value.replace(/<a[^>]+href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, label) => {
const cleanLabel = text(label);
return cleanLabel ? `[${cleanLabel}](${normalizeHref(href)})` : '';
}));
}
function meta(html, name, property = false) {
const key = property ? 'property' : 'name';
const pattern = new RegExp(`<meta[^>]+${key}=["']${name}["'][^>]+content=["']([^"']*)`, 'i');
const reverse = new RegExp(`<meta[^>]+content=["']([^"']*)["'][^>]+${key}=["']${name}["']`, 'i');
return decode(html.match(pattern)?.[1] || html.match(reverse)?.[1] || '');
}
function asset(value = '') {
const match = value.match(/(?:hs-fs\/)?hubfs\/([^?#]+)/);
return match ? `/assets/images/${path.basename(decodeURIComponent(match[1])).split('?')[0]}` : undefined;
}
function normalizeTable(value = '') {
return value
.replace(/(<a\b[^>]*\bhref=["'])([^"']+)(["'])/gi,
(_, prefix, href, suffix) => `${prefix}${normalizeHref(href)}${suffix}`)
.replace(/(<img\b[^>]*\bsrc=["'])([^"']+)(["'])/gi,
(_, prefix, src, suffix) => `${prefix}${asset(src) || src}${suffix}`);
}
function markdownFrom(html) {
let body = html.match(/<main[\s\S]*?<\/main>/i)?.[0] ||
html.match(/blog-post__body[\s\S]*?(?=<footer|blog-post__tags|<\/article>)/i)?.[0] ||
'';
const tables = [];
body = body
.replace(/<(script|style|noscript|header|footer|nav|form)\b[\s\S]*?<\/\1>/gi, '')
.replace(/<table[\s\S]*?<\/table>/gi, (match) => {
const token = `__TABLE_${tables.length}__`;
tables.push(normalizeTable(match));
return `\n\n${token}\n\n`;
})
.replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, (_, value) => `\n\n> ${inline(value)}\n\n`)
.replace(/<img[^>]+src=["']([^"']+)["'][^>]*alt=["']([^"']*)["'][^>]*>/gi, (_, src, alt) => {
const local = asset(src);
return local ? `\n\n![${text(alt)}](${local})\n\n` : '';
})
.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_, level, value) => `\n\n${'#'.repeat(Number(level))} ${inline(value)}\n\n`)
.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, (_, value) => `\n- ${inline(value)}`)
.replace(/<p[^>]*>([\s\S]*?)<\/p>/gi, (_, value) => `\n\n${inline(value)}\n\n`)
.replace(/<br\s*\/?>/gi, '\n')
.replace(/<[^>]+>/g, ' ');
body = decode(body).replace(/[ \t]+/g, ' ').replace(/^\s+$/gm, '').replace(/\n{3,}/g, '\n\n').trim();
return tables.reduce((output, table, index) => output.replaceAll(`__TABLE_${index}__`, table), body);
}
function record(file, html) {
const target = logical(file);
const lang = target.startsWith('ar/') ? 'ar' : target.startsWith('es/') ? 'es' : 'en';
const url = target === 'index.html' ? '/' : `/${target.replace(/\/index\.html$/, '').replace(/\.html$/, '')}`;
const title = text(html.match(/<title[^>]*>([\s\S]*?)<\/title>/i)?.[1] || url);
const h1 = text(html.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i)?.[1] || title);
const published = meta(html, 'article:published_time', true) ||
html.match(/<time[^>]+datetime=["']([^"']+)/i)?.[1] || '';
return {
file, lang, url, title, h1,
description: meta(html, 'description'),
image: asset(meta(html, 'og:image', true)),
date: /^\d{4}-\d{2}-\d{2}/.test(published) ? published.slice(0, 10) : '2024-01-01',
markdown: markdownFrom(html)
};
}
function frontmatter(item, blog) {
const slug = ['/', '/ar', '/es'].includes(item.url) ? 'index' : item.url.split('/').filter(Boolean).at(-1);
const lines = [
'---',
`title: ${quote(item.title)}`,
`description: ${quote(item.description)}`,
`slug: ${quote(slug)}`,
`canonical: ${quote(`${site}${item.url}`)}`,
`lang: ${quote(item.lang)}`,
`translationKey: ${quote(slug)}`,
item.image ? `featuredImage: ${quote(item.image)}` : '',
blog ? `date: "${item.date}"` : '',
blog ? 'author: "rula-diab"' : '',
blog ? 'category: "Library"' : '',
blog ? 'tags: []' : '',
'draft: false',
'---',
'',
(blog ? item.markdown.replace(blogPreamble, '') : item.markdown) || `# ${item.h1}`,
''
].filter((line) => line !== '');
return `${lines.join('\n')}\n`;
}
async function copySourceAssets(files) {
const rows = ['source,target,size,kind'];
const seen = new Set();
await Promise.all(['images', 'fonts', 'downloads'].map((kind) => fs.rm(path.join(assets, kind), { recursive: true, force: true })));
for (const file of files.filter((name) => name.startsWith('hubfs/') || name.startsWith('hs-fs/hubfs/') || name.startsWith('_hcms/googlefonts/'))) {
const font = file.startsWith('_hcms/googlefonts/');
const raw = font ? file.replace('_hcms/googlefonts/', '') : path.basename(file).split('?')[0];
if (!font && !/\.(?:avif|gif|jpe?g|png|svg|webp|pdf)$/i.test(raw)) continue;
const key = `${font}:${raw}`;
if (!raw || seen.has(key)) continue;
seen.add(key);
const kind = font ? 'fonts' : raw.endsWith('.pdf') ? 'downloads' : 'images';
const target = path.join(assets, kind, raw);
await mkdir(path.dirname(target));
await fs.copyFile(path.join(mirror, file), target);
const size = (await fs.stat(target)).size;
rows.push([file, path.relative(root, target), size, kind].map(csv).join(','));
}
await fs.writeFile(path.join(reports, 'asset-inventory.csv'), `${rows.join('\n')}\n`);
}
async function removeMissingFeaturedImages() {
for (const type of ['pages', 'blog']) {
for (const file of await walk(path.join(content, type))) {
const target = path.join(content, type, file);
let source = await fs.readFile(target, 'utf8');
const image = source.match(/^featuredImage:\s*"\/assets\/images\/([^"]+)"/m)?.[1];
if (!image) continue;
if (!await fs.access(path.join(assets, 'images', image)).then(() => true).catch(() => false)) {
source = source.replace(/^featuredImage:.*\n/m, '');
await fs.writeFile(target, source);
}
}
}
}
async function main() {
const files = await walk(mirror);
const selected = selectCanonical(files);
const records = [];
for (const file of selected) records.push(record(file, await fs.readFile(path.join(mirror, file), 'utf8')));
await Promise.all(['pages', 'blog', 'authors'].map((type) => fs.rm(path.join(content, type), { recursive: true, force: true })));
for (const lang of ['en', 'ar', 'es']) {
for (const type of ['pages', 'blog', 'authors']) await mkdir(path.join(content, type, lang));
}
for (const item of records) {
const blog = item.url.includes('/library/') && !item.url.endsWith('/library');
const slug = ['/', '/ar', '/es'].includes(item.url) ? 'index' : item.url.split('/').filter(Boolean).at(-1);
await fs.writeFile(path.join(content, blog ? 'blog' : 'pages', item.lang, `${slug}.md`), frontmatter(item, blog));
}
for (const lang of ['en', 'ar', 'es']) {
await fs.writeFile(path.join(content, 'authors', lang, 'rula-diab.md'), `---\nname: "Rula Diab"\nslug: "rula-diab"\ndescription: "Founder and clinical leader at Arizona Institute for Autism."\navatar: "/assets/images/rula-diab-avatar.jpg"\nlang: "${lang}"\ntranslationKey: "rula-diab"\n---\n`);
}
if (!records.some((item) => item.lang === 'ar' && item.url === '/ar')) {
await fs.writeFile(path.join(content, 'pages/ar/index.md'), `---\ntitle: "معهد أريزونا للتوحد"\ndescription: "صفحة عربية تمهيدية لمعهد أريزونا للتوحد."\nslug: "index"\ncanonical: "https://www.azinstitute4autism.com/ar"\nlang: "ar"\ntranslationKey: "home"\ndraft: false\n---\n\n<!-- TODO: Replace this placeholder with reviewed Arabic content. -->\n\nتتوفر المقالات العربية الحالية في المكتبة. يرجى مراجعة المحتوى العربي قبل النشر.\n`);
}
const rows = ['source_file,url,language,type,title,description,h1'];
for (const item of records) rows.push([item.file, item.url, item.lang, item.url.includes('/library/') ? 'blog' : 'page', item.title, item.description, item.h1].map(csv).join(','));
await mkdir(reports);
await fs.writeFile(path.join(reports, 'url-inventory.csv'), `${rows.join('\n')}\n`);
await copySourceAssets(files);
await removeMissingFeaturedImages();
console.log(`Fallback extraction completed: ${records.length} canonical records.`);
}
await main();
-198
View File
@@ -1,198 +0,0 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import fg from 'fast-glob';
import { load } from 'cheerio';
import TurndownService from 'turndown';
import matter from 'gray-matter';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const mirror = path.resolve(root, '../www.azinstitute4autism.com');
const site = 'https://www.azinstitute4autism.com';
const contentRoot = path.join(root, 'src/content');
const publicRoot = path.join(root, 'public/assets');
const reportsRoot = path.join(root, 'reports');
const turndown = new TurndownService({ headingStyle: 'atx', bulletListMarker: '-' });
turndown.remove(['script', 'style', 'noscript', 'iframe']);
const mkdir = (dir) => fs.mkdir(dir, { recursive: true });
const clean = (value = '') => value.replace(/\s+/g, ' ').trim();
const csv = (value = '') => `"${String(value).replaceAll('"', '""')}"`;
const yaml = (value = '') => JSON.stringify(String(value));
const blogPreamble = /^# .+\n\n!\[[^\]]*\]\(\/assets\/images\/rula-diab-avatar\.jpg\)\n\n[^\n]+\n\n[^\n]+\n\n!\[[^\]]*\]\([^)]+\)\n\n/;
function contentMarkdown(markdown, isBlog) {
return isBlog ? markdown.replace(blogPreamble, '') : markdown;
}
function logicalFile(file) {
return file.replace(/(?:\.html)?\?(?:hsLang=[^.]+|hs_amp=true)\.html$/, '.html');
}
function canonicalFiles(files) {
const selected = new Map();
for (const file of files) {
if (!file.endsWith('.html') || /\/(?:page|author)\//.test(file) || file.includes('hs_amp=true')) continue;
const logical = logicalFile(file);
const lang = logical.startsWith('ar/') ? 'ar' : logical.startsWith('es/') ? 'es' : 'en';
const key = `${lang}:${logical}`;
const current = selected.get(key);
if (!current || (!file.includes('?') && current.includes('?'))) selected.set(key, file);
}
return [...selected.values()];
}
function sourceUrl(file) {
const logical = logicalFile(file);
if (logical === 'index.html') return '/';
return `/${logical.replace(/\/index\.html$/, '').replace(/\.html$/, '')}`;
}
function isBlogFile(file) {
return file.startsWith('library/') || file.includes('/library/');
}
function languageFor(file, $) {
if (file.startsWith('ar/')) return 'ar';
if (file.startsWith('es/')) return 'es';
return $('html').attr('lang')?.split('-')[0] || 'en';
}
function localizeAsset(value = '') {
const decoded = value.replace(/^https?:\/\/[^/]+/, '').replace(/^\.\.\//, '/');
const match = decoded.match(/(?:\/)?(?:hs-fs\/)?hubfs\/([^?#]+)/);
if (!match) return undefined;
return `/assets/images/${path.basename(decodeURIComponent(match[1])).split('?')[0]}`;
}
function extractRecord(file, html) {
const $ = load(html);
const lang = languageFor(file, $);
const url = sourceUrl(file);
const title = clean($('title').first().text()) || clean($('h1').first().text()) || url;
const description = $('meta[name="description"]').attr('content') || '';
const h1 = clean($('h1').first().text());
const image = localizeAsset(
$('meta[property="og:image"]').attr('content') ||
$('.blog-post__body img, main img, .body-container-wrapper img').first().attr('src') ||
''
);
const alt = clean($('.blog-post__body img, main img, .body-container-wrapper img').first().attr('alt') || '');
const dateText = $('meta[property="article:published_time"]').attr('content') ||
$('time').first().attr('datetime') || '2024-01-01';
const date = /^\d{4}-\d{2}-\d{2}/.test(dateText) ? dateText.slice(0, 10) : '2024-01-01';
const selector = isBlogFile(file) ? '.blog-post__body' : 'main, .body-container-wrapper';
const body = $(selector).first().clone();
body.find('header, footer, nav, form, script, style, noscript, .hs_cos_wrapper_type_form').remove();
body.find('*').removeAttr('style').removeAttr('id').removeAttr('data-hs-cos-general-type').removeAttr('data-hs-cos-type');
body.find('a').each((_, element) => {
const href = $(element).attr('href');
if (!href) return;
$(element).attr('href', href
.replace(/\.html(?:%3F|\?)[^"]*$/, '')
.replace(/\.html$/, '')
.replace(/^index$/, '/'));
});
body.find('img').each((_, element) => {
const src = localizeAsset($(element).attr('src'));
if (src) $(element).attr('src', src);
});
const tables = [];
body.find('table').each((_, element) => {
const token = `__TABLE_${tables.length}__`;
tables.push($(element).prop('outerHTML'));
$(element).replaceWith(`\n\n${token}\n\n`);
});
const markdown = contentMarkdown(
tables.reduce((output, table, index) => output.replaceAll(`__TABLE_${index}__`, table),
turndown.turndown(body.html() || '').replace(/\n{3,}/g, '\n\n').trim()),
isBlogFile(file)
);
return { file, lang, url, title, description, h1, image, alt, date, markdown };
}
function frontmatter(record, type) {
const slug = ['/', '/ar', '/es'].includes(record.url) ? 'index' : record.url.split('/').filter(Boolean).at(-1);
const data = {
title: record.title,
description: record.description,
slug,
canonical: `${site}${record.url}`,
lang: record.lang,
translationKey: slug,
draft: false
};
if (record.image) data.featuredImage = record.image;
if (record.alt) data.alt = record.alt;
if (type === 'blog') Object.assign(data, {
date: record.date,
author: 'rula-diab',
category: 'Library',
tags: []
});
return matter.stringify(record.markdown || `# ${record.h1 || record.title}\n`, data);
}
async function copyAssets() {
const assets = await fg(['hubfs/*', 'hs-fs/hubfs/*', '_hcms/googlefonts/**/*'], { cwd: mirror, onlyFiles: true });
const inventory = ['source,target,size,kind'];
const seen = new Set();
await Promise.all(['images', 'fonts', 'downloads'].map((kind) => fs.rm(path.join(publicRoot, kind), { recursive: true, force: true })));
for (const source of assets) {
const original = path.join(mirror, source);
const stat = await fs.stat(original);
const isFont = source.startsWith('_hcms/googlefonts/');
const rawName = isFont ? source.replace('_hcms/googlefonts/', '') : path.basename(source).split('?')[0];
if (!isFont && !/\.(?:avif|gif|jpe?g|png|svg|webp|pdf)$/i.test(rawName)) continue;
if (!rawName || seen.has(`${isFont}:${rawName}`)) continue;
seen.add(`${isFont}:${rawName}`);
const target = path.join(publicRoot, isFont ? 'fonts' : rawName.endsWith('.pdf') ? 'downloads' : 'images', rawName);
await mkdir(path.dirname(target));
await fs.copyFile(original, target);
inventory.push([source, path.relative(root, target), stat.size, isFont ? 'font' : path.extname(rawName).slice(1)].map(csv).join(','));
}
await fs.writeFile(path.join(reportsRoot, 'asset-inventory.csv'), `${inventory.join('\n')}\n`);
}
async function main() {
await Promise.all([
mkdir(contentRoot), mkdir(publicRoot), mkdir(reportsRoot),
...['en', 'ar', 'es'].flatMap((lang) => [
mkdir(path.join(contentRoot, 'pages', lang)),
mkdir(path.join(contentRoot, 'blog', lang)),
mkdir(path.join(contentRoot, 'authors', lang))
])
]);
const files = canonicalFiles(await fg(['**/*.html'], { cwd: mirror, onlyFiles: true }));
const records = [];
for (const file of files) records.push(extractRecord(file, await fs.readFile(path.join(mirror, file), 'utf8')));
const corePages = new Set(records.filter((r) => !isBlogFile(r.file)).map((r) => r.file));
for (const record of records) {
const isBlog = isBlogFile(record.file);
if (!isBlog && !corePages.has(record.file)) continue;
const slug = ['/', '/ar', '/es'].includes(record.url) ? 'index' : record.url.split('/').filter(Boolean).at(-1);
const target = path.join(contentRoot, isBlog ? 'blog' : 'pages', record.lang, `${slug}.md`);
await fs.writeFile(target, frontmatter(record, isBlog ? 'blog' : 'page'));
}
for (const lang of ['en', 'ar', 'es']) {
await fs.writeFile(path.join(contentRoot, 'authors', lang, 'rula-diab.md'), matter.stringify('', {
name: 'Rula Diab',
slug: 'rula-diab',
description: 'Founder and clinical leader at Arizona Institute for Autism.',
avatar: '/assets/images/rula-diab-avatar.jpg',
lang,
translationKey: 'rula-diab'
}));
}
const urlRows = ['source_file,url,language,type,title,description,h1'];
for (const record of records) urlRows.push([
record.file, record.url, record.lang,
isBlogFile(record.file) ? 'blog' : 'page',
record.title, record.description, record.h1
].map(csv).join(','));
await fs.writeFile(path.join(reportsRoot, 'url-inventory.csv'), `${urlRows.join('\n')}\n`);
await copyAssets();
console.log(`Extracted ${records.length} canonical pages and posts.`);
}
await main();
+3 -3
View File
@@ -1,9 +1,9 @@
import fs from 'node:fs/promises'; import fs from 'node:fs/promises';
const redirects = [ const redirects = [
{ from: '/aba', to: '/aba-therapy', status: 301, reason: 'Brief alias to preserved mirror URL' }, { from: '/aba', to: '/aba-therapy', status: 301, reason: 'Brief legacy alias to preserved URL' },
{ from: '/autismevaluations', to: '/autism-evaluations', status: 301, reason: 'Brief alias to preserved mirror URL' }, { from: '/autismevaluations', to: '/autism-evaluations', status: 301, reason: 'Brief legacy alias to preserved URL' },
{ from: '/learnersocialclub', to: '/learner-social-club', status: 301, reason: 'Brief alias to preserved mirror URL' } { from: '/learnersocialclub', to: '/learner-social-club', status: 301, reason: 'Brief legacy alias to preserved URL' }
]; ];
await fs.writeFile(new URL('../src/data/redirects.json', import.meta.url), `${JSON.stringify(redirects, null, 2)}\n`); await fs.writeFile(new URL('../src/data/redirects.json', import.meta.url), `${JSON.stringify(redirects, null, 2)}\n`);
await fs.writeFile(new URL('../reports/redirect-map.csv', import.meta.url), await fs.writeFile(new URL('../reports/redirect-map.csv', import.meta.url),