Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions labs/SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ The server starts at: http://localhost:3000

![NYC Masterclass homepage at localhost:3000](images/nyc-masterclass-home.png)

> **Note:**
> If you see a **403 error** when navigating to [http://localhost:3000](http://localhost:3000), check if a `.env` file exists in your project root.
> If not, create a `.env` file containing:
>
> ```
> AEM_PAGES_URL = https://main--nycmasterclass--cloudadoption.aem.page
> ```
>
> After saving this file, **restart your local development server** (`aem up`).


---

## Step 7: AI Coding Agent Setup
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise1/images/select-template.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 11 additions & 2 deletions labs/exercise1/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,22 @@ In the page editor:

![Slash command menu in DA.live](images/slash-command-in-da.png)

2. Select **Templates**
3. Choose **Session** or **Lab** depending on what you are creating
2. Select **Library**

![Select Library option from the menu in DA.live](images/slash-command-select-library.png)

3. Select **Templates**

![Select Templates option](images/select-template.png)

4. Choose **Session** or **Lab** depending on what you are creating

![Session and Lab template options](images/use-session-lab-template.png)

The template inserts a Hero block, content sections, and a Metadata block — all with placeholder text.

![How to insert a template in DA](images/how-to-insert-a-template-da.gif)

> **Didn't find a template?** You can also insert individual blocks via the **Blocks Library**:
> Type `/` → select **Blocks** → browse and insert any block with placeholder content pre-filled.
>
Expand Down
Binary file added labs/exercise2/images/cards-block-1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise2/images/cards-block-7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions labs/exercise2/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ Add content to test the **existing** Cards block (default behavior). Use the **B
2. Insert **default Cards** (add a heading like "Default Cards" if you like).
3. Insert the **Cards block that includes the eyebrow** (italic label). Add a heading like **Cards with Eyebrow** above it — you'll use this when we add the eyebrow enhancement in Step 3.

![Cards Block and Variants in DA.live](images/cards-block-1.gif)

You'll add List and View Switcher content later when we implement those variations (Steps 5 and 7). DA.live auto-saves. Click **Preview** to see the page on localhost, then continue to Step 2.

---
Expand All @@ -220,6 +222,8 @@ You'll add List and View Switcher content later when we implement those variatio
- Default Cards section showing cards in a grid
- A second section with cards that have italic (eyebrow) text — still rendered as plain text for now

![Cards Block and Variants in DA.live](images/cards-block-2.gif)

**Why?** The eyebrow enhancement isn't implemented yet. We'll add it in the next step.

---
Expand Down Expand Up @@ -323,6 +327,7 @@ Add at the end of the file:
- The italic text you authored is no longer displayed inline — it's been extracted into the eyebrow
- Default Cards section is unaffected (no italic text = no eyebrow)

![Cards Block and Variants in DA.live](images/cards-block-3.png)
---

## Step 5: Implement List Variation
Expand All @@ -331,6 +336,8 @@ The list variation displays cards in a single column with centered text. Authors

**Add content to test it**: In DA.live, open your cards-test page. Type `/` → Library → Blocks → insert **Cards (List)** (add a heading like "List Variation" if you like). Preview so the page has a section to verify in Step 6.

![Cards Block and Variants in DA.live](images/cards-block-4.png)

### Add List Styles

**File**: `blocks/cards/cards.css`
Expand Down Expand Up @@ -366,6 +373,7 @@ Add at the end of the file:
- Cards are full width with full-width images
- Text is centered

![Cards Block and Variants in DA.live](images/cards-block-5.png)
---

## Step 7: Implement View Switcher Variation
Expand All @@ -374,6 +382,8 @@ Now let's add a variation that combines **JavaScript and CSS**. The view switche

**Add content to test it**: In DA.live, open your cards-test page. Type `/` → Library → Blocks → insert **Cards (View Switcher)** (add a heading like "View Switcher" if you like). Preview so the page has a section to verify in Step 8.

![Cards Block and Variants in DA.live](images/cards-block-6.png)

**This is different from list**: List is a fixed layout chosen by the author. View switcher gives the **end user** control over the layout.

### Update JavaScript
Expand Down Expand Up @@ -481,6 +491,8 @@ Add the toolbar styles at the end of the file:
- Click **Grid** → cards switch back to the grid layout
- The eyebrow enhancement still works (italic text → eyebrow label) in both views

![Cards Block and Variants in DA.live](images/cards-block-7.png)

---

## Step 9: Commit Your Changes
Expand Down
Binary file added labs/exercise3/images/exercise-3-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise3/images/exercise-3-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise3/images/exercise-3-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise3/images/exercise_3_1.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
125 changes: 21 additions & 104 deletions labs/exercise3/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
- [Step 7: Create Test Page](#step-7-create-test-page)
- [Step 8: Test Locally](#step-8-test-locally)
- [Step 9: Test Error Handling](#step-9-test-error-handling)
- [Step 10: Optional - Understanding Worker Endpoints](#step-10-optional---understanding-worker-endpoints)
- [Step 11: Optional - Apply to Real Speakers Page](#step-11-optional---apply-to-real-speakers-page)
- [Step 10: Optional - Apply to Real Speakers Page](#step-10-optional---apply-to-real-speakers-page)
- [Key Takeaways](#key-takeaways)

---
Expand Down Expand Up @@ -59,7 +58,6 @@ git branch

- How to fetch data from external sources in blocks
- How Sheets convert to JSON in DA.live
- How to use Worker endpoints for data transformation
- How to handle async operations and errors in blocks

---
Expand All @@ -74,7 +72,7 @@ In Exercise 2, you built blocks where authors manually create each card. But wha
**Manual authoring doesn't scale**. Dynamic blocks solve this by fetching data from external sources.

**The pattern**:
- Content lives in structured data (Sheet, API, Worker)
- Content lives in structured data (Sheet, API)
- Block fetches and renders that data
- Update the data once → all pages update automatically

Expand All @@ -96,29 +94,7 @@ In Exercise 2, you built blocks where authors manually create each card. But wha
5. When sheet updates, all pages show new data
```

**Alternative flow with Workers**:
```
1. Data in external system (database, API, query-index.json)
2. Worker fetches and transforms data
3. Worker returns JSON
4. Block fetches from Worker endpoint
5. Block renders cards
```

**Example - Featured content from query index**:
```
1. Worker fetches query-index.json
2. Worker filters pages tagged "featured"
3. Worker sorts by publishedDate (newest first)
4. Worker limits to 3 results
5. Dynamic Cards block renders featured articles
```

**Why use Workers?**
- Keep API keys server-side (secure)
- Transform/filter data before sending to client
- Combine multiple data sources
- Cache expensive operations
In this exercise we'll use a Sheet-based `.json` endpoint that lives as content in DA — but the block itself doesn't care where the data comes from. Any endpoint that returns the same JSON shape will work, whether it's a Cloudflare Worker, a third-party API, or a custom backend. Swap the URL and everything else stays the same.

**Reference**: [Integrations](https://www.aem.live/developer/integrations)

Expand Down Expand Up @@ -169,13 +145,15 @@ To avoid conflicts with 50 participants, you'll create your own personal speaker

**In DA.live**:

1. Navigate to https://da.live/#/cloudadoption/nycmasterclass/speakers
1. Navigate to https://da.live/sheet#/cloudadoption/nycmasterclass/speakers
2. This is the master speakers.json with 6 Adobe experts
3. Click the **3-dot menu** → **Copy**
3. Go back to the root folder and select the `speakers` file and click `copy`
4. Navigate to `/drafts/jsmith/` (your folder)
5. **Paste** the speakers file
6. Rename it to `speakers` (keep it as a .json file)

![Copy & Paste Speakers Sheet](images/exercise_3_1.gif)

**Verify**: You should now have `/drafts/jsmith/speakers.json`

---
Expand Down Expand Up @@ -230,7 +208,7 @@ Copy this code:
* Fetches speaker data and renders cards dynamically
*
* Author provides (in block):
* - Row 1: Data source URL (sheet.json or worker endpoint)
* - Row 1: Data source URL (sheet.json endpoint)
*/
export default async function decorate(block) {
// Extract data source URL from block content
Expand Down Expand Up @@ -450,6 +428,7 @@ This page demonstrates fetching speaker data dynamically from JSON.
|---------------|
| /drafts/jsmith/speakers.json |
```
![Dynamic Cards Example](images/exercise-3-2.png)

**Important**: Use YOUR actual path (replace `jsmith` with your first initial + last name).

Expand All @@ -475,6 +454,8 @@ DA.live auto-saves. Click **Preview** to see the page on localhost.
- Verify your name, title, company, and bio display correctly
- Check that your avatar image loads

![Dynamic Cards Example](images/exercise-3-3.png)

**Test the data flow**:
1. Keep the page open at `http://localhost:3000/drafts/jsmith/speakers-test`
2. Go to DA.live and open `/drafts/jsmith/speakers`
Expand All @@ -501,6 +482,7 @@ Edit your `/drafts/jsmith/speakers-test` page in DA.live, change the URL to:

Refresh localhost. You should see: "Error loading speakers: [error message]" with red background.

![Dynamic Cards Error Handling Example](images/exercise-3-4.png)
**Test 2 - No URL**:

Remove the URL row entirely:
Expand All @@ -526,72 +508,7 @@ Refresh. Speaker cards should display again.

---

## Step 10: Optional - Understanding Worker Endpoints

Workers provide a powerful middleware layer between data sources and blocks.

**Why use Workers?**
- **Security**: Keep API keys server-side (never expose in client code)
- **Transformation**: Filter, sort, aggregate, or enrich data server-side
- **Combination**: Merge multiple data sources into one response
- **Caching**: Cache expensive API calls at the edge
- **Rate Limiting**: Protect external APIs from high traffic

**Example Worker flow**:
```
1. Block fetches: https://worker.example.com/speakers
2. Worker fetches speakers.json internally
3. Worker adds computed fields (e.g., initials for avatars)
4. Worker sorts alphabetically by name
5. Worker filters by session category
6. Worker returns transformed JSON
7. Block renders without knowing about transformations
```

**Example Worker code** (Cloudflare Workers):
```javascript
export default {
async fetch(request) {
// Fetch the speakers sheet
const sheetUrl = 'https://main--nycmasterclass--cloudadoption.aem.page/speakers.json';
const response = await fetch(sheetUrl);
const data = await response.json();

// Transform: Add initials, sort alphabetically
data.data = data.data
.map(speaker => ({
...speaker,
Initials: speaker.Name.split(' ').map(n => n[0]).join('')
}))
.sort((a, b) => a.Name.localeCompare(b.Name));

return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=300' // Cache for 5 minutes
}
});
}
}
```

**Key benefit**: To use a Worker instead of direct sheet access, authors just change the URL in the block:
```
| Dynamic Cards |
|---------------|
| https://worker.example.com/speakers |
```

No block code changes needed! The JSON structure stays the same.

**When you'll use this**: Exercise 6 covers form submissions to Slack via Workers. You'll deploy a real Worker endpoint then.

**Reference**: [Integrations - Edge Workers](https://www.aem.live/developer/integrations)

---

## Step 11: Optional - Apply to Real Speakers Page
## Step 10: Optional - Apply to Real Speakers Page

Now that your dynamic-cards block is working, you can see how it would complete the real `/speakers` page.

Expand Down Expand Up @@ -675,22 +592,22 @@ try {
Note: In Exercise 4, you'll learn how query-index.json works and build a dedicated block for it.

**Use Case 2: E-commerce Product Catalog**
- Product data in database
- Worker fetches, filters by category, adds pricing
- Block displays with live inventory status
- Product data maintained in a Sheet
- Block fetches and renders product cards with pricing
- Update the sheet → all catalog pages update automatically

**Use Case 3: News/Blog Feeds**
- Articles in CMS
- Worker aggregates from multiple sources
- Block displays with filtering by topic
- Articles indexed via query-index.json
- Block fetches and displays recent articles
- Filter by topic or tag using query parameters

---

## Key Takeaways

- Sheets automatically convert to JSON endpoints in DA.live
- Dynamic blocks fetch data instead of decorating authored content
- Workers provide secure middleware for data transformation
- The same block works with any JSON endpoint
- Always handle loading states and errors
- Same JSON structure as Sheets - reusable patterns
- Performance: consider placement (below fold preferred)
Expand All @@ -708,7 +625,7 @@ Note: In Exercise 4, you'll learn how query-index.json works and build a dedicat
- [ ] Tested editing sheet data - changes reflected on refresh
- [ ] Tested error handling (invalid URL, no URL, restore)
- [ ] Tested in Chrome DevTools responsive view (desktop and mobile)
- [ ] Understand when to use Workers vs direct sheet fetch
- [ ] Understand the sheet-to-JSON data flow
- [ ] Committed and pushed block code changes

---
Expand Down
Binary file added labs/exercise4/images/query-index.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise4/images/search-block.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added labs/exercise4/images/search_demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions labs/exercise4/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,11 @@ Look for your `/labs/jsmith/my-session` path in the `data` array.

**Validate index definition**: [Index Admin](https://tools.aem.live/tools/index-admin/index.html?org=cloudadoption&site=nycmasterclass) — use this tool to fetch and validate the index configuration (include/exclude paths, properties) for this org/site.

![Query Index Example](images/query-index.png)

> **Note**: Index updates can take a few minutes after publishing. If you don't see your page yet, continue — it will be there by the time you test.


---

## Step 2: Look at the Block Collection Reference
Expand Down Expand Up @@ -614,6 +617,8 @@ Add this content:

The URL row is optional — if omitted, the block defaults to `/query-index.json`. Authors can point the block at any JSON endpoint that returns `{ data: [...] }`.

![search Example](images/search-block.png)

DA.live auto-saves. Click **Preview** to see the page on localhost.

---
Expand Down Expand Up @@ -646,6 +651,8 @@ Results render as Cards block cards — same dark cards with hover effect you sa

**Escape key**: Press Escape while the input is focused to clear the search and results.

![Search demo](images/search_demo.gif)

---

## Step 8: Test Edge Cases
Expand Down
2 changes: 1 addition & 1 deletion labs/exercise8/instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ Ask other participants to share their site URLs and compare.

A working implementation of this exercise is available for the site `ukhalid-mc`.

- Site: [https://main--ukhalid-mc--cloudadoption.aem.page/](https://main--ukhalid-mc--cloudadoption.aem.page/)
- Site: [https://answers--ukhalid-mc--cloudadoption.aem.page/](https://answers--ukhalid-mc--cloudadoption.aem.page/)
- Metadata sheet: [https://da.live/sheet#/cloudadoption/ukhalid-mc/metadata](https://da.live/sheet#/cloudadoption/ukhalid-mc/metadata)

---
Expand Down