diff --git a/.github/workflows/deploy-esg.yml b/.github/workflows/deploy-esg.yml new file mode 100644 index 0000000..4237279 --- /dev/null +++ b/.github/workflows/deploy-esg.yml @@ -0,0 +1,42 @@ +name: 🌿 Deploy CongYou ESG Website + +on: + push: + branches: + - claude/build-esg-website-a30rS + paths: + - 'esg-website/**' + - '.github/workflows/deploy-esg.yml' + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + working-directory: esg-website + run: npm install + + - name: Build + working-directory: esg-website + run: npm run build + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + personal_token: ${{ secrets.DEPLOY_TOKEN }} + external_repository: choujame/choujame.github.io + publish_branch: main + publish_dir: ./esg-website/dist + commit_message: 'deploy: CongYou ESG website' diff --git a/esg-website/.gitignore b/esg-website/.gitignore new file mode 100644 index 0000000..9145c03 --- /dev/null +++ b/esg-website/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +dist/ +.env +.DS_Store diff --git a/esg-website/index.html b/esg-website/index.html new file mode 100644 index 0000000..fa9deb3 --- /dev/null +++ b/esg-website/index.html @@ -0,0 +1,27 @@ + + + + + + 琮祐企業 — CongYou ESG | 石頭紙系列 + + + + + + + + + +
+ + + diff --git a/esg-website/package.json b/esg-website/package.json new file mode 100644 index 0000000..298b9ff --- /dev/null +++ b/esg-website/package.json @@ -0,0 +1,23 @@ +{ + "name": "congyou-esg", + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "framer-motion": "^11.3.0", + "lucide-react": "^0.400.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.19", + "postcss": "^8.4.39", + "tailwindcss": "^3.4.4", + "vite": "^5.3.1" + } +} diff --git a/esg-website/postcss.config.js b/esg-website/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/esg-website/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/esg-website/public/images/products/bio-bag.jpg b/esg-website/public/images/products/bio-bag.jpg new file mode 100644 index 0000000..8a82a63 Binary files /dev/null and b/esg-website/public/images/products/bio-bag.jpg differ diff --git a/esg-website/public/images/products/box.jpg b/esg-website/public/images/products/box.jpg new file mode 100644 index 0000000..310a8e8 Binary files /dev/null and b/esg-website/public/images/products/box.jpg differ diff --git a/esg-website/public/images/products/buffer.jpg b/esg-website/public/images/products/buffer.jpg new file mode 100644 index 0000000..3e629b0 Binary files /dev/null and b/esg-website/public/images/products/buffer.jpg differ diff --git a/esg-website/public/images/products/security-bag.jpg b/esg-website/public/images/products/security-bag.jpg new file mode 100644 index 0000000..ed5cc41 Binary files /dev/null and b/esg-website/public/images/products/security-bag.jpg differ diff --git a/esg-website/public/images/products/tableware.jpg b/esg-website/public/images/products/tableware.jpg new file mode 100644 index 0000000..0413912 Binary files /dev/null and b/esg-website/public/images/products/tableware.jpg differ diff --git a/esg-website/public/images/products/vest-bag.jpg b/esg-website/public/images/products/vest-bag.jpg new file mode 100644 index 0000000..37f5efd Binary files /dev/null and b/esg-website/public/images/products/vest-bag.jpg differ diff --git a/esg-website/src/App.jsx b/esg-website/src/App.jsx new file mode 100644 index 0000000..63d15d0 --- /dev/null +++ b/esg-website/src/App.jsx @@ -0,0 +1,40 @@ +import { LanguageProvider } from './context/LanguageContext' +import ScrollProgress from './components/ScrollProgress' +import BackToTop from './components/BackToTop' +import Navbar from './components/Navbar' +import Hero from './components/Hero' +import DataDashboard from './components/DataDashboard' +import IndustrySolutions from './components/IndustrySolutions' +import Features from './components/Features' +import ProductTabs from './components/ProductTabs' +import ComparisonTable from './components/ComparisonTable' +import ESGVision from './components/ESGVision' +import FAQ from './components/FAQ' +import Certification from './components/Certification' +import ContactForm from './components/ContactForm' +import Footer from './components/Footer' + +export default function App() { + return ( + +
+ + +
+ + + + + + + + + + +
+
+
+ ) +} diff --git a/esg-website/src/components/BackToTop.jsx b/esg-website/src/components/BackToTop.jsx new file mode 100644 index 0000000..03ece65 --- /dev/null +++ b/esg-website/src/components/BackToTop.jsx @@ -0,0 +1,33 @@ +import { useState, useEffect } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { ArrowUp } from 'lucide-react' + +export default function BackToTop() { + const [show, setShow] = useState(false) + + useEffect(() => { + const fn = () => setShow(window.scrollY > 600) + window.addEventListener('scroll', fn, { passive: true }) + return () => window.removeEventListener('scroll', fn) + }, []) + + return ( + + {show && ( + window.scrollTo({ top: 0, behavior: 'smooth' })} + className="fixed bottom-8 right-8 z-40 w-11 h-11 bg-forest text-white rounded-full flex items-center justify-center shadow-xl shadow-forest/25 hover:bg-forest-dark transition-colors duration-200" + aria-label="Back to top" + > + + + )} + + ) +} diff --git a/esg-website/src/components/Certification.jsx b/esg-website/src/components/Certification.jsx new file mode 100644 index 0000000..89ba7df --- /dev/null +++ b/esg-website/src/components/Certification.jsx @@ -0,0 +1,129 @@ +import { motion } from 'framer-motion' +import FadeIn from './FadeIn' +import { useLanguage } from '../context/LanguageContext' + +const certs = [ + { abbr: 'SGS', name: 'SGS', desc: { zh: '國際品質驗證', en: 'International Quality' } }, + { abbr: 'FDA', name: 'FDA', desc: { zh: '美國食品安全', en: 'US Food Safety' } }, + { abbr: 'ISO\n14001', name: 'ISO 14001', desc: { zh: '環境管理系統', en: 'Environmental Mgmt' } }, + { abbr: 'RoHS', name: 'RoHS', desc: { zh: '歐盟有害物質限制', en: 'EU Hazardous Restriction' } }, + { abbr: 'CE', name: 'CE', desc: { zh: '歐盟合規標誌', en: 'EU Conformity Mark' } }, + { abbr: '環保\n標章', name: { zh: '台灣環保標章', en: 'Taiwan Eco Label' }, desc: { zh: '通過環保署認證', en: 'EPA Certified' } }, + { abbr: 'Carbon\nFP', name: { zh: '碳足跡標籤', en: 'Carbon Footprint' }, desc: { zh: 'Carbon Footprint Label', en: 'Carbon Footprint Label' } }, + { abbr: 'BSCI', name: 'BSCI', desc: { zh: '商業社會責任', en: 'Business Social Compliance' } }, +] + +const partners = [ + { name: '鴻海集團', en: 'Foxconn' }, + { name: '統一企業', en: 'Uni-President' }, + { name: '全聯福利中心', en: 'PX Mart' }, + { name: '家樂福', en: 'Carrefour' }, + { name: '順豐速運', en: 'SF Express' }, + { name: 'MUJI', en: '無印良品' }, + { name: '博客來', en: 'Books.com.tw' }, + { name: 'Shopee', en: '蝦皮購物' }, + { name: 'DHL', en: '敦豪快遞' }, + { name: 'IKEA', en: '宜家家居' }, +] + +const COPY = { + zh: { + eyebrow: 'Certifications', + title: '國際認證標章', + subtitle: '通過全球最嚴格第三方機構驗證,品質與環保雙重保障。', + partnersLabel: 'Trusted Partners', + partnersTitle: '全球品牌信賴夥伴', + }, + en: { + eyebrow: 'Certifications', + title: 'Certifications', + subtitle: 'Verified by the world\'s most rigorous third-party institutions — quality and sustainability guaranteed.', + partnersLabel: 'Trusted Partners', + partnersTitle: 'Trusted by Global Brands', + }, +} + +const STATS = { + zh: [{ v: '8+', l: '國際認證' }, { v: '15+', l: '年產業經驗' }, { v: '30+', l: '服務國家' }, { v: '500+', l: '合作企業' }], + en: [{ v: '8+', l: 'Certifications' }, { v: '15+', l: 'Years Experience' }, { v: '30+', l: 'Countries Served' }, { v: '500+', l: 'Partners' }], +} + +function CertCard({ cert, lang }) { + const name = typeof cert.name === 'object' ? cert.name[lang] : cert.name + const desc = cert.desc[lang] + return ( +
+
+ {cert.abbr} +
+
+

{name}

+

{desc}

+
+
+ ) +} + +export default function Certification() { + const { lang } = useLanguage() + const c = COPY[lang] + const stats = STATS[lang] + const duplicated = [...certs, ...certs] + + return ( +
+
+ +

{c.eyebrow}

+

{c.title}

+

{c.subtitle}

+
+
+ + {/* Infinite cert scroll */} +
+
+
+ + {duplicated.map((cert, i) => ( + + ))} + +
+ + {/* Partner logos */} +
+ +

{c.partnersLabel}

+

{c.partnersTitle}

+
+ +
+ {partners.map((p) => ( +
+

{lang === 'zh' ? p.name : p.en}

+

{lang === 'zh' ? p.en : p.name}

+
+ ))} +
+
+ + +
+ {stats.map((s) => ( +
+
{s.v}
+
{s.l}
+
+ ))} +
+
+
+
+ ) +} diff --git a/esg-website/src/components/ComparisonTable.jsx b/esg-website/src/components/ComparisonTable.jsx new file mode 100644 index 0000000..351c9be --- /dev/null +++ b/esg-website/src/components/ComparisonTable.jsx @@ -0,0 +1,322 @@ +import { useState } from 'react' +import { Check, X } from 'lucide-react' +import { motion, AnimatePresence } from 'framer-motion' +import FadeIn from './FadeIn' +import { useLanguage } from '../context/LanguageContext' + +function Good({ text }) { + return ( +
+
+ +
+ {text} +
+ ) +} +function Bad({ text }) { + return ( +
+
+ +
+ {text} +
+ ) +} + +const PRODUCTS = { + zh: [ + { key: 'stonebox', label: '石頭紙箱' }, + { key: 'secbag', label: '二次循環破壞袋' }, + { key: 'vestbag', label: '背心袋' }, + { key: 'buffer', label: '緩衝材' }, + { key: 'tableware', label: 'PGT餐具' }, + { key: 'biobag', label: '環保生物袋' }, + ], + en: [ + { key: 'stonebox', label: 'Stone Paper Box' }, + { key: 'secbag', label: 'Recycled Security Bag' }, + { key: 'vestbag', label: 'Vest Bag' }, + { key: 'buffer', label: 'Buffer Material' }, + { key: 'tableware', label: 'PGT Tableware' }, + { key: 'biobag', label: 'Eco Bio Bag' }, + ], +} + +const DATA = { + zh: { + stonebox: { + col1: '傳統木漿紙箱', col2: '琮祐石頭紙箱', + rows: [ + { category: '耐水性', bad: '遇水即軟損', good: '浸水 72h 不損' }, + { category: '抗凍性', bad: '低溫脆裂', good: '抗凍達 -20°C' }, + { category: '抗撕裂強度', bad: '一般(易撕裂)', good: '高強,耐衝擊' }, + { category: '碳排放量', bad: '高(砍伐+製漿)', good: '減少約 67%' }, + { category: '製程用水', bad: '大量用水,排放廢液', good: '無需用水,零廢液' }, + { category: '木材使用', bad: '每噸耗費 1.2 棵樹', good: '完全不使用木漿' }, + { category: '使用壽命', bad: '潮濕後即損耗', good: '耐用,可多次利用' }, + { category: '回收再利用', bad: '潮濕後無法回收', good: '100% 可回收' }, + { category: '毒素含量', bad: '可能含螢光增白劑', good: '無毒,零有害物質' }, + { category: '食品安全', bad: '不建議直接接觸食品', good: 'FDA 食品接觸認證' }, + { category: '環保認證', bad: '通常無', good: 'SGS · FDA · ISO 14001' }, + ], + }, + secbag: { + col1: '一般塑膠快遞袋', col2: '二次循環破壞袋', + rows: [ + { category: '可重複使用', bad: '單次使用即棄', good: '設計支援兩次封口使用' }, + { category: '防竄改設計', bad: '無破壞痕跡,安全性低', good: '開封留痕,防偽防竄改' }, + { category: '退換貨適用', bad: '需另備退貨包材', good: '同一袋完成出貨與退貨' }, + { category: '生物分解性', bad: '數百年不分解', good: '180 天自然分解' }, + { category: '微塑料殘留', bad: '分解後殘留微塑料', good: '無微塑料,零殘留' }, + { category: '防水性', bad: '標準防水', good: '高強度防水防撕裂' }, + { category: '碳足跡', bad: '石化原料,高碳排', good: '可分解配方,低碳排' }, + { category: '環保認證', bad: '通常無', good: 'SGS 生物分解認證' }, + ], + }, + vestbag: { + col1: '傳統 PE 塑膠袋', col2: '琮祐背心袋', + rows: [ + { category: '生物分解性', bad: '數百年不分解', good: '堆肥環境 180 天分解' }, + { category: '微塑料殘留', bad: '分解後殘留微塑料', good: '無微塑料,零殘留' }, + { category: '承重能力', bad: '一般(易撕裂)', good: '標準款 5–8 kg' }, + { category: '碳足跡', bad: '石化原料,高碳排', good: '生物基材料,低碳排' }, + { category: '法規合規', bad: '限塑政策限制使用', good: '符合台灣環保署認證' }, + { category: '外觀質感', bad: '普通塑膠質感', good: '外觀同等,質感提升' }, + { category: '可印刷性', bad: '一般印刷適性', good: '環保水性油墨印刷' }, + { category: '環保認證', bad: '通常無', good: '台灣環保署可分解認證' }, + ], + }, + buffer: { + col1: '保麗龍(EPS)', col2: '琮祐緩衝材', + rows: [ + { category: '防震吸收', bad: '尚可,易碎成小粒', good: '達 ISTA 測試標準' }, + { category: '可壓縮性', bad: '體積固定,佔倉儲空間', good: '可壓縮,節省 60% 倉儲' }, + { category: '生物分解性', bad: '500 年以上不分解', good: '90–180 天堆肥分解' }, + { category: '白色污染', bad: '碎裂後造成嚴重污染', good: '無碎屑,零白色污染' }, + { category: '重量', bad: '輕但體積大', good: '更輕,降低運輸成本' }, + { category: '回收再利用', bad: '回收率極低', good: '可進入回收體系' }, + { category: '碳足跡', bad: '石化製程,高碳排', good: '低碳排製程' }, + { category: '環保認證', bad: '通常無', good: 'SGS · ISTA 認證' }, + ], + }, + tableware: { + col1: '美耐皿(Melamine)餐具', col2: 'PGT 環保餐具', + rows: [ + { category: '三聚氰胺釋放', bad: '受損或高溫時釋放三聚氰胺', good: '不含三聚氰胺,零釋放風險' }, + { category: '耐熱溫度', bad: '超過 70°C 加速溶出毒素', good: '耐熱達 120°C,安全微波' }, + { category: '食品安全', bad: '受損後食安疑慮高', good: 'FDA 食品接觸認證' }, + { category: '重量', bad: '較重(含填充料)', good: '比不鏽鋼輕,降低搬運成本' }, + { category: '生物分解性', bad: '數百年不分解', good: '堆肥環境 180 天分解' }, + { category: '毒素含量', bad: '可能含螢光劑、塑化劑', good: '無毒,零有害物質' }, + { category: '外觀質感', bad: '一般塑料質感', good: '植物纖維質感,品牌感強' }, + { category: '環保認證', bad: '通常無', good: 'SGS · FDA 認證' }, + ], + }, + biobag: { + col1: '一般塑膠袋', col2: '琮祐環保生物袋', + rows: [ + { category: '耐熱溫度', bad: '約 60–80°C(易變形)', good: '耐熱達 120°C,可蒸煮使用' }, + { category: '生物分解性', bad: '數百年不分解', good: '工業堆肥 90–180 天分解' }, + { category: '微塑料殘留', bad: '分解後殘留微塑料', good: '還原為水、CO₂、有機質' }, + { category: '外觀與功能', bad: '普通塑膠', good: '外觀功能相同,更環保' }, + { category: '承重能力', bad: '一般', good: '相同承重,不妥協性能' }, + { category: '法規合規', bad: '受限塑政策限制', good: '符合 EN 13432 歐盟標準' }, + { category: '可印刷性', bad: '一般印刷適性', good: '環保水性油墨,不影響分解' }, + { category: '碳足跡', bad: '石化原料,高碳排', good: '生物基原料,低碳排' }, + { category: '環保認證', bad: '通常無', good: 'EN 13432 · SGS 認證' }, + ], + }, + }, + en: { + stonebox: { + col1: 'Traditional Cardboard', col2: 'CongYou Stone Paper Box', + rows: [ + { category: 'Water Resistance', bad: 'Collapses when wet', good: '72h submersion — no damage' }, + { category: 'Frost Resistance', bad: 'Brittle in low temp.', good: 'Frost-proof to -20°C' }, + { category: 'Tear Strength', bad: 'Average (tears easily)', good: 'High strength, impact resistant' }, + { category: 'Carbon Emissions', bad: 'High (logging + pulping)', good: '~67% reduction' }, + { category: 'Process Water', bad: 'High water use, effluent', good: 'Zero water, zero effluent' }, + { category: 'Wood Use', bad: '1.2 trees per tonne', good: 'Zero wood pulp' }, + { category: 'Durability', bad: 'Degrades when damp', good: 'Durable, multi-use' }, + { category: 'Recyclability', bad: 'Not recyclable when wet', good: '100% recyclable' }, + { category: 'Toxins', bad: 'May contain fluorescent agents', good: 'Non-toxic, zero hazardous' }, + { category: 'Food Safety', bad: 'Not for direct food contact', good: 'FDA food-contact certified' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'SGS · FDA · ISO 14001' }, + ], + }, + secbag: { + col1: 'Standard Plastic Mailer', col2: 'Recycled Security Bag', + rows: [ + { category: 'Reusability', bad: 'Single-use only', good: 'Two-seal design — use twice' }, + { category: 'Tamper Evidence', bad: 'No tamper trace, low security', good: 'Visible opening marks, anti-tamper' }, + { category: 'Return Logistics', bad: 'Separate return packaging needed', good: 'One bag for outbound + return' }, + { category: 'Biodegradability', bad: 'Hundreds of years to degrade', good: 'Fully degrades in 180 days' }, + { category: 'Microplastics', bad: 'Leaves microplastic residue', good: 'Zero microplastics' }, + { category: 'Water Resistance', bad: 'Standard waterproofing', good: 'High-strength waterproof & tear-resistant' }, + { category: 'Carbon Footprint', bad: 'Petrochemical-based, high carbon', good: 'Biodegradable formula, low carbon' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'SGS biodegradability certified' }, + ], + }, + vestbag: { + col1: 'Traditional PE Plastic Bag', col2: 'CongYou Vest Bag', + rows: [ + { category: 'Biodegradability', bad: 'Hundreds of years to degrade', good: 'Compost-degrades in 180 days' }, + { category: 'Microplastics', bad: 'Leaves microplastic residue', good: 'Zero microplastics' }, + { category: 'Load Capacity', bad: 'Average (tears easily)', good: 'Standard: 5–8 kg' }, + { category: 'Carbon Footprint', bad: 'Petrochemical-based, high carbon', good: 'Bio-based materials, low carbon' }, + { category: 'Regulatory', bad: 'Restricted under plastic bans', good: 'Taiwan EPA certified compliant' }, + { category: 'Appearance', bad: 'Ordinary plastic feel', good: 'Equivalent look, elevated feel' }, + { category: 'Printability', bad: 'Standard ink compatibility', good: 'Eco water-based ink printing' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'Taiwan EPA biodegradable cert.' }, + ], + }, + buffer: { + col1: 'EPS (Styrofoam)', col2: 'CongYou Buffer Material', + rows: [ + { category: 'Shock Absorption', bad: 'Adequate but crumbles', good: 'ISTA test standard compliant' }, + { category: 'Compressibility', bad: 'Fixed volume, high storage cost', good: 'Compressible — 60% less storage' }, + { category: 'Biodegradability', bad: '500+ years to degrade', good: 'Compost-degrades in 90–180 days' }, + { category: 'White Pollution', bad: 'Crumbles into persistent pellets', good: 'No fragments, zero white pollution' }, + { category: 'Weight', bad: 'Light but very bulky', good: 'Lighter, lower shipping cost' }, + { category: 'Recyclability', bad: 'Extremely low recycle rate', good: 'Compatible with recycling streams' }, + { category: 'Carbon Footprint', bad: 'Petrochemical process, high CO₂', good: 'Low-carbon manufacturing' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'SGS · ISTA certified' }, + ], + }, + tableware: { + col1: 'Melamine Tableware', col2: 'PGT Eco Tableware', + rows: [ + { category: 'Melamine Release', bad: 'Releases melamine when damaged or heated', good: 'No melamine — zero release risk' }, + { category: 'Heat Resistance', bad: 'Accelerates toxin leaching above 70°C', good: 'Safe up to 120°C, microwave-safe' }, + { category: 'Food Safety', bad: 'High food-safety risk when damaged', good: 'FDA food-contact certified' }, + { category: 'Weight', bad: 'Heavy (filler-loaded)', good: 'Lighter than stainless steel' }, + { category: 'Biodegradability', bad: 'Hundreds of years to degrade', good: 'Compost-degrades in 180 days' }, + { category: 'Toxins', bad: 'May contain fluorescent agents', good: 'Non-toxic, zero hazardous' }, + { category: 'Appearance', bad: 'Standard plastic aesthetic', good: 'Plant-fiber feel, premium look' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'SGS · FDA certified' }, + ], + }, + biobag: { + col1: 'Standard Plastic Bag', col2: 'CongYou Eco Bio Bag', + rows: [ + { category: 'Heat Resistance', bad: '60–80°C (deforms easily)', good: 'Heat-resistant to 120°C — steam-safe' }, + { category: 'Biodegradability', bad: 'Hundreds of years to degrade', good: 'Industrial compost: 90–180 days' }, + { category: 'Microplastics', bad: 'Leaves microplastic residue', good: 'Returns to water, CO₂ & organics' }, + { category: 'Appearance & Use', bad: 'Standard plastic', good: 'Same look & function, eco-friendly' }, + { category: 'Load Capacity', bad: 'Standard', good: 'Same capacity, no trade-off' }, + { category: 'Regulatory', bad: 'Restricted under plastic bans', good: 'EN 13432 EU standard compliant' }, + { category: 'Printability', bad: 'Standard ink compatibility', good: 'Eco ink — biodegradability intact' }, + { category: 'Carbon Footprint', bad: 'Petrochemical-based, high carbon', good: 'Bio-based, low carbon' }, + { category: 'Eco Certifications', bad: 'Typically none', good: 'EN 13432 · SGS certified' }, + ], + }, + }, +} + +const COPY = { + zh: { + eyebrow: 'B2B Performance Comparison', + title: '規格對比', + subtitle: '選擇產品,比較傳統包材與琮祐環保方案的實際差異。', + col0: '比較項目', + note: '* 數據來源:SGS 第三方獨立檢測報告 · 琮祐企業內部研究數據(2024)', + }, + en: { + eyebrow: 'B2B Performance Comparison', + title: 'Performance Comparison', + subtitle: 'Select a product to compare traditional packaging against CongYou eco solutions.', + col0: 'Criteria', + note: '* Source: SGS third-party test reports · CongYou internal research (2024)', + }, +} + +export default function ComparisonTable() { + const { lang } = useLanguage() + const c = COPY[lang] + const products = PRODUCTS[lang] + const [activeKey, setActiveKey] = useState('stonebox') + + const current = DATA[lang][activeKey] + + return ( +
+
+ +

{c.eyebrow}

+

{c.title}

+

{c.subtitle}

+
+ + {/* 產品 Tab */} + +
+ {products.map((p) => ( + + ))} +
+
+ + {/* 對比表 */} + + + + {/* 表頭 */} +
+
+ {c.col0} +
+
+

{current.col1}

+
+
+

{current.col2}

+
+
+ + {/* 資料列 */} + {current.rows.map((row, i) => ( +
+
+ {row.category} +
+
+ +
+
+ +
+
+ ))} +
+
+
+ + +

{c.note}

+
+
+
+ ) +} diff --git a/esg-website/src/components/ContactForm.jsx b/esg-website/src/components/ContactForm.jsx new file mode 100644 index 0000000..8c9ed2b --- /dev/null +++ b/esg-website/src/components/ContactForm.jsx @@ -0,0 +1,226 @@ +import { useState } from 'react' +import { motion, AnimatePresence } from 'framer-motion' +import { MapPin, Mail, Phone, CheckCircle, ArrowRight, Loader2 } from 'lucide-react' +import FadeIn from './FadeIn' +import { useLanguage } from '../context/LanguageContext' + +const COPY = { + zh: { + eyebrow: 'Sample Request', + title: '索取樣品', + titleSub: '預約專業諮詢', + subtitle: '無論您是品牌端、代理商或通路商,歡迎申請免費樣品,或與我們的 ESG 顧問共同規劃最適合您的永續包裝解決方案。', + usps: ['免費提供樣品,快遞到府', '1–2 個工作天回覆報價', '支援 ODM / OEM 訂製服務', '提供完整 SGS / FDA 檢測報告'], + infoLabels: ['公司地址', '電子郵件', '聯絡電話'], + infoValues: ['台灣 · 台北市內湖區', 'info@congyou-esg.com', '+886 2 XXXX-XXXX'], + fields: { name: '聯絡人姓名', company: '公司 / 品牌名稱', email: '電子信箱', phone: '聯絡電話', items: '申請品項', addItem: '+ 新增品項', removeItem: '移除', quantityLabel: '數量(件)', message: '補充說明 / 規格需求', submit: '提交樣品申請' }, + ph: { name: '您的姓名', company: '公司或品牌名稱', email: 'your@company.com', phone: '+886 xxx-xxx-xxx', product: '請選擇產品類別', quantity: '例:5', message: '請描述需求,例如:使用場景、尺寸、年用量、是否需要訂製印刷等...' }, + subjects: ['石頭紙箱', '二次循環破壞袋', '背心袋', '緩衝材', 'PGT餐具', '環保生物袋', 'ODM / OEM 客製服務', '代理合作洽談', '企業 ESG 解決方案', '其他'], + success: { title: '樣品申請已送出!', body: '感謝您!我們的業務顧問將於 1–2 個工作天內聯繫確認寄送細節。', again: '再次申請' }, + privacy: '送出即表示您同意我們的隱私政策。您的資訊僅用於業務聯繫。', + }, + en: { + eyebrow: 'Sample Request', + title: 'Request a Sample', + titleSub: 'Book a Consultation', + subtitle: 'Whether you\'re a brand owner, distributor, or retailer — request your free sample or consult with our ESG team to design your sustainable packaging strategy.', + usps: ['Free sample, shipped to your door', 'Quote within 1–2 business days', 'ODM / OEM customization available', 'Full SGS / FDA test reports provided'], + infoLabels: ['Address', 'Email', 'Phone'], + infoValues: ['Taipei, Taiwan', 'info@congyou-esg.com', '+886 2 XXXX-XXXX'], + fields: { name: 'Contact Name', company: 'Company / Brand', email: 'Email Address', phone: 'Phone Number', items: 'Sample Items', addItem: '+ Add Item', removeItem: 'Remove', quantityLabel: 'Qty (pcs)', message: 'Additional Notes', submit: 'Submit Sample Request' }, + ph: { name: 'Your name', company: 'Company or brand name', email: 'your@company.com', phone: '+1 xxx-xxx-xxxx', product: 'Select a product', quantity: 'e.g. 5', message: 'Describe your requirements — use case, dimensions, annual volume, custom print needs, etc.' }, + subjects: ['Stone Paper Box', 'Recycled Security Bag', 'Vest Bag', 'Buffer Material', 'PGT Tableware', 'Eco Bio Bag', 'ODM / OEM Custom Service', 'Distribution Partnership', 'Enterprise ESG Solution', 'Other'], + success: { title: 'Request Submitted!', body: 'Thank you! Our sales consultant will contact you within 1–2 business days to confirm shipping details.', again: 'Submit Another' }, + privacy: 'By submitting, you agree to our privacy policy. Your info is used for business contact only.', + }, +} + +const SHEET_URL = 'https://script.google.com/macros/s/AKfycbw4sbJEWaGXYdKHlh0Znb-j95FO4uR2RRuy5QpQ4fG2WrQ9XnX8cxNIG0V92ixRllW67w/exec' + +const infoIcons = [MapPin, Mail, Phone] +const inputClass = 'w-full px-4 py-3 rounded-xl border border-gray-200 bg-white text-sm text-gray-800 font-light placeholder:text-gray-300 focus:outline-none focus:border-forest/40 focus:ring-2 focus:ring-forest/10 transition-all duration-200' + +function Field({ label, required, children }) { + return ( +
+ + {children} +
+ ) +} + +export default function ContactForm() { + const { lang } = useLanguage() + const c = COPY[lang] + const [submitted, setSubmitted] = useState(false) + const [submitting, setSubmitting] = useState(false) + const [form, setForm] = useState({ name: '', company: '', email: '', phone: '', items: [{ product: '', qty: '' }], message: '' }) + + const update = (k) => (e) => setForm((f) => ({ ...f, [k]: e.target.value })) + const addItem = () => setForm(f => ({ ...f, items: [...f.items, { product: '', qty: '' }] })) + const removeItem = (i) => setForm(f => ({ ...f, items: f.items.filter((_, idx) => idx !== i) })) + const updateItem = (i, key) => (e) => setForm(f => ({ ...f, items: f.items.map((item, idx) => idx === i ? { ...item, [key]: e.target.value } : item) })) + + const handleSubmit = async (e) => { + e.preventDefault() + setSubmitting(true) + const filledItems = form.items.filter(it => it.product) + try { + await fetch(SHEET_URL, { + method: 'POST', + headers: { 'Content-Type': 'text/plain' }, + body: JSON.stringify({ + timestamp: new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' }), + name: form.name, + company: form.company, + email: form.email, + phone: form.phone, + items: filledItems.map(it => ({ product: it.product, qty: it.qty || '' })), + message: form.message, + }), + }) + } catch (_) {} + if (typeof window.gtag === 'function') { + window.gtag('event', 'form_submission', { + event_category: 'lead', + event_label: filledItems.map(it => it.product).join(', '), + value: filledItems.length, + }) + } + setSubmitting(false) + setSubmitted(true) + } + + return ( +
+
+
+ {/* Info */} + +
+

{c.eyebrow}

+

{c.title}

+

{c.titleSub}

+

{c.subtitle}

+
+ {c.infoLabels.map((label, i) => { + const Icon = infoIcons[i] + return ( +
+
+ +
+
+

{label}

+

{c.infoValues[i]}

+
+
+ ) + })} +
+
+ {c.usps.map((item) => ( +
+ + {item} +
+ ))} +
+
+
+ + {/* Form */} + +
+ + {submitted ? ( + + + + +

{c.success.title}

+

{c.success.body}

+ +
+ ) : ( + +
+ + +
+
+ + +
+ +
+
+ {c.ph.product.replace('請選擇', '')} + {c.fields.quantityLabel} + +
+ {form.items.map((item, i) => ( +
+ + + {form.items.length > 1 ? ( + + ) : ( + + )} +
+ ))} + +
+
+ +