forked from UKSOURCE/ipv6
fix: agenda, qrcode, carousel
This commit is contained in:
@@ -5,6 +5,7 @@ type AgendaItem = {
|
||||
time: string;
|
||||
title: string;
|
||||
description: string;
|
||||
avatar?: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -53,6 +54,25 @@ const renderFormattedText = (text: string) => {
|
||||
};
|
||||
|
||||
export default function AgendaSection({ data }: Props) {
|
||||
const base = process.env.NEXT_PUBLIC_BASE_PATH || "";
|
||||
|
||||
const renderAvatar = (avatarUrl: string, sizeClass: string) => (
|
||||
<div className={`${sizeClass} rounded-full overflow-hidden border border-primary/20 bg-white/5 flex items-center justify-center backdrop-blur-sm shadow-inner shrink-0`}>
|
||||
{avatarUrl.includes("placeholder") ? (
|
||||
<svg className="w-1/2 h-1/2 text-primary/60" fill="none" stroke="currentColor" viewBox="0 0 24 24" strokeWidth={1.5}>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
) : (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={`${base}${avatarUrl}`}
|
||||
alt="Speaker"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="py-16 lg:py-24 max-w-hd mx-auto px-[var(--spacing-gutter)]" id={data.id}>
|
||||
{/* Section Header */}
|
||||
@@ -108,13 +128,25 @@ export default function AgendaSection({ data }: Props) {
|
||||
{item.time}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-[var(--font-display-lg)] text-base lg:text-lg text-on-surface mb-3 leading-snug pr-8">
|
||||
<h3 className="font-[var(--font-display-lg)] text-base lg:text-lg text-on-surface mb-3 leading-snug text-balance pr-8">
|
||||
{renderFormattedText(item.title)}
|
||||
</h3>
|
||||
{!item.description && item.avatar && (
|
||||
<div className="flex lg:justify-end justify-start mb-3">
|
||||
{renderAvatar(item.avatar, "w-10 h-10 lg:w-12 lg:h-12")}
|
||||
</div>
|
||||
)}
|
||||
{item.description && (
|
||||
<div className="text-xs lg:text-sm text-on-surface-variant/75 leading-relaxed border-t border-primary/10 pt-3 mt-3">
|
||||
<div className="text-xs lg:text-sm text-on-surface-variant/75 leading-relaxed border-t border-primary/10 pt-3 mt-3 flex flex-row lg:flex-row-reverse items-center gap-4">
|
||||
{item.avatar && (
|
||||
<div className="shrink-0">
|
||||
{renderAvatar(item.avatar, "w-10 h-10 lg:w-12 lg:h-12")}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1 lg:text-right">
|
||||
{renderFormattedText(item.description)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,13 +179,25 @@ export default function AgendaSection({ data }: Props) {
|
||||
{item.time}
|
||||
</span>
|
||||
</div>
|
||||
<h3 className="font-[var(--font-display-lg)] text-base lg:text-lg text-on-surface mb-3 leading-snug pr-8">
|
||||
<h3 className="font-[var(--font-display-lg)] text-base lg:text-lg text-on-surface mb-3 leading-snug text-balance pr-8">
|
||||
{renderFormattedText(item.title)}
|
||||
</h3>
|
||||
{!item.description && item.avatar && (
|
||||
<div className="flex justify-start mb-3">
|
||||
{renderAvatar(item.avatar, "w-10 h-10 lg:w-12 lg:h-12")}
|
||||
</div>
|
||||
)}
|
||||
{item.description && (
|
||||
<div className="text-xs lg:text-sm text-on-surface-variant/75 leading-relaxed border-t border-primary/10 pt-3 mt-3">
|
||||
<div className="text-xs lg:text-sm text-on-surface-variant/75 leading-relaxed border-t border-primary/10 pt-3 mt-3 flex flex-row items-center gap-4">
|
||||
{item.avatar && (
|
||||
<div className="shrink-0">
|
||||
{renderAvatar(item.avatar, "w-10 h-10 lg:w-12 lg:h-12")}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex-1">
|
||||
{renderFormattedText(item.description)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
// Tên file chính xác trong public/assets/img/carousel/
|
||||
const ROW_1 = [
|
||||
{ name: "IEAS", file: "ieas.png" },
|
||||
{ name: "NVIDIA", file: "Nvidia_logo.svg.png" },
|
||||
{ name: "Maxis", file: "Maxis-logo.png" },
|
||||
{ name: "Singtel", file: "Singtel_logo.svg.png" },
|
||||
|
||||
+9
-5
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"hero": {
|
||||
"badgeIcon": "calendar_today",
|
||||
"badgeText": "27 August 2026 | Ho Chi Minh City, Vietnam",
|
||||
"badgeText": "27 August 2026 | Hanoi, Vietnam",
|
||||
"title": "IPv6 - Enhanced for AI & Data Centre Summit 2026",
|
||||
"subtitle": "Unlocking the Potential of Next-Gen Infrastructure. Join global leaders in redefining ASEAN's digital connectivity for the age of AI.",
|
||||
"primaryCta": { "label": "Register", "href": "/registration" },
|
||||
@@ -153,7 +153,8 @@
|
||||
"order": "03",
|
||||
"time": "9.15 am – 9.25 am",
|
||||
"title": "Welcome Address by **Prof Emeritus Dr Sureswaran Ramadass**",
|
||||
"description": "*Chairman, IPv6 Forum Malaysia*\n*Chairman, APAC IPv6 Council*"
|
||||
"description": "*Chairman, IPv6 Forum Malaysia*\n*Chairman, APAC IPv6 Council*",
|
||||
"avatar": "/assets/img/speakers/speaker.png"
|
||||
},
|
||||
{
|
||||
"order": "04",
|
||||
@@ -177,19 +178,22 @@
|
||||
"order": "07",
|
||||
"time": "10.00 am – 10.40 am",
|
||||
"title": "Keynote Address: **\"IPv6 Enhanced, SRv6 & Net5.5G for AI-Native Data Centres\"**",
|
||||
"description": "Speaker: Dr. Will Liu, Huawei, China"
|
||||
"description": "Speaker: Dr. Will Liu, Huawei, China",
|
||||
"avatar": "/assets/img/speakers/placeholder.png"
|
||||
},
|
||||
{
|
||||
"order": "08",
|
||||
"time": "10.40 am – 11.10 am",
|
||||
"title": "**AI, Cybersecurity & Smart Digital Ecosystems**",
|
||||
"description": "Speaker: Prof. Sureswaran Ramadass, Malaysia\nChairman, IPv6 Forum Malaysia"
|
||||
"description": "Speaker: Prof. Sureswaran Ramadass, Malaysia\nChairman, IPv6 Forum Malaysia",
|
||||
"avatar": "/assets/img/speakers/speaker.png"
|
||||
},
|
||||
{
|
||||
"order": "09",
|
||||
"time": "11.10 am – 11.50 am",
|
||||
"title": "**Building AI-Ready Data Centre Infrastructure in ASEAN**",
|
||||
"description": "Speaker: Mr. Bayu Hanantasena, Strategic Advisor to CEO, Indosat, Indonesia"
|
||||
"description": "Speaker: Mr. Bayu Hanantasena, Strategic Advisor to CEO, Indosat, Indonesia",
|
||||
"avatar": "/assets/img/speakers/placeholder.png"
|
||||
},
|
||||
{
|
||||
"order": "10",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"hero": {
|
||||
"badgeIcon": "calendar_today",
|
||||
"badgeText": "27 Tháng 8/2026 | TP. Hồ Chí Minh, Việt Nam",
|
||||
"badgeText": "27 Tháng 8/2026 | Hà Nội, Việt Nam",
|
||||
"title": "IPv6 - Enhanced for AI & Data Centre Summit 2026",
|
||||
"subtitle": "Khám phá tiềm năng Hạ tầng thế hệ mới. Chung sức định hình kỷ nguyên kết nối số tại ASEAN cùng doanh nghiệp hàng đầu quốc tế.",
|
||||
"primaryCta": { "label": "Đăng Ký", "href": "/registration" },
|
||||
@@ -153,7 +153,8 @@
|
||||
"order": "03",
|
||||
"time": "9.15 am – 9.25 am",
|
||||
"title": "Phát biểu chào mừng bởi **Prof Emeritus Dr Sureswaran Ramadass**",
|
||||
"description": "*Chairman, IPv6 Forum Malaysia*\n*Chairman, APAC IPv6 Council*"
|
||||
"description": "*Chairman, IPv6 Forum Malaysia*\n*Chairman, APAC IPv6 Council*",
|
||||
"avatar": "/assets/img/speakers/speaker.png"
|
||||
},
|
||||
{
|
||||
"order": "04",
|
||||
@@ -177,19 +178,22 @@
|
||||
"order": "07",
|
||||
"time": "10.00 am – 10.40 am",
|
||||
"title": "Bài phát biểu Keynote: **\"Tối ưu hóa IPv6, SRv6 & Net5.5G cho Trung tâm Dữ liệu tích hợp AI\"**",
|
||||
"description": "Speaker: Dr. Will Liu, Huawei, China"
|
||||
"description": "Speaker: Dr. Will Liu, Huawei, China",
|
||||
"avatar": "/assets/img/speakers/placeholder.png"
|
||||
},
|
||||
{
|
||||
"order": "08",
|
||||
"time": "10.40 am – 11.10 am",
|
||||
"title": "**AI, An ninh mạng & Hệ sinh thái số thông minh**",
|
||||
"description": "Speaker: Prof. Sureswaran Ramadass, Malaysia\nChairman, IPv6 Forum Malaysia"
|
||||
"description": "Speaker: Prof. Sureswaran Ramadass, Malaysia\nChairman, IPv6 Forum Malaysia",
|
||||
"avatar": "/assets/img/speakers/speaker.png"
|
||||
},
|
||||
{
|
||||
"order": "09",
|
||||
"time": "11.10 am – 11.50 am",
|
||||
"title": "**Xây dựng hạ tầng Trung tâm dữ liệu sẵn sàng cho AI tại ASEAN**",
|
||||
"description": "Speaker: Mr. Bayu Hanantasena, Strategic Advisor to CEO, Indosat, Indonesia"
|
||||
"description": "Speaker: Mr. Bayu Hanantasena, Strategic Advisor to CEO, Indosat, Indonesia",
|
||||
"avatar": "/assets/img/speakers/placeholder.png"
|
||||
},
|
||||
{
|
||||
"order": "10",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"hero": {
|
||||
"eyebrow": "OPPORTUNITY AWAITS",
|
||||
"title": "Become a Sponsor",
|
||||
"subtitle": "IPv6 - Enhanced AI & Data Centre Summit 2026 — 27 August 2026, Ho Chi Minh City",
|
||||
"subtitle": "IPv6 - Enhanced AI & Data Centre Summit 2026 — 27 August 2026, Hanoi",
|
||||
"description": "Join industry leaders at the forefront of the technological evolution. We invite innovative companies to co-sponsor an elite gathering focusing on AI, IPv6, Cloud Computing, Cybersecurity, Blockchain, and Data Centres. Align your brand with the architects of tomorrow's infrastructure.",
|
||||
"primaryCta": { "label": "Download Prospectus", "href": "#" },
|
||||
"secondaryCta": { "label": "Speak to an Agent", "href": "#contact" }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"hero": {
|
||||
"eyebrow": "CƠ HỘI ĐANG CHỜ",
|
||||
"title": "Trở Thành Nhà Tài Trợ",
|
||||
"subtitle": "Hội Nghị IPv6 cho AI & Trung Tâm Dữ Liệu 2026 — 27 Tháng 8 năm 2026, TP. Hồ Chí Minh",
|
||||
"subtitle": "Hội Nghị IPv6 cho AI & Trung Tâm Dữ Liệu 2026 — 27 Tháng 8 năm 2026, Hà Nội",
|
||||
"description": "Cùng các nhà lãnh đạo ngành ở tuyến đầu tiến hóa công nghệ. Chúng tôi mời các công ty đổi mới đồng tài trợ cho sự kiện đẳng cấp tập trung vào AI, IPv6, Điện Toán Đám Mây, An Ninh Mạng, Blockchain và Trung Tâm Dữ Liệu. Kết nối thương hiệu của bạn với những kiến trúc sư của hạ tầng ngày mai.",
|
||||
"primaryCta": { "label": "Tải Hồ Sơ Tài Trợ", "href": "#" },
|
||||
"secondaryCta": { "label": "Liên Hệ Chuyên Viên", "href": "#contact" }
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 556 B |
Binary file not shown.
|
After Width: | Height: | Size: 578 B |
@@ -0,0 +1,50 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import axios from 'axios';
|
||||
|
||||
async function downloadQR(url: string, outputPath: string) {
|
||||
const qrApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=${encodeURIComponent(url)}`;
|
||||
const response = await axios({
|
||||
url: qrApiUrl,
|
||||
method: 'GET',
|
||||
responseType: 'stream',
|
||||
});
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const writer = fs.createWriteStream(outputPath);
|
||||
response.data.pipe(writer);
|
||||
writer.on('finish', () => resolve());
|
||||
writer.on('error', (err) => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const localUrl = 'http://localhost:3000/ipv6/feedback';
|
||||
const prodUrl = 'https://techvanguard.vn/ipv6/feedback';
|
||||
|
||||
const publicDir = path.join(__dirname, '../public/assets/img');
|
||||
if (!fs.existsSync(publicDir)) {
|
||||
fs.mkdirSync(publicDir, { recursive: true });
|
||||
}
|
||||
|
||||
const localPath = path.join(publicDir, 'feedback-qr-local.png');
|
||||
const prodPath = path.join(publicDir, 'feedback-qr-prod.png');
|
||||
|
||||
console.log('Downloading QR code for local URL:', localUrl);
|
||||
await downloadQR(localUrl, localPath);
|
||||
console.log('Saved local QR to:', localPath);
|
||||
|
||||
console.log('Downloading QR code for prod URL:', prodUrl);
|
||||
await downloadQR(prodUrl, prodPath);
|
||||
console.log('Saved prod QR to:', prodPath);
|
||||
|
||||
// Copy to artifact directory
|
||||
const artifactDir = 'C:\\Users\\Admin\\.gemini\\antigravity-ide\\brain\\c96f6734-1739-4dd2-b415-68dac04243f7';
|
||||
if (fs.existsSync(artifactDir)) {
|
||||
fs.copyFileSync(localPath, path.join(artifactDir, 'feedback-qr-local.png'));
|
||||
fs.copyFileSync(prodPath, path.join(artifactDir, 'feedback-qr-prod.png'));
|
||||
console.log('Copied QR codes to artifact directory.');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
Reference in New Issue
Block a user