ACTUAL CODEX CLI RUN / STEP 05 Codex CLI 0.153.4 · captured 11 September 2026 This is a selected event transcript, not the Codex Desktop UI. Reasoning, environment diagnostics and supporting skill instructions are omitted. Paths are shortened. COMMAND codex exec -C --sandbox workspace-write --json --output-last-message 05-final.txt - < prompts/05-review.txt PROMPT SENT อ่าน inputs.md, brief.md, index.html, style.css, main.js และ acceptance-notes.md แล้วทบทวนเฉพาะsourceในโฟลเดอร์นี้ ตรวจข้อมูลจริงเทียบsource, mapping11บท/Day1Day2, defaultlight+dark storageerror, การค้นร่วมกับfilter/empty/reset, noJSfallback, semanticHTML keyboardfocus alt printและreducedmotion รัน node --check main.js ได้ แต่อย่ารันserverหรืออ้างbrowser/contrastผ่านจากการอ่านโค้ด หากพบข้อผิดพลาดที่พิสูจน์ได้ให้แก้ไฟล์ที่เกี่ยวข้องและเขียน review.md ระบุสาเหตุ สิ่งที่เปลี่ยน ผลคำสั่ง และbrowserchecksที่ยังรอ หากไม่พบให้บันทึกตามจริง ไม่สร้างปัญหาหรือผลทดสอบขึ้นเอง. เว็บไซต์นี้เป็นตัวอย่างสื่อรายวิชา ไม่ใช่LMSหรือเว็บมหาวิทยาลัยที่รับรองแล้ว EXECUTED COMMAND /bin/bash -lc "pwd && rg --files -g 'inputs.md' -g 'brief.md' -g 'index.html' -g 'style.css' -g 'main.js' -g 'acceptance-notes.md' -g 'review.md' && git status --short" OUTPUT brief.md main.js style.css index.html acceptance-notes.md inputs.md ?? ../../../.diagram-design ?? ../../../.gitattributes ?? ../../../.gitignore ?? ../../../CLAUDE.md ?? ../../../DESIGN.md ?? ../../../INFRASTRUCTURE.md ?? ../../../PROJECT_PLAN.md ?? ../../../README.md ?? ../../ ?? ../../../design-system/ ?? ../../../diagrams/ ?? ../../../docs/ ?? ../../../examples/ ?? ../../../migrations/ ?? ../../../package-lock.json ?? ../../../package.json ?? ../../../playwright.config.mjs ?? ../../../public/ ?? ../../../scripts/ ?? ../../../src/ ?? ../../../tests/ ?? ../../../training-skills/ ?? ../../../tsconfig.json ?? ../../../worker-configuration.d.ts ?? ../../../wrangler.jsonc EXIT 0 EXECUTED COMMAND /bin/bash -lc "for f in inputs.md brief.md index.html style.css main.js acceptance-notes.md; do printf '\\n===== %s =====\\n' \""'$f"; sed -n '"'1,240p' \""'$f"; done' OUTPUT ===== inputs.md ===== # ข้อมูลตั้งต้นสำหรับเว็บไซต์ตัวอย่างรายวิชา S1 — ข้อมูลที่ผู้ใช้ให้: 977-121 Module: Website Design and Development, มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus. S2 — design-system/course.json และ docs/instructor/course-guide.md ของหลักสูตรนี้: AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI เป็นหน่วย workshop 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง รวมพัก 10 นาทีต่อวัน เป็นส่วนหนึ่งของรายวิชา ไม่ใช่ชั่วโมง/หน่วยกิต/ประมวลรายวิชาฉบับมหาวิทยาลัยทั้งหมด S3 — DESIGN.md และ Rawinnipa Brand Guidelines v1.0 ที่ใช้กับ course shell: Inter + Noto Sans Thai, light default: #F7F7F7 พื้น, #0A0A0A ข้อความ, #3EDC81 accent มีข้อความเข้ม, #17653F สำหรับข้อความเขียวบนพื้นอ่อน. Dark: #0A0A0A canvas, #171717 surface, #F7F7F7 text. จำกัด green เป็นจุดเน้น; focus มองเห็น; print กระดาษขาว. ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อ https://rawinsoft.com/ ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัยเพิ่ม. ห้ามสร้างตราหรือโลโก้มหาวิทยาลัยขึ้นเอง S4 — บทเรียนที่มีจริงใน repository (ชื่อย่อใช้แสดงได้): - 00 | บทเรียน 00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | /learn/lessons/00-setup-and-web-basics/ - 01 | บทที่ 1: พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | /learn/lessons/01-vibe-coding-foundations/ - 02 | บทที่ 2: Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | /learn/lessons/02-agent-skills/ - 03 | บทที่ 3: Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | /learn/lessons/03-specs-and-prompts/ - 04 | บทเรียน 04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | /learn/lessons/04-design-and-assets/ - 05 | บทเรียน 05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | /learn/lessons/05-company-website/ - 06 | บทเรียน 06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | /learn/lessons/06-rental-and-data/ - 07 | บทเรียน 07 — GSAP product story, storefront และ quote demo | /learn/lessons/07-gsap-storefront/ - 08 | บทเรียน 08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | /learn/lessons/08-cloudflare-deploy/ - 09 | บทเรียน 09 — Production Operations: security, observability, rollback และต้นทุน | /learn/lessons/09-production-operations/ - 10 | บทเรียน 10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | /learn/lessons/10-capstone-and-handoff/ S5 — ปลายทางที่มีจริง: / (เว็บไซต์สื่อหลักสูตร), /resources/, /handbook/, /learn/labs/install-ai-tools/, /learn/labs/research-to-brand-website/, /learn/labs/design-tools-and-mcp/. เว็บไซต์ตัวอย่างจะอยู่ /examples/course-website/. ลิงก์อ่านการสร้างทีละขั้นใช้ /learn/labs/build-course-website-step-by-step/ (กำลังสร้าง) S6 — สินทรัพย์ font ที่ใช้ได้: /fonts/Inter-Regular.woff2, /fonts/Inter-Bold.woff2, /fonts/NotoSansThai-Regular.woff2, /fonts/NotoSansThai-Bold.woff2. ใช้ตัวอักษร/HTML/SVG ธรรมดา ไม่ต้องสร้างภาพ raster หรือโหลด font ภายนอก GAP — ยังไม่มีเจ้าของยืนยันชื่อผู้สอน จำนวนหน่วยกิต ตารางภาคเรียน เกณฑ์ให้คะแนน ช่องทางสมัคร หรือบัญชี LMS. ไม่สร้างข้อมูลเหล่านี้ ไม่สร้าง login/รับสมัครที่ทำงานปลอม PROPOSAL — กลุ่มเป้าหมายของ prototype คือผู้เรียนที่ต้องการรู้ว่าเริ่มตรงไหน เลือกบทเรียน และดูแผน workshop. เว็บไซต์นี้เป็นตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ ขอบเขตงาน - เว็บภาษาไทย static HTML/CSS/JS หน้าเดียว; API/ฐานข้อมูลไม่จำเป็นสำหรับเนื้อหาสาธารณะ - ให้ไปถึงบทเรียนได้จริง; optional ค้นหาบทเรียนและกรอง Day1/Day2/ทั้งหมด - โปรเจ็กต์เดิมมีเวลา workshop 8h; เนื้อหาเกินเวลาเป็นอ่านต่อ. แสดง Day1/Day2 สรุปไม่แต่งตารางรายวิชาเต็ม - สร้างแบบทีละขั้น: brief → semantic HTML → responsive CSS → JS interaction → QA → publication - code ทั้งหมดและผลแต่ละช่วงต้องตรวจ/ย้อนดูได้ ข้อมูลยืนยันเพิ่มเติมหลังทบทวน brief (ก่อนขั้น02): แบ่ง Day1 เป็นบท00–05, Day2 เป็นบท06–10 ตาม dayData ใน scripts/build.mjs. การแบ่งนี้เป็นเส้นทางคลังบทเรียน; ตารางในห้องยังเลือกกิจกรรมตามเวลา4ชม/วัน ไม่ได้หมายถึงต้องทำครบทุกเนื้อหา แหล่งอ้างอิงชื่อรายวิชาภายนอก: https://computing.psu.ac.th/th/b-eng-digital-engineer-international-program/ ตรวจ11กันยายน2026. ใช้เฉพาะยืนยันชื่อวิชา/บริบทPSUPhuket; ไม่เอาจำนวนหน่วยกิตในแผนคนละรุ่นมาใส่เป็นเวลาworkshop ===== brief.md ===== # Brief — เว็บไซต์ตัวอย่างรายวิชา 977-121 ## กรอบงานและสถานะข้อมูล - **ขอบเขตผลลัพธ์:** เอกสารสังเคราะห์สำหรับหน้า static HTML/CSS/JS ภาษาไทยหน้าเดียวในอนาคต; เอกสารนี้ไม่ใช่หน้าเว็บ และไม่มีการทำ web research - **สถานะ:** Draft สำหรับให้เจ้าของตรวจสอบก่อนเข้าสู่ semantic HTML - **ตำแหน่งผลิตภัณฑ์:** เว็บไซต์ตัวอย่างประกอบการเรียนที่ `/examples/course-website/` ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ - **ข้อจำกัด:** ไม่สร้างตรา/โลโก้มหาวิทยาลัย ข้อมูลผู้สอน หน่วยกิต ตารางภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร บัญชี LMS หรือ login/รับสมัครจำลอง ## FACT - ชื่อรายวิชา: **977-121 Module: Website Design and Development** - สถาบันที่ระบุ: **มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus** - **AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI** เป็น workshop ภายในรายวิชา ระยะเวลา 2 วัน × 4 ชั่วโมง (รวม 8 ชั่วโมง) และมีพัก 10 นาทีต่อวัน; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับเต็มของมหาวิทยาลัย - มีบทเรียนจริง 11 บท (00–10) และมีปลายทางบทเรียน/ทรัพยากรตาม content inventory ด้านล่าง - visual system ที่มีอยู่ใช้ Inter + Noto Sans Thai, light เป็นค่าเริ่มต้น และใช้สีเขียวอย่างจำกัดเพื่อเน้น ## INFERENCE - ผู้เข้าชมหลักต้องการตอบคำถามเร็ว ๆ ว่า “เริ่มตรงไหน”, “มีบทเรียนใดบ้าง” และ “workshop สองวันนี้ทำอะไร”; ดังนั้นหน้าเดียวควรให้ทางเลือกเริ่มเรียนและแผน Day 1/Day 2 อยู่ก่อนเนื้อหารายละเอียด - CTA ควรพาไปยังปลายทางที่มีอยู่จริงเท่านั้น และป้ายกำกับต้องบอกชนิด/สถานะของปลายทางอย่างตรงไปตรงมา โดยเฉพาะลิงก์บทความแบบทีละขั้นที่ยังอยู่ระหว่างสร้าง - เนื่องจาก workshop เป็นเพียงส่วนหนึ่งของ module จึงควรนำเสนอเป็น “แผน workshop” ไม่ใช่ตารางสอนหรือคำอธิบายรายวิชาฉบับสมบูรณ์ ## PROPOSAL ### เป้าหมายและ audience **เป้าหมายหลัก:** ช่วยผู้เรียนค้นพบเส้นทางเริ่มเรียน เข้าถึงบทเรียนจริง และเข้าใจขอบเขตของ AI Web Studio workshop โดยไม่ทำให้เข้าใจว่าเป็นเว็บไซต์ทางการหรือระบบรับสมัคร **Audience หลัก:** ผู้เรียนที่ต้องการเริ่มทำเว็บไซต์ด้วย AI และต้องเลือกบทเรียน/ดูภาพรวม workshop ก่อนเข้าเนื้อหา **Audience รอง:** ผู้สอนหรือผู้ทบทวนสื่อที่ต้องการตรวจรายการบทเรียนและปลายทางของหลักสูตรอย่างรวดเร็ว ### ข้อเสนอคุณค่า (value proposition) “เส้นทางเรียนรู้เพื่อออกแบบและพัฒนาเว็บไซต์ด้วย AI: เริ่มจากเครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้ พร้อม workshop สองวันเป็นส่วนหนึ่งของ module.” ### CTA และปลายทาง | ระดับ | ป้าย CTA ที่เสนอ | ปลายทาง | หมายเหตุ | | --- | --- | --- | --- | | หลัก | `เริ่มจากบทเรียน 00` | `/learn/lessons/00-setup-and-web-basics/` | เริ่มต้นที่จุดเข้าเรียนชัดเจน | | รอง | `ดูบทเรียนทั้งหมด` | `/` | ใช้เมื่อหน้าเว็บไซต์สื่อหลักสูตรแสดงรายการเรียน; ยืนยัน label ใน implementation อีกครั้ง | | รอง | `ดูแผน AI Web Studio 2 วัน` | anchor `#workshop` | เลื่อนภายในหน้า ไม่อ้างว่าเป็นตารางรายวิชาเต็ม | | รอง | `เปิดคู่มือการเรียน` | `/handbook/` | ปลายทางที่มีจริง | | รอง | `ดูทรัพยากร` | `/resources/` | ปลายทางที่มีจริง | | บริบท | `อ่านการสร้างทีละขั้น` | `/learn/labs/build-course-website-step-by-step/` | ติดป้าย “กำลังสร้าง” จนกว่าจะยืนยันว่าเผยแพร่แล้ว | | เครดิต | `Rawinnipa` | `https://rawinsoft.com/` | ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อเท่านั้น ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัย | ### ลำดับ section ของหน้าเดียว 1. **Utility/header** — ชื่อรายวิชา, สถาบัน, ป้าย “เว็บไซต์ตัวอย่างประกอบการเรียน”, การข้ามไปเนื้อหาหลัก (skip link), สวิตช์ theme 2. **Hero** — ชื่อรายวิชาเต็ม, ชื่อ workshop, value proposition, CTA หลัก และ CTA ดู workshop 3. **ขอบเขต AI Web Studio** — ข้อความชัดเจนว่าเป็นส่วนหนึ่งของ module; 2 วัน × 4 ชั่วโมง, พัก 10 นาที/วัน, รวม 8 ชั่วโมง; ไม่แทนรายละเอียดรายวิชาฉบับมหาวิทยาลัย 4. **แผน workshop Day 1 / Day 2** — สรุปกิจกรรมตามระดับหัวข้อเท่านั้น; ไม่ประดิษฐ์ตารางเวลาเต็มหรือผลการประเมิน 5. **เส้นทางบทเรียน** — รายการ 00–10 พร้อมชื่อและลิงก์ที่มีจริง; search/filter แบบ optional: ทั้งหมด, Day 1, Day 2 โดยต้องประกาศเกณฑ์การจัดกลุ่มก่อนใช้ 6. **Labs และแหล่งเรียนต่อ** — ลิงก์ labs ที่มีจริง, handbook และ resources; ลิงก์ “อ่านการสร้างทีละขั้น” พร้อมป้าย “กำลังสร้าง” 7. **ข้อจำกัด/ความโปร่งใส** — ย้ำสถานะเว็บไซต์ตัวอย่าง; ไม่มี login, รับสมัคร, LMS หรือข้อมูลทางวิชาการที่ยังไม่ยืนยัน 8. **Footer** — ชื่อรายวิชาและ PSU Phuket เป็นข้อความ, ลิงก์ Rawinnipa ตามขอบเขตเครดิต; ไม่มีตราหรือโลโก้ที่สร้างขึ้น ### Content inventory | กลุ่ม | เนื้อหาที่แสดง | ปลายทาง | | --- | --- | --- | | รายวิชา | 977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus | ไม่มีลิงก์สถาบันที่ยืนยัน | | Workshop | AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI; 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง; พัก 10 นาที/วัน | `#workshop` | | บทเรียน 00 | เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | `/learn/lessons/00-setup-and-web-basics/` | | บทเรียน 01 | พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | `/learn/lessons/01-vibe-coding-foundations/` | | บทเรียน 02 | Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | `/learn/lessons/02-agent-skills/` | | บทเรียน 03 | Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | `/learn/lessons/03-specs-and-prompts/` | | บทเรียน 04 | ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | `/learn/lessons/04-design-and-assets/` | | บทเรียน 05 | เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | `/learn/lessons/05-company-website/` | | บทเรียน 06 | เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | `/learn/lessons/06-rental-and-data/` | | บทเรียน 07 | GSAP product story, storefront และ quote demo | `/learn/lessons/07-gsap-storefront/` | | บทเรียน 08 | รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | `/learn/lessons/08-cloudflare-deploy/` | | บทเรียน 09 | Production Operations: security, observability, rollback และต้นทุน | `/learn/lessons/09-production-operations/` | | บทเรียน 10 | สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | `/learn/lessons/10-capstone-and-handoff/` | | Labs/ทรัพยากร | install AI tools; research-to-brand website; design tools and MCP; resources; handbook | `/learn/labs/install-ai-tools/`; `/learn/labs/research-to-brand-website/`; `/learn/labs/design-tools-and-mcp/`; `/resources/`; `/handbook/` | ### States | State | ข้อเสนอพฤติกรรม/ข้อความ | | --- | --- | | Default | แสดง hero, CTA, workshop summary และรายการบทเรียนทั้งหมด | | Light (default) | พื้น `#F7F7F7`, ข้อความ `#0A0A0A`, accent `#3EDC81` พร้อมข้อความเข้ม, ข้อความเขียวบนพื้นอ่อน `#17653F` | | Dark | canvas `#0A0A0A`, surface `#171717`, ข้อความ `#F7F7F7`; รักษา contrast และไม่ใช้เขียวเป็นข้อความหลักบนพื้นมืดหากยังไม่ตรวจ contrast | | Theme preference | ใช้ light เป็น default; หากมีสวิตช์ ต้องมองเห็นสถานะและทำงานด้วยคีย์บอร์ด | | Lesson filter/search (optional) | แสดงผล “ไม่พบบทเรียนที่ตรงกัน” พร้อมปุ่ม/ลิงก์คืนค่า; filter Day 1/Day 2 ใช้ได้ต่อเมื่อเจ้าของยืนยัน mapping | | CTA pending | `อ่านการสร้างทีละขั้น` มีป้าย “กำลังสร้าง” และไม่อ้างว่าอ่านได้แล้ว | | Link failure/unknown | ไม่สร้างหน้า 404 หรือ loading simulation; ใช้เฉพาะปลายทางที่ S5 ระบุ | | Print | พื้นกระดาษขาว, ข้อความอ่านได้, ไม่พึ่งสีอย่างเดียวเพื่อสื่อความหมาย | ### Responsive - **Mobile ก่อน:** หนึ่งคอลัมน์, CTA กว้างแตะง่าย, nav ไม่บังคับเลื่อนแนวนอน, lesson cards เรียงแนวตั้ง - **Tablet:** hero และ workshop สามารถจัดสองคอลัมน์เมื่อยังเหลือพื้นที่อ่านง่าย; filters อยู่ก่อนรายการผลลัพธ์ - **Desktop:** ใช้ความกว้างข้อความจำกัดเพื่อการอ่าน, lesson grid หลายคอลัมน์ตามพื้นที่, header ยังเข้าถึง CTA หลักได้ - ทุกขนาด: ไม่ซ่อนเนื้อหาสำคัญเพียงเพราะ viewport, รองรับ text zoom/reflow, และไม่ยึดความหมายด้วย hover เพียงอย่างเดียว ### Accessibility acceptance checks - [ ] ใช้ semantic landmarks (`header`, `nav`, `main`, `section`, `footer`) และลำดับ heading ไม่ข้ามระดับ - [ ] มี skip link; ทุก CTA/ลิงก์เข้าถึงด้วยคีย์บอร์ด และ focus ชัดเจน - [ ] สี light/dark และทุกสถานะ focus/hover/selected ผ่าน contrast ที่เหมาะสม; สีเขียวไม่ใช่ตัวบอกความหมายเพียงอย่างเดียว - [ ] สวิตช์ theme และ filter/search (หากสร้าง) มี accessible name, state และประกาศการเปลี่ยนแปลงผลลัพธ์อย่างเหมาะสม - [ ] ข้อความไทยใช้ Noto Sans Thai และข้อความ Latin ใช้ Inter จาก font ในระบบ; ไม่มี external font - [ ] ขนาดเป้าหมายสัมผัสเพียงพอ, หน้า reflow ได้ที่ความกว้างแคบ/zoom, และไม่มี horizontal overflow โดยไม่จำเป็น - [ ] ไม่มีภาพที่ต้องพึ่งพาเพื่อเข้าใจเนื้อหา; ถ้ามี SVG ตกแต่งต้องซ่อนจาก assistive technology - [ ] โครงสร้าง print เป็นพื้นขาวและยังอ่านลิงก์/ป้าย “กำลังสร้าง” ได้ ## ทางเลือกภาพ (ไม่สร้าง raster/ตรามหาวิทยาลัย) ### ทางเลือก A — Type-led learning map ใช้ typography เป็นภาพหลัก: หมายเลขบทเรียน 00–10 ขนาดใหญ่, เส้นทาง/จุดสถานะด้วย CSS หรือ SVG ธรรมดา, และ chip “Day 1/Day 2”. ภาพสื่อการเดินทางผ่านเนื้อหาโดยไม่ต้องใช้รูปถ่ายหรือสินทรัพย์ใหม่; ใช้ green เฉพาะจุดเริ่มต้น, CTA และสถานะที่ได้รับการยืนยัน. ### ทางเลือก B — Editorial workshop cards ใช้การ์ดขาว/ผิว dark ที่มีตัวเลข “Day 1”, “Day 2” และ glyph จาก HTML/SVG ธรรมดา (เช่น cursor, bracket, check) พร้อมภาพพิมพ์ขนาดใหญ่. ให้บรรยากาศ workshop ชัด แต่ต้องระวังไม่ทำให้ผู้ใช้เข้าใจว่าบัตรเหล่านี้คือกำหนดการรายวิชาทางการ. ### Draft ที่เลือก — ทางเลือก A เลือก **Type-led learning map** เพราะสอดคล้องกับแบรนด์เดิมที่เรียบ ใช้สีเขียวจำกัด และให้บทเรียนจริงเป็นศูนย์กลาง. ลดความเสี่ยงการสร้างภาพ/ตรามหาวิทยาลัยหรือการใส่บริบท workshop เกินข้อเท็จจริง. จะใช้เฉพาะข้อความ, HTML และ SVG ธรรมดาตามสินทรัพย์ที่อนุญาต. ## GAP — ต้องถามเจ้าของก่อน implementation 1. ต้องการให้ชื่อไทยของรายวิชามีหรือไม่? ปัจจุบันยืนยันเพียงชื่อ `977-121 Module: Website Design and Development`. 2. Mapping ที่ได้รับอนุมัติของบทเรียนใดอยู่ Day 1 และ Day 2 คืออะไร? จนกว่าจะยืนยัน ต้องไม่เปิด filter Day 1/Day 2 หรือใส่ป้ายรายบท. 3. CTA `ดูบทเรียนทั้งหมด` ควรชี้ไปหน้าใด/anchor ใด? S5 ยืนยันเพียง `/` เป็นเว็บไซต์สื่อหลักสูตร ไม่ได้ยืนยันส่วนรายการบทเรียน. 4. ปลายทาง `/learn/labs/build-course-website-step-by-step/` เผยแพร่เมื่อใด? ก่อนนั้นต้องคงป้าย “กำลังสร้าง” หรือซ่อน CTA. 5. อนุมัติข้อความ disclaimer ว่า “เว็บไซต์ตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ” หรือมีถ้อยคำที่เจ้าของกำหนดหรือไม่? 6. ผู้ใช้ต้องการ theme toggle จริงหรือเพียงรองรับ system preference? ข้อกำหนด design system ระบุ light default และ dark palette แต่ยังไม่ยืนยัน interaction. 7. ยืนยันว่าต้องการแสดงลิงก์ Rawinnipa ใน footer หรือไม่; หากแสดงให้ใช้เพียงเครดิตผู้ออกแบบ/ผู้จัดทำสื่อ. 8. ผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร และ LMS จะได้รับอนุมัติให้แสดงหรือไม่? ถ้าไม่ ต้องคงไม่แสดงทั้งหมด. ===== index.html ===== 977-121 Module: Website Design and Development | AI Web Studio

