add alisurvey main page

This commit is contained in:
hsueh chiahao
2025-09-25 16:20:49 +08:00
parent 7fc028e186
commit 4ee023d68f
29 changed files with 7428 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,25 @@
# Alisurvey
https://www.alicorns.co.jp/alisurvey
## 本地开发
### 环境准备
- 安装 [Node.js](https://nodejs.org/en)
### 操作步骤
- 安装依赖
```sh
npm install
```
- 启动 Dev Server
```sh
npm run dev
```
- 在浏览器访问 http://localhost:3000

View File

@@ -0,0 +1,28 @@
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Alisurvey - 日本企業向けSaaSアンケートツール | アンケート作成・データ分析</title>
<meta name="description" content="Alisurveyは、日本企業のニーズに特化したSaaS型アンケートツールです。コード不要で直感的にアンケートを作成し、データを分析できます。無料で始める。" />
<meta name="keywords" content="アンケート, アンケート作成, アンケートツール, SaaS, データ分析, Alisurvey, 日本語アンケート" />
<meta property="og:title" content="Alisurvey - 日本企業向けSaaSアンケートツール" />
<meta property="og:description" content="コード不要で直感的にアンケートを作成し、データを分析できるSaaSツール" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://example.com" />
<meta property="og:image" content="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Survey%20software%20dashboard%20Japanese%20interface&sign=abf2fd53e3a93d90381b48ce9d773a33" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Alisurvey - 日本企業向けSaaSアンケートツール" />
<meta name="twitter:description" content="コード不要で直感的にアンケートを作成し、データを分析できます" />
<meta name="twitter:image" content="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Survey%20software%20dashboard%20Japanese%20interface&sign=abf2fd53e3a93d90381b48ce9d773a33" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
crossorigin="anonymous"
/>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
{
"name": "project_template_react",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev:client": "vite --host --port 3000",
"dev": "npm run dev:client",
"build:client": "vite build --outDir dist/static",
"build": "rm -rf dist && npm run build:client && cp package.json dist && touch dist/build.flag"
},
"dependencies": {
"clsx": "^2.1.1",
"framer-motion": "^12.9.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^7.3.0",
"recharts": "^2.15.1",
"sonner": "^2.0.2",
"tailwind-merge": "^3.0.2",
"zod": "^3.24.2"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
"tailwindcss": "^3.4.17",
"typescript": "~5.7.2",
"vite": "^6.2.0",
"vite-tsconfig-paths": "^5.1.4"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -0,0 +1,23 @@
import { Routes, Route } from "react-router-dom";
import Home from "@/pages/Home";
import { useState } from "react";
import { AuthContext } from '@/contexts/authContext';
export default function App() {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const logout = () => {
setIsAuthenticated(false);
};
return (
<AuthContext.Provider
value={{ isAuthenticated, setIsAuthenticated, logout }}
>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/other" element={<div className="text-center text-xl">Other Page - Coming Soon</div>} />
</Routes>
</AuthContext.Provider>
);
}

View File

@@ -0,0 +1,66 @@
import { motion } from 'framer-motion';
export default function CTA() {
return (
<section className="py-24 relative overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-blue-600 to-indigo-700 z-0"></div>
<div
className="absolute inset-0 z-10 opacity-10"
style={{
backgroundImage: `radial-gradient(#416DE8 50%, transparent 50%)`,
backgroundSize: `60px 60px`,
}}
></div>
<div className="container mx-auto px-4 md:px-6 relative z-20">
<div className="max-w-3xl mx-auto text-center">
<motion.h2
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-4xl md:text-5xl font-bold text-white mb-6 leading-tight"
>
</motion.h2>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 }}
className="text-xl text-blue-100 mb-10"
>
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="flex flex-col sm:flex-row gap-4 justify-center"
>
<a
href="#signup"
className="px-8 py-5 bg-white text-blue-600 font-bold rounded-xl shadow-xl hover:shadow-2xl transition-all text-center text-lg"
>
<i className="fa-solid fa-arrow-right ml-2"></i>
</a>
<a
href="#demo"
className="px-8 py-5 bg-transparent border-2 border-white text-white font-bold rounded-xl hover:bg-white/10 transition-all flex items-center justify-center gap-2 text-lg"
>
<i className="fa-solid fa-play-circle"></i>
</a>
</motion.div>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.3 }}
className="text-blue-100 text-sm mt-6"
>
</motion.p>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,83 @@
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
// ダミーデータ
const satisfactionData = [
{ name: '非常に満足', value: 35 },
{ name: '満足', value: 40 },
{ name: '普通', value: 15 },
{ name: '不満', value: 7 },
{ name: '非常に不満', value: 3 },
];
const monthlyData = [
{ month: '1月', 回答数: 120 },
{ month: '2月', 回答数: 190 },
{ month: '3月', 回答数: 150 },
{ month: '4月', 回答数: 280 },
{ month: '5月', 回答数: 320 },
{ month: '6月', 回答数: 250 },
];
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042', '#8884d8'];
export default function ChartDemo() {
return (
<section className="py-20 bg-gray-50">
<div className="container mx-auto px-4 md:px-8">
<h2 className="text-3xl font-bold text-center mb-16 text-gray-800"></h2>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
{/* 円グラフ */}
<div className="bg-white p-6 rounded-xl shadow-lg">
<h3 className="text-xl font-semibold mb-6 text-gray-700"></h3>
<div className="h-80">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
<Pie
data={satisfactionData}
cx="50%"
cy="50%"
labelLine={false}
outerRadius={120}
fill="#8884d8"
dataKey="value"
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
>
{satisfactionData.map((entry, index) => (
<Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</div>
</div>
{/* 棒グラフ */}
<div className="bg-white p-6 rounded-xl shadow-lg">
<h3 className="text-xl font-semibold mb-6 text-gray-700"></h3>
<div className="h-80">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={monthlyData}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="month" />
<YAxis />
<Tooltip />
<Legend />
<Bar dataKey="回答数" fill="#8884d8" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
</div>
</div>
<div className="mt-12 text-center">
<p className="text-gray-700 max-w-2xl mx-auto">
PNG画像としてエクスポートすることも可能です
</p>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,9 @@
import { toast } from "sonner";
import { cn } from "@/lib/utils";
// Empty component
export function Empty() {
return (
<div className={cn("flex h-full items-center justify-center")} onClick={() => toast('Coming soon')}>Empty</div>
);
}

View File

@@ -0,0 +1,29 @@
import { cn } from '@/lib/utils';
interface FeatureCardProps {
title: string;
description: string;
icon: string;
imageUrl: string;
}
export default function FeatureCard({ title, description, icon, imageUrl }: FeatureCardProps) {
return (
<div className="bg-white rounded-xl overflow-hidden shadow-md hover:shadow-xl transition-shadow duration-300">
<div className="h-48 overflow-hidden">
<img
src={imageUrl}
alt={title}
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105"
/>
</div>
<div className="p-6">
<div className="w-12 h-12 bg-blue-100 dark:bg-blue-900/30 rounded-2xl flex items-center justify-center mb-4 text-blue-600 dark:text-blue-400 text-2xl">
<i className={cn("fa-solid", icon, "text-blue-600 text-xl")}></i>
</div>
<h3 className="text-xl font-bold text-gray-900 mb-2">{title}</h3>
<p className="text-gray-700">{description}</p>
</div>
</div>
);
}

View File

@@ -0,0 +1,128 @@
import { motion } from 'framer-motion';
import FeatureCard from './FeatureCard';
export default function FeatureSection() {
return (
<section id="details" className="py-20 bg-gray-50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl md:text-4xl font-bold mb-4"></h2>
<p className="text-xl text-gray-600 max-w-3xl mx-auto">
</p>
</div>
{/* 機能詳細1 */}
<div className="flex flex-col md:flex-row items-center mb-20">
<div className="md:w-1/2 mb-10 md:mb-0 md:pr-12">
<h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent"></h3>
<ul className="space-y-4">
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>&</span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>使</span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>20</span>
</li>
</ul>
</div>
<div className="md:w-1/2">
<div className="bg-white p-4 rounded-xl shadow-xl">
<img
src="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Drag%20and%20drop%20questionnaire%20builder%20interface%20with%20various%20components%20modern%20UI&sign=7476f5a0f4db10309b9e34d74bff863b"
alt="ドラッグ&ドロップアンケート作成"
className="rounded-lg w-full h-auto"
/>
</div>
</div>
</div>
{/* 機能詳細2 */}
<div className="flex flex-col md:flex-row-reverse items-center mb-20">
<div className="md:w-1/2 mb-10 md:mb-0 md:pl-12">
<h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent"></h3>
<ul className="space-y-4">
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>IPアドレスによるアクセス制限</span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
</ul>
</div>
<div className="md:w-1/2">
<div className="bg-white p-4 rounded-xl shadow-xl">
<img
src="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Access%20control%20settings%20interface%20for%20questionnaire%20security&sign=1bd9e6e769ebe1e36a8f9409e42a79de"
alt="アクセス制限設定"
className="rounded-lg w-full h-auto"
/>
</div>
</div>
</div>
{/* 機能詳細3 */}
<div className="flex flex-col md:flex-row items-center">
<div className="md:w-1/2 mb-10 md:mb-0 md:pr-12">
<h3 className="text-2xl font-bold mb-4 bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent"></h3>
<ul className="space-y-4">
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span></span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>CSV形式でのエクスポート</span>
</li>
<li className="flex items-start">
<i className="fa-solid fa-check-circle text-green-500 mt-1 mr-3"></i>
<span>PNG画像としてのエクスポート</span>
</li>
</ul>
</div>
<div className="md:w-1/2">
<div className="bg-white p-4 rounded-xl shadow-xl">
<img
src="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Questionnaire%20data%20analysis%20dashboard%20with%20charts%20and%20graphs&sign=bd395ab9ad3c4c07ce7a3c64af386389"
alt="データ分析ダッシュボード"
className="rounded-lg w-full h-auto"
/>
</div>
</div>
</div>
<div className="mt-20 text-center">
<p className="text-gray-600 mb-4">
</p>
<a href="#contact" className="text-blue-600 font-medium hover:underline">
<i className="fa-solid fa-arrow-right ml-1"></i>
</a>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,119 @@
import { motion } from 'framer-motion';
import FeatureCard from './FeatureCard';
export default function FeatureSection() {
// 製品機能データ
const features = [
{
title: "直感的なアンケート作成",
description: "ドラッグドロップ操作で簡単にアンケートを作成。20種類以上のコンポーネントであらゆるニーズに対応。",
icon: "fa-magic",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20builder%20interface%20with%20drag%20and%20drop%20functionality%2C%20Japanese%20UI%2C%20form%20components&sign=8e9d8de869467bedbdf2e76d42647619"
},
{
title: "豊富なテンプレート",
description: "業界別のプリセットテンプレートを提供。すぐに使えるだけでなく、独自のテンプレートも作成可能。",
icon: "fa-file-alt",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20templates%20gallery%20Japanese%20interface%20business%20style&sign=53407b72fa47fa4cf1f6375135dcc882"
},
{
title: "高度な条件表示設定",
description: "回答に応じて質問を動的に表示/非表示。複雑なロジックも直感的に設定可能。",
icon: "fa-sitemap",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20conditional%20logic%20settings%20Japanese%20interface&sign=8caac1c11078139b117d451993301122"
},
{
title: "多様なアクセス制限",
description: "IP、デバイス、回答回数、時間制限など、必要な制限を設定してデータの信頼性を確保。",
icon: "fa-shield-alt",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20access%20control%20settings%20Japanese%20security%20interface&sign=2c413aa7bedc4e37a48cf3fd6898582e"
},
{
title: "リアルタイムデータ分析",
description: "回答をリアルタイムで集計し、グラフ(棒グラフ、折れ線グラフ、円グラフ)で視覚化。",
icon: "fa-chart-pie",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20data%20analysis%20dashboard%20charts%20Japanese%20interface&sign=ae43ebbb1096c076634ea4259267a835"
},
{
title: "柔軟なデータ管理",
description: "収集したデータの編集、エクスポート、印刷、添付ファイルの一括ダウンロードに対応。",
icon: "fa-database",
imageUrl: "https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20data%20management%20Japanese%20interface%20export%20functionality&sign=c49d55504f0bade0cfcec05fb3ac650c"
}
];
return (
<section id="features" className="py-20 bg-white dark:bg-gray-900">
<div className="container mx-auto px-4 md:px-8">
{/* セクションヘッダー */}
<div className="text-center max-w-3xl mx-auto mb-16">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-6">
Alisurveyの特徴
</h2>
<p className="text-lg text-gray-700">
</p>
</div>
{/* 機能カードグリッド */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{features.map((feature, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="group"
>
<FeatureCard {...feature} />
</motion.div>
))}
</div>
{/* 追加の機能強調 */}
<div className="mt-24">
<div className="bg-gradient-to-r from-blue-600 to-indigo-700 rounded-2xl overflow-hidden">
<div className="grid grid-cols-1 md:grid-cols-2">
<div className="p-8 md:p-12 flex flex-col justify-center relative">
<div
className="absolute inset-0 z-10 opacity-10"
style={{
backgroundImage: `radial-gradient(#416DE8 50%, transparent 50%)`,
backgroundSize: `60px 60px`,
}}
></div>
<h3 className="text-2xl md:text-3xl font-bold text-white mb-4">
</h3>
<p className="text-blue-100 mb-6">
</p>
<ul className="space-y-3">
{[
"企業ロゴやカラーテーマの適用",
"カスタム送信メッセージとリダイレクト設定",
"モバイルフレンドリーなレスポンシブデザイン",
"回収センターでアンケートを簡単に復元"
].map((item, i) => (
<li key={i} className="flex items-center text-white">
<i className="fa-solid fa-check-circle mr-2"></i>
<span>{item}</span>
</li>
))}
</ul>
</div>
<div className="bg-gray-100 p-4 md:p-8 flex items-center justify-center">
<img
src="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_4_3&prompt=Survey%20customization%20interface%20Japanese%20design%20tools%20brand%20colors&sign=9512c3b4c76e5a0413e8a1275d960909"
alt="アンケートカスタマイズ"
className="rounded-xl shadow-lg max-w-full h-auto"
/>
</div>
</div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,71 @@
import { cn } from '@/lib/utils';
export default function Footer() {
return (
<footer className="bg-gray-900 text-gray-300 pt-16 pb-8">
<div className="container mx-auto px-4 md:px-6">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-8 mb-12">
<div className="lg:col-span-2">
<h3 className="text-2xl font-bold text-white mb-4">Alisurvey</h3>
<p className="text-gray-400 mb-6 max-w-md">
SaaSプラットフォームです
</p>
<div className="flex space-x-4">
<a href="#" className="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-blue-600 transition-colors">
<i className="fa-brands fa-twitter"></i>
</a>
<a href="#" className="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-blue-700 transition-colors">
<i className="fa-brands fa-facebook"></i>
</a>
<a href="#" className="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-pink-600 transition-colors">
<i className="fa-brands fa-instagram"></i>
</a>
<a href="#" className="w-10 h-10 rounded-full bg-gray-800 flex items-center justify-center hover:bg-gray-700 transition-colors">
<i className="fa-brands fa-linkedin"></i>
</a>
</div>
</div>
<div>
<h4 className="text-lg font-semibold text-white mb-4"></h4>
<ul className="space-y-2">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
</ul>
</div>
<div>
<h4 className="text-lg font-semibold text-white mb-4"></h4>
<ul className="space-y-2">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
</ul>
</div>
<div>
<h4 className="text-lg font-semibold text-white mb-4"></h4>
<ul className="space-y-2">
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
<li><a href="#" className="text-gray-400 hover:text-white transition-colors"></a></li>
</ul>
</div>
</div>
<div className="border-t border-gray-800 pt-8">
<div className="flex flex-col md:flex-row justify-between items-center">
<p className="text-gray-500 text-sm mb-4 md:mb-0">
&copy; 2025 Alisurvey. .
</p>
<div className="flex gap-6">
<a href="#" className="text-gray-500 hover:text-gray-300 text-sm"></a>
<a href="#" className="text-gray-500 hover:text-gray-300 text-sm"></a>
<a href="#" className="text-gray-500 hover:text-gray-300 text-sm">Cookie設定</a>
<a href="#" className="text-gray-500 hover:text-gray-300 text-sm"></a>
</div>
</div>
</div>
</div>
</footer>
);
}

View File

@@ -0,0 +1,97 @@
import { useState } from 'react';
import { cn } from '@/lib/utils';
interface HeaderProps {
isScrolled: boolean;
}
export default function Header({ isScrolled }: HeaderProps) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
return (
<header
className={cn(
"fixed w-full z-50 transition-all duration-300",
isScrolled
? "bg-white shadow-md py-3"
: "bg-transparent py-5"
)}
>
<div className="container mx-auto px-4 md:px-8">
<div className="flex justify-between items-center">
{/* ロゴ */}
<div className="flex items-baseline">
<h1 className="text-2xl font-bold text-blue-600">Alisurvey</h1>
<span className="ml-2 text-gray-500 text-xs"></span>
</div>
{/* デスクトップナビゲーション */}
<nav className="hidden md:flex items-center space-x-8">
<a href="#features" className="text-gray-700 hover:text-blue-600 transition-colors"></a>
<a href="#details" className="text-gray-700 hover:text-blue-600 transition-colors"></a>
{/* <a href="#pricing" className="text-gray-700 hover:text-blue-600 transition-colors">価格</a>
<a href="#testimonials" className="text-gray-700 hover:text-blue-600 transition-colors">顧客の声</a> */}
<a href="#contact" className="text-gray-700 hover:text-blue-600 transition-colors"></a>
<button className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg transition-colors">
</button>
</nav>
{/* モバイルメニューボタン */}
<button
className="md:hidden text-gray-700"
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
<i className="fa-solid fa-bars text-xl"></i>
</button>
</div>
</div>
{/* モバイルメニュー */}
{mobileMenuOpen && (
<div className="md:hidden bg-white shadow-lg absolute w-full">
<div className="container mx-auto px-4 py-4 flex flex-col space-y-4">
<a
href="#features"
className="text-gray-700 hover:text-blue-600 py-2 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
</a>
<a
href="#details"
className="text-gray-700 hover:text-blue-600 py-2 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
</a>
{/* <a
href="#pricing"
className="text-gray-700 hover:text-blue-600 py-2 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
価格
</a>
<a
href="#testimonials"
className="text-gray-700 hover:text-blue-600 py-2 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
顧客の声
</a> */}
<a
href="#contact"
className="text-gray-700 hover:text-blue-600 py-2 transition-colors"
onClick={() => setMobileMenuOpen(false)}
>
</a>
<button className="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg transition-colors">
</button>
</div>
</div>
)}
</header>
);
}

View File

@@ -0,0 +1,104 @@
import { motion } from "framer-motion";
export default function Hero() {
return (
<section
className="pt-32 pb-20 md:pt-40 md:pb-32 bg-gradient-to-br from-blue-50 to-indigo-50">
<div className="container mx-auto px-4 md:px-8">
<div className="flex flex-col md:flex-row items-center">
{}
<div className="md:w-1/2 mb-12 md:mb-0">
<motion.div
initial={{
opacity: 0,
y: 20
}}
animate={{
opacity: 1,
y: 0
}}
transition={{
duration: 0.6
}}>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold text-gray-900 mb-6" style={{ lineHeight: '1.1em' }}>
<br />
<br />
<span className="bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent"></span>
</h1>
<p className="text-lg md:text-xl text-gray-700 mb-8 max-w-lg"><br />QRコードで即時共有</p>
<div className="flex flex-col sm:flex-row gap-4">
<button
className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-4 rounded-lg text-lg font-medium transition-all shadow-lg hover:shadow-xl transform hover:-translate-y-1"> <i className="fa-solid fa-arrow-right ml-2"></i>
</button>
<button
className="bg-white hover:bg-gray-50 text-blue-600 border border-blue-600 px-8 py-4 rounded-lg text-lg font-medium transition-all">
<i className="fa-solid fa-play-circle mr-2"></i>
</button>
</div>
{/* <div className="mt-10 flex items-center">
<div className="flex -space-x-2">
{[1, 2, 3, 4].map(i => <img
key={i}
src={`https://space.coze.cn/api/coze_space/gen_image?image_size=square&prompt=Japanese%20business%20person%20avatar&sign=c0224456042d7467b42e4fe01b6bb356`}
alt="顧客"
className="w-10 h-10 rounded-full border-2 border-white" />)}
</div>
<div className="ml-4">
<div className="flex items-center">
{[1, 2, 3, 4, 5].map(i => <i key={i} className="fa-solid fa-star text-yellow-400 text-sm"></i>)}
</div>
<p className="text-sm text-gray-600">500社以上の企業が信頼</p>
</div>
</div> */}
</motion.div>
</div>
{}
<div className="md:w-1/2">
<motion.div
initial={{
opacity: 0,
x: 20
}}
animate={{
opacity: 1,
x: 0
}}
transition={{
duration: 0.6,
delay: 0.2
}}>
<div className="relative">
<img
src="https://space.coze.cn/api/coze_space/gen_image?image_size=landscape_16_9&prompt=Survey%20software%20dashboard%20interface%20with%20Japanese%20language%20UI%2C%20clean%20design%2C%20data%20visualization%2C%20professional%20business%20software&sign=5519ee83ef20788c1286f1e6b97baab3"
alt="Alisurveyダッシュボード"
className="relative rounded-2xl overflow-hidden shadow-2xl transform rotate-1 hover:rotate-0 transition-transform duration-500" />
<div className="absolute -bottom-6 -left-6 bg-white p-4 rounded-xl shadow-lg transform hover:scale-105 transition-transform">
<div className="flex items-center">
<div className="bg-green-100 p-2 rounded-lg">
<i className="fa-solid fa-chart-line text-green-600 text-xl"></i>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900"></p>
<p className="text-2xl font-bold text-gray-900"></p>
</div>
</div>
</div>
<div className="absolute -top-6 -right-6 bg-white p-4 rounded-xl shadow-lg transform hover:scale-105 transition-transform">
<div className="flex items-center">
<div className="bg-blue-100 p-2 rounded-lg">
<i className="fa-solid fa-magic text-blue-600 text-xl"></i>
</div>
<div className="ml-3">
<p className="text-sm font-medium text-gray-900"></p>
<p className="text-2xl font-bold text-gray-900">90</p>
</div>
</div>
</div>
</div>
</motion.div>
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,164 @@
import { motion } from 'framer-motion';
export default function PricingSection() {
return (
<section id="pricing" className="py-20 bg-white">
<div className="container mx-auto px-4 md:px-8">
<div className="text-center max-w-3xl mx-auto mb-16">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
</h2>
<p className="text-gray-700 mb-8">
14
</p>
<div className="inline-flex bg-gray-100 p-1 rounded-lg">
<button className="px-6 py-2 rounded-lg bg-white shadow-sm text-gray-900 font-medium">
</button>
<button className="px-6 py-2 rounded-lg text-gray-600">
<span className="text-xs bg-red-100 text-red-600 px-2 py-0.5 rounded ml-1">2</span>
</button>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
{/* スタータープラン */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="bg-white border border-gray-200 rounded-2xl overflow-hidden shadow-sm hover:shadow-md transition-shadow"
>
<div className="p-8">
<h3 className="text-xl font-bold text-gray-900 mb-2"></h3>
<p className="text-gray-600 mb-6"></p>
<div className="mb-6">
<span className="text-4xl font-bold text-gray-900">¥2,980</span>
<span className="text-gray-500">/</span>
</div>
<button className="w-full py-3 border border-blue-600 text-blue-600 font-medium rounded-lg hover:bg-blue-50 transition-colors mb-8">
</button>
<ul className="space-y-3">
{[
"月間5アンケート作成",
"最大100件/月回答収集",
"基本テンプレート20種類",
"基本フォームコンポーネント10種類",
"基本データ分析",
"CSVエクスポート",
"メールサポート"
].map((feature, i) => (
<li key={i} className="flex items-start">
<i className="fa-solid fa-check text-green-500 mt-1 mr-2"></i>
<span className="text-gray-700">{feature}</span>
</li>
))}
</ul>
</div>
</motion.div>
{/* ビジネスプラン */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="bg-gradient-to-b from-blue-50 to-white border-2 border-blue-600 rounded-2xl overflow-hidden shadow-lg transform scale-105 z-10"
>
<div className="bg-blue-600 text-white text-center py-2 text-sm font-medium">
</div>
<div className="p-8">
<h3 className="text-xl font-bold text-gray-900 mb-2"></h3>
<p className="text-gray-600 mb-6"></p>
<div className="mb-6">
<span className="text-4xl font-bold text-gray-900">¥7,980</span>
<span className="text-gray-500">/</span>
</div>
<button className="w-full py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors mb-8">
</button>
<ul className="space-y-3">
{[
"月間20アンケート作成",
"最大1,000件/月回答収集",
"全テンプレート50種類",
"全フォームコンポーネント20種類",
"詳細データ分析とグラフ",
"Excel/PDF/CSVエクスポート",
"優先メールサポート",
"条件表示設定",
"基本アクセス制限",
"ブランドカスタマイズ"
].map((feature, i) => (
<li key={i} className="flex items-start">
<i className="fa-solid fa-check text-green-500 mt-1 mr-2"></i>
<span className="text-gray-700">{feature}</span>
</li>
))}
</ul>
</div>
</motion.div>
{/* エンタープライズプラン */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.4 }}
className="bg-white border border-gray-200 rounded-2xl overflow-hidden shadow-sm hover:shadow-md transition-shadow"
>
<div className="p-8">
<h3 className="text-xl font-bold text-gray-900 mb-2"></h3>
<p className="text-gray-600 mb-6"></p>
<div className="mb-6">
<span className="text-4xl font-bold text-gray-900"></span>
</div>
<button className="w-full py-3 border border-blue-600 text-blue-600 font-medium rounded-lg hover:bg-blue-50 transition-colors mb-8">
</button>
<ul className="space-y-3">
{[
"無制限アンケート作成",
"無制限回答収集",
"カスタムテンプレート作成",
"全フォームコンポーネント20+種類)",
"高度なデータ分析レポート",
"APIアクセス",
"専属アカウントマネージャー",
"すべてのアクセス制限機能",
"詳細なブランドカスタマイズ",
"SSO統合"
].map((feature, i) => (
<li key={i} className="flex items-start">
<i className="fa-solid fa-check text-green-500 mt-1 mr-2"></i>
<span className="text-gray-700">{feature}</span>
</li>
))}
</ul>
</div>
</motion.div>
</div>
<div className="mt-12 text-center">
<p className="text-gray-600 mb-4">
</p>
<a href="#contact" className="text-blue-600 font-medium hover:underline">
<i className="fa-solid fa-arrow-right ml-1"></i>
</a>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,88 @@
import { motion } from 'framer-motion';
const testimonials = [
{
name: "田中 健太",
company: "株式会社ABC",
position: "マーケティング部長",
content: "Alisurveyの直感的な操作感に驚きました。これまでIT部門に依頼していたアンケート作成を、マーケティングチーム内で完結できるようになり、作業効率が格段に向上しました。",
avatar: "https://space.coze.cn/api/coze_space/gen_image?image_size=square&prompt=Middle%20aged%20Japanese%20businessman%20smile&sign=753057963873d8d3eaec44917a19d62f"
},
{
name: "鈴木 美玲",
company: "デザイン事務所DEF",
position: "代表取締役",
content: "顧客満足度調査を効率よく実施できるようになりました。デザインカスタマイズ機能も充実していて、自分たちのブランドに合わせたアンケートを作成できる点が非常に魅力的です。",
avatar: "https://space.coze.cn/api/coze_space/gen_image?image_size=square&prompt=Japanese%20female%20designer%20professional%20look&sign=0c57ddb3fbc04b1fa0b374f9dfacdfdd"
},
{
name: "佐藤 明",
company: "大学 経済学部",
position: "准教授",
content: "学術研究のためのアンケート調査に使用しています。高度な条件表示機能と詳細なデータ分析ができるため、複雑な研究デザインにも十分対応できます。学生のアルバイトにも簡単に操作してもらえます。",
avatar: "https://space.coze.cn/api/coze_space/gen_image?image_size=square&prompt=Japanese%20university%20professor%20serious%20expression&sign=f364a27a1ded38fb623a950e768190db"
}
];
export default function Testimonials() {
return (
<section id="testimonials" className="py-20 bg-gray-50">
<div className="container mx-auto px-4 md:px-8">
<div className="text-center max-w-3xl mx-auto mb-16">
<h2 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">
</h2>
<p className="text-gray-700">
Alisurveyをご利用いただいている顧客の声をご紹介します
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{testimonials.map((testimonial, index) => (
<motion.div
key={index}
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: index * 0.1 }}
className="bg-white p-8 rounded-2xl shadow-sm"
>
<div className="flex items-center mb-4">
{[1, 2, 3, 4, 5].map((i) => (
<i key={i} className="fa-solid fa-star text-yellow-400"></i>
))}
</div>
<p className="text-gray-700 mb-6 italic">"{testimonial.content}"</p>
<div className="flex items-center">
<img
src={testimonial.avatar}
alt={testimonial.name}
className="w-12 h-12 rounded-full object-cover mr-4"
/>
<div>
<h4 className="font-bold text-gray-900">{testimonial.name}</h4>
<p className="text-sm text-gray-600">{testimonial.position}, {testimonial.company}</p>
</div>
</div>
</motion.div>
))}
</div>
<div className="mt-16 text-center">
<div className="inline-flex items-center justify-center space-x-12">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="opacity-60 grayscale hover:opacity-100 hover:grayscale-0 transition-all">
<img
src={`https://space.coze.cn/api/coze_space/gen_image?image_size=square&prompt=Japanese%20company%20logo%20simple%20design&sign=d07c387595cd76e07532ca1d17df694e`}
alt="顧客企業"
className="h-8 object-contain"
/>
</div>
))}
</div>
</div>
</div>
</section>
);
}

View File

@@ -0,0 +1,7 @@
import { createContext } from "react";
export const AuthContext = createContext({
isAuthenticated: false,
setIsAuthenticated: (value: boolean) => {},
logout: () => {},
});

View File

@@ -0,0 +1,29 @@
import { useState, useEffect } from 'react';
type Theme = 'light' | 'dark';
export function useTheme() {
const [theme, setTheme] = useState<Theme>(() => {
const savedTheme = localStorage.getItem('theme') as Theme;
if (savedTheme) {
return savedTheme;
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
});
useEffect(() => {
document.documentElement.classList.remove('light', 'dark');
document.documentElement.classList.add(theme);
localStorage.setItem('theme', theme);
}, [theme]);
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return {
theme,
toggleTheme,
isDark: theme === 'dark'
};
}

View File

@@ -0,0 +1,15 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
line-height: 1.5;
font-weight: 400;
scroll-behavior: smooth;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

View File

@@ -0,0 +1,6 @@
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}

View File

@@ -0,0 +1,15 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { Toaster } from 'sonner';
import App from "./App.tsx";
import "./index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<BrowserRouter>
<App />
<Toaster />
</BrowserRouter>
</StrictMode>
);

View File

@@ -0,0 +1,68 @@
import { useState, useEffect } from 'react';
import {
BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
PieChart, Pie, Cell, LineChart, Line
} from 'recharts';
import Header from '@/components/Header';
import Hero from '@/components/Hero';
import FeatureSection from '@/components/FeatureSection';
import FeatureDetail from '@/components/FeatureDetail';
import ChartDemo from '@/components/ChartDemo';
import PricingSection from '@/components/PricingSection';
import Testimonials from '@/components/Testimonials';
import CTA from '@/components/CTA';
import Footer from '@/components/Footer';
// ダミーデータ - アンケート統計例
const surveyData = [
{ name: '満足', value: 65 },
{ name: '普通', value: 25 },
{ name: '不満', value: 10 },
];
const usageData = [
{ month: '1月', 利用者: 400 },
{ month: '2月', 利用者: 600 },
{ month: '3月', 利用者: 800 },
{ month: '4月', 利用者: 1200 },
{ month: '5月', 利用者: 1500 },
{ month: '6月', 利用者: 1800 },
];
const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042'];
export default function Home() {
const [isScrolled, setIsScrolled] = useState(false);
// スクロール時のヘッダースタイル変更
useEffect(() => {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<div className="min-h-screen bg-white text-gray-800">
{/* ヘッダー */}
<Header isScrolled={isScrolled} />
{/* ヒーローセクション */}
<Hero />
{/* 特徴セクション */}
<FeatureSection />
{/* 機能詳細セクション */}
<FeatureDetail />
{/* CTAセクション */}
<CTA />
{/* フッター */}
<Footer />
</div>
);
}

View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@@ -0,0 +1,17 @@
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** @type {import('tailwindcss').Config} */
export default {
darkMode: "class",
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
container: {
center: true,
},
extend: {},
},
plugins: [],
};

View File

@@ -0,0 +1,36 @@
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true,
/* Paths */
"baseUrl": "./",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"]
}

View File

@@ -0,0 +1,16 @@
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
/** WARNING: DON'T EDIT THIS FILE */
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
function getPlugins() {
const plugins = [react(), tsconfigPaths()];
return plugins;
}
export default defineConfig({
plugins: getPlugins()
});