AI Web Studio

977-121 Module: Website Design and Development

ออกแบบและพัฒนาเว็บไซต์ด้วย AI

เส้นทางเรียนรู้เพื่อเริ่มสร้างเว็บไซต์ด้วย AI ตั้งแต่เครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้

เริ่มจากบทเรียน 00 ดูบทเรียนทั้งหมด

ภาพรวมเส้นทางการทำงาน

  1. Brief
  2. Build
  3. Verify
  4. Publish

เป้าหมายของ workshop

AI Web Studio เป็นส่วนหนึ่งของรายวิชา เพื่อช่วยผู้เรียนเลือกจุดเริ่มต้น เข้าถึงบทเรียนจริง และฝึกสร้างเว็บไซต์ด้วย AI อย่างมีขั้นตอน

  • เข้าใจเครื่องมือและพื้นฐานของเว็บก่อนเริ่มลงมือ
  • ใช้ specs, prompts และเครื่องมือ AI เพื่อพัฒนาเว็บไซต์
  • ตรวจคุณภาพและส่งมอบงานที่ตรวจสอบได้

workshop นี้ไม่ใช่รายละเอียดรายวิชาฉบับมหาวิทยาลัยหรือระบบมหาวิทยาลัยอย่างเป็นทางการ

แผน AI Web Studio 2 วัน

รวม 8 ชั่วโมง: 2 วัน วันละ 4 ชั่วโมง และพัก 10 นาทีต่อวัน

แผนนี้เป็นเส้นทางเลือกใช้คลังบทเรียนตามเวลาจริงในห้องเรียน ไม่ได้สัญญาว่าจะสอนครบทุกบทภายใน 8 ชั่วโมง

Day 1 — เริ่มต้น ออกแบบ และสร้างฐานงาน

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 00–05 เพื่อเตรียมเครื่องมือ วางบริบท และเริ่มทำเว็บไซต์

Day 2 — ขยายงาน ตรวจสอบ และส่งมอบ

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 06–10 เพื่อทำงานกับข้อมูล ประสบการณ์เว็บ การ deploy และการส่งมอบ

เส้นทางบทเรียน

บท 00–05 อยู่ในเส้นทาง Day 1 และบท 06–10 อยู่ในเส้นทาง Day 2 เพื่อใช้เลือกเนื้อหาใน workshop

Day 1: บท 00–05

00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร

เตรียมเครื่องมือและทำความเข้าใจพื้นฐานการทำงานของเว็บก่อนเริ่มสร้างงาน

อ่านบทเรียน 00

01 — พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง

เรียนรู้พื้นฐาน Vibe Coding เพื่อสร้างเว็บที่พร้อมส่งมอบ

อ่านบทเรียน 01

02 — Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง

ทำความเข้าใจ Agent Skills, MCP และ Plugins พร้อมดูแลบริบทการทำงาน

อ่านบทเรียน 02

03 — Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation

เขียน specs และ prompts สำหรับเว็บบริษัท catalog และเว็บที่มี animation

อ่านบทเรียน 03

04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ

วางงานออกแบบ ภาพ และเกณฑ์คุณภาพก่อนเริ่มเขียนหน้าเว็บ

อ่านบทเรียน 04

05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง

สร้างเว็บบริษัทและ contact form ที่ทำงานกับ demo ได้จริง

อ่านบทเรียน 05

Day 2: บท 06–10

06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง

พัฒนาเว็บเช่าอุปกรณ์ที่จัดการ availability และ capacity ของ demo ได้

อ่านบทเรียน 06

08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้

รันโปรเจกต์และตรวจเส้นทาง deployment ของ Cloudflare

อ่านบทเรียน 08

09 — Production Operations: security, observability, rollback และต้นทุน

ดูแล production ทั้งความปลอดภัย การสังเกตการณ์ การ rollback และต้นทุน

อ่านบทเรียน 09

10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้

สร้างเว็บของตนเองและเตรียมการส่งมอบที่ตรวจสอบได้

อ่านบทเรียน 10

Labs และแหล่งเรียนต่อ

977-121 Module: Website Design and Development · มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต

สื่อออกแบบและจัดทำโดย Rawinnipa

===== style.css ===== @font-face { font-family: "Inter"; src: url("/fonts/Inter-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: "Inter"; src: url("/fonts/Inter-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; } @font-face { font-family: "Noto Sans Thai"; src: url("/fonts/NotoSansThai-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: "Noto Sans Thai"; src: url("/fonts/NotoSansThai-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; } :root { color-scheme: light; --surface: #f7f7f7; --surface-raised: #ffffff; --text: #0a0a0a; --muted: #505050; --line: #d0d0d0; --action: #3edc81; --action-text: #063119; --link: #17653f; --focus: #17653f; --radius: 0.75rem; --page-width: 72rem; } html[data-theme="dark"] { color-scheme: dark; --surface: #0a0a0a; --surface-raised: #171717; --text: #f7f7f7; --muted: #c8c8c8; --line: #555555; --action: #3edc81; --action-text: #062c16; --link: #82efae; --focus: #82efae; } * { box-sizing: border-box; } [hidden] { display: none !important; } html { background: var(--surface); } body { margin: 0; min-width: 0; background: var(--surface); color: var(--text); font-family: Inter, "Noto Sans Thai", sans-serif; font-size: 1rem; line-height: 1.7; overflow-wrap: anywhere; } a { color: var(--link); text-decoration-thickness: 0.12em; text-underline-offset: 0.18em; } a:hover { color: var(--text); } a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; } .skip-link { position: fixed; z-index: 5; top: 0.75rem; left: 0.75rem; padding: 0.6rem 0.85rem; background: var(--action); color: var(--action-text); transform: translateY(-150%); } .skip-link:focus { transform: translateY(0); } .site-header { border-bottom: 1px solid var(--line); } .header-inner, .page-shell, .site-footer { width: min(100% - 2rem, var(--page-width)); margin-inline: auto; } .header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem; padding-block: 1.15rem; } .course-identity p { margin: 0; } .eyebrow, .preview-label { margin: 0; color: var(--muted); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; } .course-code { font-weight: 700; } .institution { color: var(--muted); font-size: 0.9rem; } .site-nav { display: flex; flex: 1 1 26rem; flex-wrap: wrap; justify-content: flex-end; gap: 0.4rem 1rem; } .site-nav a { padding: 0.35rem 0; white-space: nowrap; } .page-shell { padding-block: clamp(2.5rem, 6vw, 5.5rem); } .course-hero { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(15rem, 0.65fr); gap: clamp(1.5rem, 5vw, 5rem); align-items: end; padding-bottom: clamp(2.5rem, 5vw, 4rem); border-bottom: 1px solid var(--line); } h1, h2, h3, h4 { margin: 0; color: var(--text); line-height: 1.22; text-wrap: balance; } h1 { max-width: 15ch; font-size: clamp(2.3rem, 7vw, 5.6rem); letter-spacing: -0.055em; } h2 { font-size: clamp(1.65rem, 4vw, 2.7rem); letter-spacing: -0.035em; } h3 { font-size: clamp(1.2rem, 2.2vw, 1.55rem); } h4 { font-size: 1.08rem; } .hero-subtitle { margin: 1.15rem 0 0; font-size: clamp(1.15rem, 2vw, 1.5rem); font-weight: 700; } .hero-summary { max-width: 58ch; margin: 0.85rem 0 0; color: var(--muted); font-size: 1.08rem; } .hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem 1.25rem; margin: 1.75rem 0 0; align-items: center; } .hero-actions a:first-child { display: inline-flex; min-height: 2.8rem; align-items: center; padding: 0.55rem 1rem; background: var(--action); border: 1px solid var(--action); border-radius: var(--radius); color: var(--action-text); font-weight: 700; text-decoration: none; } .learning-preview { padding: clamp(1.25rem, 3vw, 2rem); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .learning-preview ol { display: grid; gap: 0.75rem; margin: 1rem 0 0; padding: 0; list-style: none; counter-reset: route; } .learning-preview li { display: flex; align-items: center; gap: 0.7rem; font-weight: 700; } .learning-preview li::before { display: grid; width: 1.8rem; height: 1.8rem; place-items: center; border: 1px solid var(--line); border-radius: 50%; color: var(--muted); content: counter(route, decimal-leading-zero); counter-increment: route; font: 700 0.7rem/1 Inter, sans-serif; } .content-section { padding-top: clamp(3rem, 8vw, 7rem); } .content-section > p, .goals-section li { max-width: 72ch; } .content-section > p { color: var(--muted); } .goals-section ul { padding-left: 1.25rem; } .day-grid, .lesson-grid { display: grid; gap: 1rem; margin-top: 1.5rem; } .day-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .day-card, [data-lesson] { min-width: 0; padding: clamp(1.1rem, 3vw, 1.6rem); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .day-card p, [data-lesson] p { color: var(--muted); } .lesson-day + .lesson-day { margin-top: 2.5rem; } .lesson-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } [data-lesson] { display: flex; flex-direction: column; gap: 0.85rem; } [data-lesson] p { margin: 0; } [data-lesson] a { width: fit-content; margin-top: auto; font-weight: 700; } .resources-section ul { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem 2rem; padding: 0; list-style: none; } .resources-section a { display: inline-block; padding: 0.35rem 0; } .site-footer { margin-top: 2rem; padding-block: 2rem 3rem; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.92rem; } .site-footer p { margin: 0.25rem 0; } button, input, select, textarea { min-height: 2.75rem; border: 1px solid var(--line); border-radius: 0.4rem; background: var(--surface-raised); color: var(--text); font: inherit; } button, select { padding-inline: 0.8rem; } input, textarea { width: 100%; padding: 0.6rem 0.8rem; } .theme-toggle { white-space: nowrap; } .lesson-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1rem; align-items: end; margin-top: 1.5rem; padding: 1rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .lesson-search-field { min-width: 0; } .lesson-search-field label, .lesson-filter-field p { display: block; margin: 0 0 0.35rem; font-weight: 700; } .lesson-filter-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; } .lesson-filter-buttons button[aria-pressed="true"] { border-color: var(--action); background: var(--action); color: var(--action-text); font-weight: 700; } .lesson-empty { margin-top: 1.5rem; padding: 1rem; border-left: 0.3rem solid var(--action); background: var(--surface-raised); font-weight: 700; } @media (max-width: 46rem) { .header-inner, .site-nav { align-items: flex-start; justify-content: flex-start; } .course-hero, .day-grid, .lesson-grid, .resources-section ul { grid-template-columns: 1fr; } .lesson-controls { grid-template-columns: 1fr; align-items: stretch; } h1 { max-width: none; } .site-nav { flex-basis: 100%; } } @media print { :root, html[data-theme="dark"] { color-scheme: light; --surface: #fff; --surface-raised: #fff; --text: #000; --muted: #333; --line: #888; --link: #000; } .skip-link, .site-nav, .theme-toggle, .lesson-controls, .lesson-empty { display: none !important; } .page-shell { padding-block: 1.5rem; } .course-hero, .day-grid, .lesson-grid, .resources-section ul { grid-template-columns: 1fr; } a { color: #000; } a[href]::after { content: " (" attr(href) ")"; font-size: 0.8em; } } ===== main.js ===== (() => { "use strict"; const storageKey = "psu-course-website-theme-v1"; const root = document.documentElement; const themeToggle = document.querySelector("#theme-toggle"); const controls = document.querySelector(".lesson-controls"); const search = document.querySelector("#lesson-search"); const filterButtons = [...document.querySelectorAll("[data-filter]")]; const clearSearch = document.querySelector("#clear-search"); const status = document.querySelector("#lesson-status"); const empty = document.querySelector("#lesson-empty"); const lessons = [...document.querySelectorAll("article[data-lesson][data-day]")]; const lessonDays = [...document.querySelectorAll(".lesson-day")]; let theme = "light"; let selectedFilter = "all"; try { const savedTheme = window.localStorage.getItem(storageKey); if (savedTheme === "light" || savedTheme === "dark") { theme = savedTheme; } } catch (_) { // Theme selection still works for this visit when storage is unavailable. } function setTheme(nextTheme) { theme = nextTheme; root.dataset.theme = theme; const isDark = theme === "dark"; themeToggle.setAttribute("aria-pressed", String(isDark)); themeToggle.textContent = isDark ? "เปลี่ยนเป็นโหมดสว่าง" : "เปลี่ยนเป็นโหมดมืด"; themeToggle.setAttribute( "aria-label", isDark ? "โหมดปัจจุบัน: มืด เปลี่ยนเป็นโหมดสว่าง" : "โหมดปัจจุบัน: สว่าง เปลี่ยนเป็นโหมดมืด" ); } function normalise(value) { return value.replace(/\s+/g, " ").trim().toLocaleLowerCase(); } function lessonText(lesson) { const title = lesson.querySelector("h4"); const description = lesson.querySelector("p"); return normalise(`${title?.textContent ?? ""} ${description?.textContent ?? ""}`); } function updateLessons() { const query = normalise(search.value); let count = 0; lessons.forEach((lesson) => { const matchesFilter = selectedFilter === "all" || lesson.dataset.day === selectedFilter; const matchesQuery = query === "" || lessonText(lesson).includes(query); const visible = matchesFilter && matchesQuery; lesson.hidden = !visible; if (visible) count += 1; }); lessonDays.forEach((day) => { day.hidden = !day.querySelector("article[data-lesson]:not([hidden])"); }); empty.hidden = count !== 0; status.textContent = `พบบทเรียน ${count} จาก ${lessons.length} บท`; } function setFilter(nextFilter) { selectedFilter = nextFilter; filterButtons.forEach((button) => { button.setAttribute("aria-pressed", String(button.dataset.filter === selectedFilter)); }); updateLessons(); } if (themeToggle) { themeToggle.hidden = false; setTheme(theme); themeToggle.addEventListener("click", () => { const nextTheme = theme === "dark" ? "light" : "dark"; setTheme(nextTheme); try { window.localStorage.setItem(storageKey, nextTheme); } catch (_) { // Storage can be disabled without preventing the visual toggle. } }); } if (controls && search && clearSearch && status && empty && lessons.length > 0) { controls.hidden = false; search.addEventListener("input", updateLessons); filterButtons.forEach((button) => { button.addEventListener("click", () => setFilter(button.dataset.filter)); }); clearSearch.addEventListener("click", () => { search.value = ""; setFilter("all"); search.focus(); }); updateLessons(); } })(); ===== acceptance-notes.md ===== # Acceptance notes ## ตรวจที่ทำได้จริง - ตรวจ source ด้วย `rg` และการอ่านไฟล์ว่า HTML มีบทเรียน `article[data-lesson][data-day]` 11 บท: Day 1 คือ 00–05 (6 บท) และ Day 2 คือ 06–10 (5 บท) - ตรวจว่า controls ของ theme, search และ filter เริ่มต้นด้วย `hidden`; หาก JavaScript ไม่ทำงาน เนื้อหาบทเรียนและลิงก์ anchor ทั้ง 11 บทยังคงอยู่ใน HTML - ตรวจว่า `main.js` ใช้ `textContent` เพื่อนำชื่อและคำอธิบายมาค้นหา และไม่สร้าง HTML จากค่าค้นหาของผู้ใช้ - ตรวจ logic แบบ static ว่า default theme คือ light, `data-theme` อยู่บน `html`, `aria-pressed` เปลี่ยนตาม dark mode, และอ่าน/เขียน `psu-course-website-theme-v1` อยู่ใน `try/catch` - ตรวจว่า search trim ช่องว่าง, search/filter ประกอบกัน, clear คืนค่า query และ filter all แล้วจึง focus ช่องค้นหา - ตรวจ CSS ว่ามี `[hidden] { display: none !important; }` และ media print ยังบังคับสีสำหรับกระดาษพร้อมซ่อน controls ## สิ่งที่ยังรอการตรวจในเบราว์เซอร์ - ยังไม่ได้รันเบราว์เซอร์หรือ local server ในงานนี้ จึงยังไม่ได้ยืนยันการกดปุ่ม, การประกาศ live region, keyboard focus, localStorage ที่ถูกปิด, responsive layout, reduced-motion และ print preview จาก runtime จริง EXIT 0 EXECUTED COMMAND /bin/bash -lc "wc -l inputs.md brief.md index.html style.css main.js acceptance-notes.md && sed -n '1,260p' brief.md && sed -n '1,320p' index.html && sed -n '1,300p' style.css" OUTPUT 33 inputs.md 135 brief.md 192 index.html 158 style.css 106 main.js 14 acceptance-notes.md 638 total # Brief — เว็บไซต์ตัวอย่างรายวิชา 977-121 ## กรอบงานและสถานะข้อมูล - **ขอบเขตผลลัพธ์:** เอกสารสังเคราะห์สำหรับหน้า static HTML/CSS/JS ภาษาไทยหน้าเดียวในอนาคต; เอกสารนี้ไม่ใช่หน้าเว็บ และไม่มีการทำ web research - **สถานะ:** Draft สำหรับให้เจ้าของตรวจสอบก่อนเข้าสู่ semantic HTML - **ตำแหน่งผลิตภัณฑ์:** เว็บไซต์ตัวอย่างประกอบการเรียนที่ `/examples/course-website/` ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ - **ข้อจำกัด:** ไม่สร้างตรา/โลโก้มหาวิทยาลัย ข้อมูลผู้สอน หน่วยกิต ตารางภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร บัญชี LMS หรือ login/รับสมัครจำลอง ## FACT - ชื่อรายวิชา: **977-121 Module: Website Design and Development** - สถาบันที่ระบุ: **มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus** - **AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI** เป็น workshop ภายในรายวิชา ระยะเวลา 2 วัน × 4 ชั่วโมง (รวม 8 ชั่วโมง) และมีพัก 10 นาทีต่อวัน; ไม่ใช่ชั่วโมง หน่วยกิต หรือประมวลรายวิชาฉบับเต็มของมหาวิทยาลัย - มีบทเรียนจริง 11 บท (00–10) และมีปลายทางบทเรียน/ทรัพยากรตาม content inventory ด้านล่าง - visual system ที่มีอยู่ใช้ Inter + Noto Sans Thai, light เป็นค่าเริ่มต้น และใช้สีเขียวอย่างจำกัดเพื่อเน้น ## INFERENCE - ผู้เข้าชมหลักต้องการตอบคำถามเร็ว ๆ ว่า “เริ่มตรงไหน”, “มีบทเรียนใดบ้าง” และ “workshop สองวันนี้ทำอะไร”; ดังนั้นหน้าเดียวควรให้ทางเลือกเริ่มเรียนและแผน Day 1/Day 2 อยู่ก่อนเนื้อหารายละเอียด - CTA ควรพาไปยังปลายทางที่มีอยู่จริงเท่านั้น และป้ายกำกับต้องบอกชนิด/สถานะของปลายทางอย่างตรงไปตรงมา โดยเฉพาะลิงก์บทความแบบทีละขั้นที่ยังอยู่ระหว่างสร้าง - เนื่องจาก workshop เป็นเพียงส่วนหนึ่งของ module จึงควรนำเสนอเป็น “แผน workshop” ไม่ใช่ตารางสอนหรือคำอธิบายรายวิชาฉบับสมบูรณ์ ## PROPOSAL ### เป้าหมายและ audience **เป้าหมายหลัก:** ช่วยผู้เรียนค้นพบเส้นทางเริ่มเรียน เข้าถึงบทเรียนจริง และเข้าใจขอบเขตของ AI Web Studio workshop โดยไม่ทำให้เข้าใจว่าเป็นเว็บไซต์ทางการหรือระบบรับสมัคร **Audience หลัก:** ผู้เรียนที่ต้องการเริ่มทำเว็บไซต์ด้วย AI และต้องเลือกบทเรียน/ดูภาพรวม workshop ก่อนเข้าเนื้อหา **Audience รอง:** ผู้สอนหรือผู้ทบทวนสื่อที่ต้องการตรวจรายการบทเรียนและปลายทางของหลักสูตรอย่างรวดเร็ว ### ข้อเสนอคุณค่า (value proposition) “เส้นทางเรียนรู้เพื่อออกแบบและพัฒนาเว็บไซต์ด้วย AI: เริ่มจากเครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้ พร้อม workshop สองวันเป็นส่วนหนึ่งของ module.” ### CTA และปลายทาง | ระดับ | ป้าย CTA ที่เสนอ | ปลายทาง | หมายเหตุ | | --- | --- | --- | --- | | หลัก | `เริ่มจากบทเรียน 00` | `/learn/lessons/00-setup-and-web-basics/` | เริ่มต้นที่จุดเข้าเรียนชัดเจน | | รอง | `ดูบทเรียนทั้งหมด` | `/` | ใช้เมื่อหน้าเว็บไซต์สื่อหลักสูตรแสดงรายการเรียน; ยืนยัน label ใน implementation อีกครั้ง | | รอง | `ดูแผน AI Web Studio 2 วัน` | anchor `#workshop` | เลื่อนภายในหน้า ไม่อ้างว่าเป็นตารางรายวิชาเต็ม | | รอง | `เปิดคู่มือการเรียน` | `/handbook/` | ปลายทางที่มีจริง | | รอง | `ดูทรัพยากร` | `/resources/` | ปลายทางที่มีจริง | | บริบท | `อ่านการสร้างทีละขั้น` | `/learn/labs/build-course-website-step-by-step/` | ติดป้าย “กำลังสร้าง” จนกว่าจะยืนยันว่าเผยแพร่แล้ว | | เครดิต | `Rawinnipa` | `https://rawinsoft.com/` | ลิงก์ผู้ออกแบบ/ผู้จัดทำสื่อเท่านั้น ไม่อ้าง partnership หรือเจ้าของมหาวิทยาลัย | ### ลำดับ section ของหน้าเดียว 1. **Utility/header** — ชื่อรายวิชา, สถาบัน, ป้าย “เว็บไซต์ตัวอย่างประกอบการเรียน”, การข้ามไปเนื้อหาหลัก (skip link), สวิตช์ theme 2. **Hero** — ชื่อรายวิชาเต็ม, ชื่อ workshop, value proposition, CTA หลัก และ CTA ดู workshop 3. **ขอบเขต AI Web Studio** — ข้อความชัดเจนว่าเป็นส่วนหนึ่งของ module; 2 วัน × 4 ชั่วโมง, พัก 10 นาที/วัน, รวม 8 ชั่วโมง; ไม่แทนรายละเอียดรายวิชาฉบับมหาวิทยาลัย 4. **แผน workshop Day 1 / Day 2** — สรุปกิจกรรมตามระดับหัวข้อเท่านั้น; ไม่ประดิษฐ์ตารางเวลาเต็มหรือผลการประเมิน 5. **เส้นทางบทเรียน** — รายการ 00–10 พร้อมชื่อและลิงก์ที่มีจริง; search/filter แบบ optional: ทั้งหมด, Day 1, Day 2 โดยต้องประกาศเกณฑ์การจัดกลุ่มก่อนใช้ 6. **Labs และแหล่งเรียนต่อ** — ลิงก์ labs ที่มีจริง, handbook และ resources; ลิงก์ “อ่านการสร้างทีละขั้น” พร้อมป้าย “กำลังสร้าง” 7. **ข้อจำกัด/ความโปร่งใส** — ย้ำสถานะเว็บไซต์ตัวอย่าง; ไม่มี login, รับสมัคร, LMS หรือข้อมูลทางวิชาการที่ยังไม่ยืนยัน 8. **Footer** — ชื่อรายวิชาและ PSU Phuket เป็นข้อความ, ลิงก์ Rawinnipa ตามขอบเขตเครดิต; ไม่มีตราหรือโลโก้ที่สร้างขึ้น ### Content inventory | กลุ่ม | เนื้อหาที่แสดง | ปลายทาง | | --- | --- | --- | | รายวิชา | 977-121 Module: Website Design and Development; มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต / Prince of Songkla University, Phuket Campus | ไม่มีลิงก์สถาบันที่ยืนยัน | | Workshop | AI Web Studio — ออกแบบและพัฒนาเว็บไซต์ด้วย AI; 2 วัน × 4 ชั่วโมง = 8 ชั่วโมง; พัก 10 นาที/วัน | `#workshop` | | บทเรียน 00 | เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร | `/learn/lessons/00-setup-and-web-basics/` | | บทเรียน 01 | พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง | `/learn/lessons/01-vibe-coding-foundations/` | | บทเรียน 02 | Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง | `/learn/lessons/02-agent-skills/` | | บทเรียน 03 | Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation | `/learn/lessons/03-specs-and-prompts/` | | บทเรียน 04 | ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ | `/learn/lessons/04-design-and-assets/` | | บทเรียน 05 | เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง | `/learn/lessons/05-company-website/` | | บทเรียน 06 | เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง | `/learn/lessons/06-rental-and-data/` | | บทเรียน 07 | GSAP product story, storefront และ quote demo | `/learn/lessons/07-gsap-storefront/` | | บทเรียน 08 | รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้ | `/learn/lessons/08-cloudflare-deploy/` | | บทเรียน 09 | Production Operations: security, observability, rollback และต้นทุน | `/learn/lessons/09-production-operations/` | | บทเรียน 10 | สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้ | `/learn/lessons/10-capstone-and-handoff/` | | Labs/ทรัพยากร | install AI tools; research-to-brand website; design tools and MCP; resources; handbook | `/learn/labs/install-ai-tools/`; `/learn/labs/research-to-brand-website/`; `/learn/labs/design-tools-and-mcp/`; `/resources/`; `/handbook/` | ### States | State | ข้อเสนอพฤติกรรม/ข้อความ | | --- | --- | | Default | แสดง hero, CTA, workshop summary และรายการบทเรียนทั้งหมด | | Light (default) | พื้น `#F7F7F7`, ข้อความ `#0A0A0A`, accent `#3EDC81` พร้อมข้อความเข้ม, ข้อความเขียวบนพื้นอ่อน `#17653F` | | Dark | canvas `#0A0A0A`, surface `#171717`, ข้อความ `#F7F7F7`; รักษา contrast และไม่ใช้เขียวเป็นข้อความหลักบนพื้นมืดหากยังไม่ตรวจ contrast | | Theme preference | ใช้ light เป็น default; หากมีสวิตช์ ต้องมองเห็นสถานะและทำงานด้วยคีย์บอร์ด | | Lesson filter/search (optional) | แสดงผล “ไม่พบบทเรียนที่ตรงกัน” พร้อมปุ่ม/ลิงก์คืนค่า; filter Day 1/Day 2 ใช้ได้ต่อเมื่อเจ้าของยืนยัน mapping | | CTA pending | `อ่านการสร้างทีละขั้น` มีป้าย “กำลังสร้าง” และไม่อ้างว่าอ่านได้แล้ว | | Link failure/unknown | ไม่สร้างหน้า 404 หรือ loading simulation; ใช้เฉพาะปลายทางที่ S5 ระบุ | | Print | พื้นกระดาษขาว, ข้อความอ่านได้, ไม่พึ่งสีอย่างเดียวเพื่อสื่อความหมาย | ### Responsive - **Mobile ก่อน:** หนึ่งคอลัมน์, CTA กว้างแตะง่าย, nav ไม่บังคับเลื่อนแนวนอน, lesson cards เรียงแนวตั้ง - **Tablet:** hero และ workshop สามารถจัดสองคอลัมน์เมื่อยังเหลือพื้นที่อ่านง่าย; filters อยู่ก่อนรายการผลลัพธ์ - **Desktop:** ใช้ความกว้างข้อความจำกัดเพื่อการอ่าน, lesson grid หลายคอลัมน์ตามพื้นที่, header ยังเข้าถึง CTA หลักได้ - ทุกขนาด: ไม่ซ่อนเนื้อหาสำคัญเพียงเพราะ viewport, รองรับ text zoom/reflow, และไม่ยึดความหมายด้วย hover เพียงอย่างเดียว ### Accessibility acceptance checks - [ ] ใช้ semantic landmarks (`header`, `nav`, `main`, `section`, `footer`) และลำดับ heading ไม่ข้ามระดับ - [ ] มี skip link; ทุก CTA/ลิงก์เข้าถึงด้วยคีย์บอร์ด และ focus ชัดเจน - [ ] สี light/dark และทุกสถานะ focus/hover/selected ผ่าน contrast ที่เหมาะสม; สีเขียวไม่ใช่ตัวบอกความหมายเพียงอย่างเดียว - [ ] สวิตช์ theme และ filter/search (หากสร้าง) มี accessible name, state และประกาศการเปลี่ยนแปลงผลลัพธ์อย่างเหมาะสม - [ ] ข้อความไทยใช้ Noto Sans Thai และข้อความ Latin ใช้ Inter จาก font ในระบบ; ไม่มี external font - [ ] ขนาดเป้าหมายสัมผัสเพียงพอ, หน้า reflow ได้ที่ความกว้างแคบ/zoom, และไม่มี horizontal overflow โดยไม่จำเป็น - [ ] ไม่มีภาพที่ต้องพึ่งพาเพื่อเข้าใจเนื้อหา; ถ้ามี SVG ตกแต่งต้องซ่อนจาก assistive technology - [ ] โครงสร้าง print เป็นพื้นขาวและยังอ่านลิงก์/ป้าย “กำลังสร้าง” ได้ ## ทางเลือกภาพ (ไม่สร้าง raster/ตรามหาวิทยาลัย) ### ทางเลือก A — Type-led learning map ใช้ typography เป็นภาพหลัก: หมายเลขบทเรียน 00–10 ขนาดใหญ่, เส้นทาง/จุดสถานะด้วย CSS หรือ SVG ธรรมดา, และ chip “Day 1/Day 2”. ภาพสื่อการเดินทางผ่านเนื้อหาโดยไม่ต้องใช้รูปถ่ายหรือสินทรัพย์ใหม่; ใช้ green เฉพาะจุดเริ่มต้น, CTA และสถานะที่ได้รับการยืนยัน. ### ทางเลือก B — Editorial workshop cards ใช้การ์ดขาว/ผิว dark ที่มีตัวเลข “Day 1”, “Day 2” และ glyph จาก HTML/SVG ธรรมดา (เช่น cursor, bracket, check) พร้อมภาพพิมพ์ขนาดใหญ่. ให้บรรยากาศ workshop ชัด แต่ต้องระวังไม่ทำให้ผู้ใช้เข้าใจว่าบัตรเหล่านี้คือกำหนดการรายวิชาทางการ. ### Draft ที่เลือก — ทางเลือก A เลือก **Type-led learning map** เพราะสอดคล้องกับแบรนด์เดิมที่เรียบ ใช้สีเขียวจำกัด และให้บทเรียนจริงเป็นศูนย์กลาง. ลดความเสี่ยงการสร้างภาพ/ตรามหาวิทยาลัยหรือการใส่บริบท workshop เกินข้อเท็จจริง. จะใช้เฉพาะข้อความ, HTML และ SVG ธรรมดาตามสินทรัพย์ที่อนุญาต. ## GAP — ต้องถามเจ้าของก่อน implementation 1. ต้องการให้ชื่อไทยของรายวิชามีหรือไม่? ปัจจุบันยืนยันเพียงชื่อ `977-121 Module: Website Design and Development`. 2. Mapping ที่ได้รับอนุมัติของบทเรียนใดอยู่ Day 1 และ Day 2 คืออะไร? จนกว่าจะยืนยัน ต้องไม่เปิด filter Day 1/Day 2 หรือใส่ป้ายรายบท. 3. CTA `ดูบทเรียนทั้งหมด` ควรชี้ไปหน้าใด/anchor ใด? S5 ยืนยันเพียง `/` เป็นเว็บไซต์สื่อหลักสูตร ไม่ได้ยืนยันส่วนรายการบทเรียน. 4. ปลายทาง `/learn/labs/build-course-website-step-by-step/` เผยแพร่เมื่อใด? ก่อนนั้นต้องคงป้าย “กำลังสร้าง” หรือซ่อน CTA. 5. อนุมัติข้อความ disclaimer ว่า “เว็บไซต์ตัวอย่างประกอบการเรียน ไม่ใช่ระบบมหาวิทยาลัยอย่างเป็นทางการ” หรือมีถ้อยคำที่เจ้าของกำหนดหรือไม่? 6. ผู้ใช้ต้องการ theme toggle จริงหรือเพียงรองรับ system preference? ข้อกำหนด design system ระบุ light default และ dark palette แต่ยังไม่ยืนยัน interaction. 7. ยืนยันว่าต้องการแสดงลิงก์ Rawinnipa ใน footer หรือไม่; หากแสดงให้ใช้เพียงเครดิตผู้ออกแบบ/ผู้จัดทำสื่อ. 8. ผู้สอน หน่วยกิต ภาคเรียน เกณฑ์คะแนน ช่องทางสมัคร และ LMS จะได้รับอนุมัติให้แสดงหรือไม่? ถ้าไม่ ต้องคงไม่แสดงทั้งหมด. 977-121 Module: Website Design and Development | AI Web Studio

AI Web Studio

977-121 Module: Website Design and Development

ออกแบบและพัฒนาเว็บไซต์ด้วย AI

เส้นทางเรียนรู้เพื่อเริ่มสร้างเว็บไซต์ด้วย AI ตั้งแต่เครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้

เริ่มจากบทเรียน 00 ดูบทเรียนทั้งหมด

ภาพรวมเส้นทางการทำงาน

  1. Brief
  2. Build
  3. Verify
  4. Publish

เป้าหมายของ workshop

AI Web Studio เป็นส่วนหนึ่งของรายวิชา เพื่อช่วยผู้เรียนเลือกจุดเริ่มต้น เข้าถึงบทเรียนจริง และฝึกสร้างเว็บไซต์ด้วย AI อย่างมีขั้นตอน

  • เข้าใจเครื่องมือและพื้นฐานของเว็บก่อนเริ่มลงมือ
  • ใช้ specs, prompts และเครื่องมือ AI เพื่อพัฒนาเว็บไซต์
  • ตรวจคุณภาพและส่งมอบงานที่ตรวจสอบได้

workshop นี้ไม่ใช่รายละเอียดรายวิชาฉบับมหาวิทยาลัยหรือระบบมหาวิทยาลัยอย่างเป็นทางการ

แผน AI Web Studio 2 วัน

รวม 8 ชั่วโมง: 2 วัน วันละ 4 ชั่วโมง และพัก 10 นาทีต่อวัน

แผนนี้เป็นเส้นทางเลือกใช้คลังบทเรียนตามเวลาจริงในห้องเรียน ไม่ได้สัญญาว่าจะสอนครบทุกบทภายใน 8 ชั่วโมง

Day 1 — เริ่มต้น ออกแบบ และสร้างฐานงาน

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 00–05 เพื่อเตรียมเครื่องมือ วางบริบท และเริ่มทำเว็บไซต์

Day 2 — ขยายงาน ตรวจสอบ และส่งมอบ

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 06–10 เพื่อทำงานกับข้อมูล ประสบการณ์เว็บ การ deploy และการส่งมอบ

เส้นทางบทเรียน

บท 00–05 อยู่ในเส้นทาง Day 1 และบท 06–10 อยู่ในเส้นทาง Day 2 เพื่อใช้เลือกเนื้อหาใน workshop

Day 1: บท 00–05

00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร

เตรียมเครื่องมือและทำความเข้าใจพื้นฐานการทำงานของเว็บก่อนเริ่มสร้างงาน

อ่านบทเรียน 00

01 — พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง

เรียนรู้พื้นฐาน Vibe Coding เพื่อสร้างเว็บที่พร้อมส่งมอบ

อ่านบทเรียน 01

02 — Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง

ทำความเข้าใจ Agent Skills, MCP และ Plugins พร้อมดูแลบริบทการทำงาน

อ่านบทเรียน 02

03 — Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation

เขียน specs และ prompts สำหรับเว็บบริษัท catalog และเว็บที่มี animation

อ่านบทเรียน 03

04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ

วางงานออกแบบ ภาพ และเกณฑ์คุณภาพก่อนเริ่มเขียนหน้าเว็บ

อ่านบทเรียน 04

05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง

สร้างเว็บบริษัทและ contact form ที่ทำงานกับ demo ได้จริง

อ่านบทเรียน 05

Day 2: บท 06–10

06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง

พัฒนาเว็บเช่าอุปกรณ์ที่จัดการ availability และ capacity ของ demo ได้

อ่านบทเรียน 06

08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้

รันโปรเจกต์และตรวจเส้นทาง deployment ของ Cloudflare

อ่านบทเรียน 08

09 — Production Operations: security, observability, rollback และต้นทุน

ดูแล production ทั้งความปลอดภัย การสังเกตการณ์ การ rollback และต้นทุน

อ่านบทเรียน 09

10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้

สร้างเว็บของตนเองและเตรียมการส่งมอบที่ตรวจสอบได้

อ่านบทเรียน 10

Labs และแหล่งเรียนต่อ

977-121 Module: Website Design and Development · มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต

สื่อออกแบบและจัดทำโดย Rawinnipa

@font-face { font-family: "Inter"; src: url("/fonts/Inter-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: "Inter"; src: url("/fonts/Inter-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; } @font-face { font-family: "Noto Sans Thai"; src: url("/fonts/NotoSansThai-Regular.woff2") format("woff2"); font-weight: 400; font-style: normal; font-display: swap; } @font-face { font-family: "Noto Sans Thai"; src: url("/fonts/NotoSansThai-Bold.woff2") format("woff2"); font-weight: 700; font-style: normal; font-display: swap; } :root { color-scheme: light; --surface: #f7f7f7; --surface-raised: #ffffff; --text: #0a0a0a; --muted: #505050; --line: #d0d0d0; --action: #3edc81; --action-text: #063119; --link: #17653f; --focus: #17653f; --radius: 0.75rem; --page-width: 72rem; } html[data-theme="dark"] { color-scheme: dark; --surface: #0a0a0a; --surface-raised: #171717; --text: #f7f7f7; --muted: #c8c8c8; --line: #555555; --action: #3edc81; --action-text: #062c16; --link: #82efae; --focus: #82efae; } * { box-sizing: border-box; } [hidden] { display: none !important; } html { background: var(--surface); } body { margin: 0; min-width: 0; background: var(--surface); color: var(--text); font-family: Inter, "Noto Sans Thai", sans-serif; font-size: 1rem; line-height: 1.7; overflow-wrap: anywhere; } a { color: var(--link); text-decoration-thickness: 0.12em; text-underline-offset: 0.18em; } a:hover { color: var(--text); } a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; } .skip-link { position: fixed; z-index: 5; top: 0.75rem; left: 0.75rem; padding: 0.6rem 0.85rem; background: var(--action); color: var(--action-text); transform: translateY(-150%); } .skip-link:focus { transform: translateY(0); } .site-header { border-bottom: 1px solid var(--line); } .header-inner, .page-shell, .site-footer { width: min(100% - 2rem, var(--page-width)); margin-inline: auto; } .header-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem; padding-block: 1.15rem; } .course-identity p { margin: 0; } .eyebrow, .preview-label { margin: 0; color: var(--muted); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; } .course-code { font-weight: 700; } .institution { color: var(--muted); font-size: 0.9rem; } .site-nav { display: flex; flex: 1 1 26rem; flex-wrap: wrap; justify-content: flex-end; gap: 0.4rem 1rem; } .site-nav a { padding: 0.35rem 0; white-space: nowrap; } .page-shell { padding-block: clamp(2.5rem, 6vw, 5.5rem); } .course-hero { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(15rem, 0.65fr); gap: clamp(1.5rem, 5vw, 5rem); align-items: end; padding-bottom: clamp(2.5rem, 5vw, 4rem); border-bottom: 1px solid var(--line); } h1, h2, h3, h4 { margin: 0; color: var(--text); line-height: 1.22; text-wrap: balance; } h1 { max-width: 15ch; font-size: clamp(2.3rem, 7vw, 5.6rem); letter-spacing: -0.055em; } h2 { font-size: clamp(1.65rem, 4vw, 2.7rem); letter-spacing: -0.035em; } h3 { font-size: clamp(1.2rem, 2.2vw, 1.55rem); } h4 { font-size: 1.08rem; } .hero-subtitle { margin: 1.15rem 0 0; font-size: clamp(1.15rem, 2vw, 1.5rem); font-weight: 700; } .hero-summary { max-width: 58ch; margin: 0.85rem 0 0; color: var(--muted); font-size: 1.08rem; } .hero-actions { display: flex; flex-wrap: wrap; gap: 0.75rem 1.25rem; margin: 1.75rem 0 0; align-items: center; } .hero-actions a:first-child { display: inline-flex; min-height: 2.8rem; align-items: center; padding: 0.55rem 1rem; background: var(--action); border: 1px solid var(--action); border-radius: var(--radius); color: var(--action-text); font-weight: 700; text-decoration: none; } .learning-preview { padding: clamp(1.25rem, 3vw, 2rem); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .learning-preview ol { display: grid; gap: 0.75rem; margin: 1rem 0 0; padding: 0; list-style: none; counter-reset: route; } .learning-preview li { display: flex; align-items: center; gap: 0.7rem; font-weight: 700; } .learning-preview li::before { display: grid; width: 1.8rem; height: 1.8rem; place-items: center; border: 1px solid var(--line); border-radius: 50%; color: var(--muted); content: counter(route, decimal-leading-zero); counter-increment: route; font: 700 0.7rem/1 Inter, sans-serif; } .content-section { padding-top: clamp(3rem, 8vw, 7rem); } .content-section > p, .goals-section li { max-width: 72ch; } .content-section > p { color: var(--muted); } .goals-section ul { padding-left: 1.25rem; } .day-grid, .lesson-grid { display: grid; gap: 1rem; margin-top: 1.5rem; } .day-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .day-card, [data-lesson] { min-width: 0; padding: clamp(1.1rem, 3vw, 1.6rem); border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .day-card p, [data-lesson] p { color: var(--muted); } .lesson-day + .lesson-day { margin-top: 2.5rem; } .lesson-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } [data-lesson] { display: flex; flex-direction: column; gap: 0.85rem; } [data-lesson] p { margin: 0; } [data-lesson] a { width: fit-content; margin-top: auto; font-weight: 700; } .resources-section ul { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem 2rem; padding: 0; list-style: none; } .resources-section a { display: inline-block; padding: 0.35rem 0; } .site-footer { margin-top: 2rem; padding-block: 2rem 3rem; border-top: 1px solid var(--line); color: var(--muted); font-size: 0.92rem; } .site-footer p { margin: 0.25rem 0; } button, input, select, textarea { min-height: 2.75rem; border: 1px solid var(--line); border-radius: 0.4rem; background: var(--surface-raised); color: var(--text); font: inherit; } button, select { padding-inline: 0.8rem; } input, textarea { width: 100%; padding: 0.6rem 0.8rem; } .theme-toggle { white-space: nowrap; } .lesson-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 1rem; align-items: end; margin-top: 1.5rem; padding: 1rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-raised); } .lesson-search-field { min-width: 0; } .lesson-search-field label, .lesson-filter-field p { display: block; margin: 0 0 0.35rem; font-weight: 700; } .lesson-filter-buttons { display: flex; flex-wrap: wrap; gap: 0.5rem; } .lesson-filter-buttons button[aria-pressed="true"] { border-color: var(--action); background: var(--action); color: var(--action-text); font-weight: 700; } .lesson-empty { margin-top: 1.5rem; padding: 1rem; border-left: 0.3rem solid var(--action); background: var(--surface-raised); font-weight: 700; } @media (max-width: 46rem) { .header-inner, .site-nav { align-items: flex-start; justify-content: flex-start; } .course-hero, .day-grid, .lesson-grid, .resources-section ul { grid-template-columns: 1fr; } .lesson-controls { grid-template-columns: 1fr; align-items: stretch; } h1 { max-width: none; } .site-nav { flex-basis: 100%; } } @media print { :root, html[data-theme="dark"] { color-scheme: light; --surface: #fff; --surface-raised: #fff; --text: #000; --muted: #333; --line: #888; --link: #000; } .skip-link, .site-nav, .theme-toggle, .lesson-controls, .lesson-empty { display: none !important; } .page-shell { padding-block: 1.5rem; } .course-hero, .day-grid, .lesson-grid, .resources-section ul { grid-template-columns: 1fr; } a { color: #000; } a[href]::after { content: " (" attr(href) ")"; font-size: 0.8em; } } EXIT 0 CODEX MESSAGE พบข้อบกพร่องที่ยืนยันได้หนึ่งจุด: CSS ยังไม่มีการเคารพ `prefers-reduced-motion` แม้ skip link ใช้ `transform` เพื่อเลื่อนเข้า/ออก. ผมจะแก้แบบจำกัดผลกระทบและปรับบันทึกการตรวจให้แยกผลจากซอร์สออกจากสิ่งที่ยังต้องทดสอบในเบราว์เซอร์. EXECUTED COMMAND /bin/bash -lc "nl -ba index.html | sed -n '1,220p' nl -ba main.js | sed -n '1,180p' nl -ba acceptance-notes.md | sed -n '1,120p' rg -n 'data-day=\"day1\"|data-day=\"day2\"|prefers-reduced-motion| 2 3 4 5 6 7 977-121 Module: Website Design and Development | AI Web Studio 8 9 10 11 12 13 32 33
34
35
36

AI Web Studio

37

977-121 Module: Website Design and Development

38

ออกแบบและพัฒนาเว็บไซต์ด้วย AI

39

เส้นทางเรียนรู้เพื่อเริ่มสร้างเว็บไซต์ด้วย AI ตั้งแต่เครื่องมือและพื้นฐาน ไปจนถึงการส่งมอบที่ตรวจสอบได้

40

41 เริ่มจากบทเรียน 00 42 ดูบทเรียนทั้งหมด 43

44
45
46

ภาพรวมเส้นทางการทำงาน

47
    48
  1. Brief
  2. 49
  3. Build
  4. 50
  5. Verify
  6. 51
  7. Publish
  8. 52
53
54
55 56
57

เป้าหมายของ workshop

58

AI Web Studio เป็นส่วนหนึ่งของรายวิชา เพื่อช่วยผู้เรียนเลือกจุดเริ่มต้น เข้าถึงบทเรียนจริง และฝึกสร้างเว็บไซต์ด้วย AI อย่างมีขั้นตอน

59
    60
  • เข้าใจเครื่องมือและพื้นฐานของเว็บก่อนเริ่มลงมือ
  • 61
  • ใช้ specs, prompts และเครื่องมือ AI เพื่อพัฒนาเว็บไซต์
  • 62
  • ตรวจคุณภาพและส่งมอบงานที่ตรวจสอบได้
  • 63
64

workshop นี้ไม่ใช่รายละเอียดรายวิชาฉบับมหาวิทยาลัยหรือระบบมหาวิทยาลัยอย่างเป็นทางการ

65
66 67
68

แผน AI Web Studio 2 วัน

69

รวม 8 ชั่วโมง: 2 วัน วันละ 4 ชั่วโมง และพัก 10 นาทีต่อวัน

70

แผนนี้เป็นเส้นทางเลือกใช้คลังบทเรียนตามเวลาจริงในห้องเรียน ไม่ได้สัญญาว่าจะสอนครบทุกบทภายใน 8 ชั่วโมง

71
72
73

Day 1 — เริ่มต้น ออกแบบ และสร้างฐานงาน

74

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 00–05 เพื่อเตรียมเครื่องมือ วางบริบท และเริ่มทำเว็บไซต์

75
76
77

Day 2 — ขยายงาน ตรวจสอบ และส่งมอบ

78

4 ชั่วโมง รวมพัก 10 นาที: เลือกกิจกรรมจากบท 06–10 เพื่อทำงานกับข้อมูล ประสบการณ์เว็บ การ deploy และการส่งมอบ

79
80
81
82 83
84

เส้นทางบทเรียน

85

บท 00–05 อยู่ในเส้นทาง Day 1 และบท 06–10 อยู่ในเส้นทาง Day 2 เพื่อใช้เลือกเนื้อหาใน workshop

86 87 103 104 105
106

Day 1: บท 00–05

107
108
109

00 — เตรียมเครื่องและเข้าใจว่าเว็บทำงานอย่างไร

110

เตรียมเครื่องมือและทำความเข้าใจพื้นฐานการทำงานของเว็บก่อนเริ่มสร้างงาน

111 อ่านบทเรียน 00 112
113
114

01 — พื้นฐาน Vibe Coding สำหรับเว็บที่ส่งมอบได้จริง

115

เรียนรู้พื้นฐาน Vibe Coding เพื่อสร้างเว็บที่พร้อมส่งมอบ

116 อ่านบทเรียน 01 117
118
119

02 — Agent Skills, MCP และ Plugins โดยไม่ทำให้บริบทพัง

120

ทำความเข้าใจ Agent Skills, MCP และ Plugins พร้อมดูแลบริบทการทำงาน

121 อ่านบทเรียน 02 122
123
124

03 — Specs และ Prompts สำหรับเว็บบริษัท, Catalog และเว็บ animation

125

เขียน specs และ prompts สำหรับเว็บบริษัท catalog และเว็บที่มี animation

126 อ่านบทเรียน 03 127
128
129

04 — ออกแบบ, ภาพ และคุณภาพก่อนเขียนหน้าเว็บ

130

วางงานออกแบบ ภาพ และเกณฑ์คุณภาพก่อนเริ่มเขียนหน้าเว็บ

131 อ่านบทเรียน 04 132
133
134

05 — เว็บบริษัท: contact form ที่รันกับ demo นี้ได้จริง

135

สร้างเว็บบริษัทและ contact form ที่ทำงานกับ demo ได้จริง

136 อ่านบทเรียน 05 137
138
139
140 141
142

Day 2: บท 06–10

143
144
145

06 — เว็บเช่าอุปกรณ์: availability และ capacity ของ demo ที่รันได้จริง

146

พัฒนาเว็บเช่าอุปกรณ์ที่จัดการ availability และ capacity ของ demo ได้

147 อ่านบทเรียน 06 148
149
150

07 — GSAP product story, storefront และ quote demo

151

สร้าง product story, storefront และ quote demo ด้วย GSAP

152 อ่านบทเรียน 07 153
154
155

08 — รันและตรวจ deployment path ของโปรเจกต์ Cloudflare นี้

156

รันโปรเจกต์และตรวจเส้นทาง deployment ของ Cloudflare

157 อ่านบทเรียน 08 158
159
160

09 — Production Operations: security, observability, rollback และต้นทุน

161

ดูแล production ทั้งความปลอดภัย การสังเกตการณ์ การ rollback และต้นทุน

162 อ่านบทเรียน 09 163
164
165

10 — สร้างเว็บของตนเองและส่งมอบอย่างตรวจสอบได้

166

สร้างเว็บของตนเองและเตรียมการส่งมอบที่ตรวจสอบได้

167 อ่านบทเรียน 10 168
169
170
171
172 173
174

Labs และแหล่งเรียนต่อ

175 183
184
185 186
187

977-121 Module: Website Design and Development · มหาวิทยาลัยสงขลานครินทร์ วิทยาเขตภูเก็ต

188

สื่อออกแบบและจัดทำโดย Rawinnipa

189
190 191 192 1 (() => { 2 "use strict"; 3 4 const storageKey = "psu-course-website-theme-v1"; 5 const root = document.documentElement; 6 const themeToggle = document.querySelector("#theme-toggle"); 7 const controls = document.querySelector(".lesson-controls"); 8 const search = document.querySelector("#lesson-search"); 9 const filterButtons = [...document.querySelectorAll("[data-filter]")]; 10 const clearSearch = document.querySelector("#clear-search"); 11 const status = document.querySelector("#lesson-status"); 12 const empty = document.querySelector("#lesson-empty"); 13 const lessons = [...document.querySelectorAll("article[data-lesson][data-day]")]; 14 const lessonDays = [...document.querySelectorAll(".lesson-day")]; 15 16 let theme = "light"; 17 let selectedFilter = "all"; 18 19 try { 20 const savedTheme = window.localStorage.getItem(storageKey); 21 if (savedTheme === "light" || savedTheme === "dark") { 22 theme = savedTheme; 23 } 24 } catch (_) { 25 // Theme selection still works for this visit when storage is unavailable. 26 } 27 28 function setTheme(nextTheme) { 29 theme = nextTheme; 30 root.dataset.theme = theme; 31 const isDark = theme === "dark"; 32 themeToggle.setAttribute("aria-pressed", String(isDark)); 33 themeToggle.textContent = isDark ? "เปลี่ยนเป็นโหมดสว่าง" : "เปลี่ยนเป็นโหมดมืด"; 34 themeToggle.setAttribute( 35 "aria-label", 36 isDark 37 ? "โหมดปัจจุบัน: มืด เปลี่ยนเป็นโหมดสว่าง" 38 : "โหมดปัจจุบัน: สว่าง เปลี่ยนเป็นโหมดมืด" 39 ); 40 } 41 42 function normalise(value) { 43 return value.replace(/\s+/g, " ").trim().toLocaleLowerCase(); 44 } 45 46 function lessonText(lesson) { 47 const title = lesson.querySelector("h4"); 48 const description = lesson.querySelector("p"); 49 return normalise(`${title?.textContent ?? ""} ${description?.textContent ?? ""}`); 50 } 51 52 function updateLessons() { 53 const query = normalise(search.value); 54 let count = 0; 55 56 lessons.forEach((lesson) => { 57 const matchesFilter = selectedFilter === "all" || lesson.dataset.day === selectedFilter; 58 const matchesQuery = query === "" || lessonText(lesson).includes(query); 59 const visible = matchesFilter && matchesQuery; 60 lesson.hidden = !visible; 61 if (visible) count += 1; 62 }); 63 64 lessonDays.forEach((day) => { 65 day.hidden = !day.querySelector("article[data-lesson]:not([hidden])"); 66 }); 67 empty.hidden = count !== 0; 68 status.textContent = `พบบทเรียน ${count} จาก ${lessons.length} บท`; 69 } 70 71 function setFilter(nextFilter) { 72 selectedFilter = nextFilter; 73 filterButtons.forEach((button) => { 74 button.setAttribute("aria-pressed", String(button.dataset.filter === selectedFilter)); 75 }); 76 updateLessons(); 77 } 78 79 if (themeToggle) { 80 themeToggle.hidden = false; 81 setTheme(theme); 82 themeToggle.addEventListener("click", () => { 83 const nextTheme = theme === "dark" ? "light" : "dark"; 84 setTheme(nextTheme); 85 try { 86 window.localStorage.setItem(storageKey, nextTheme); 87 } catch (_) { 88 // Storage can be disabled without preventing the visual toggle. 89 } 90 }); 91 } 92 93 if (controls && search && clearSearch && status && empty && lessons.length > 0) { 94 controls.hidden = false; 95 search.addEventListener("input", updateLessons); 96 filterButtons.forEach((button) => { 97 button.addEventListener("click", () => setFilter(button.dataset.filter)); 98 }); 99 clearSearch.addEventListener("click", () => { 100 search.value = ""; 101 setFilter("all"); 102 search.focus(); 103 }); 104 updateLessons(); 105 } 106 })(); 1 # Acceptance notes 2 3 ## ตรวจที่ทำได้จริง 4 5 - ตรวจ source ด้วย `rg` และการอ่านไฟล์ว่า HTML มีบทเรียน `article[data-lesson][data-day]` 11 บท: Day 1 คือ 00–05 (6 บท) และ Day 2 คือ 06–10 (5 บท) 6 - ตรวจว่า controls ของ theme, search และ filter เริ่มต้นด้วย `hidden`; หาก JavaScript ไม่ทำงาน เนื้อหาบทเรียนและลิงก์ anchor ทั้ง 11 บทยังคงอยู่ใน HTML 7 - ตรวจว่า `main.js` ใช้ `textContent` เพื่อนำชื่อและคำอธิบายมาค้นหา และไม่สร้าง HTML จากค่าค้นหาของผู้ใช้ 8 - ตรวจ logic แบบ static ว่า default theme คือ light, `data-theme` อยู่บน `html`, `aria-pressed` เปลี่ยนตาม dark mode, และอ่าน/เขียน `psu-course-website-theme-v1` อยู่ใน `try/catch` 9 - ตรวจว่า search trim ช่องว่าง, search/filter ประกอบกัน, clear คืนค่า query และ filter all แล้วจึง focus ช่องค้นหา 10 - ตรวจ CSS ว่ามี `[hidden] { display: none !important; }` และ media print ยังบังคับสีสำหรับกระดาษพร้อมซ่อน controls 11 12 ## สิ่งที่ยังรอการตรวจในเบราว์เซอร์ 13 14 - ยังไม่ได้รันเบราว์เซอร์หรือ local server ในงานนี้ จึงยังไม่ได้ยืนยันการกดปุ่ม, การประกาศ live region, keyboard focus, localStorage ที่ถูกปิด, responsive layout, reduced-motion และ print preview จาก runtime จริง main.js:6: const themeToggle = document.querySelector("#theme-toggle"); main.js:7: const controls = document.querySelector(".lesson-controls"); main.js:12: const empty = document.querySelector("#lesson-empty"); index.html:11: index.html:13: