mirror of
https://github.com/Funkoala14/CreatorCenter_OOIN.git
synced 2025-06-07 20:38:14 +08:00
[dev]creator detail->top info
This commit is contained in:
parent
9999e334fb
commit
cf1a9d10f6
@ -141,7 +141,7 @@ OOIN Creator Center is a React application built with Vite that allows users to
|
||||
### UI Components
|
||||
- `SearchBar`: Reusable search component used across different pages
|
||||
- `DatabaseFilter`: Complex filter component for creator discovery
|
||||
- `DatabaseList`: Displays creator data in a tabular format
|
||||
- `CreatorList`: Displays creator data in a tabular format
|
||||
- `ChatWindow` and `ChatInput`: Used for creator communications
|
||||
- `RangeSlider`: Custom slider component for range-based filtering
|
||||
|
||||
|
27
package-lock.json
generated
27
package-lock.json
generated
@ -16,12 +16,14 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@reduxjs/toolkit": "^2.8.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
"chart.js": "^4.4.9",
|
||||
"date-fns": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.508.0",
|
||||
"react": "^19.1.0",
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-bootstrap-range-slider": "^3.0.8",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
@ -1057,6 +1059,11 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@kurkle/color": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
|
||||
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
|
||||
@ -2143,6 +2150,17 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "4.4.9",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz",
|
||||
"integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==",
|
||||
"dependencies": {
|
||||
"@kurkle/color": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
@ -3999,6 +4017,15 @@
|
||||
"react-dom": ">=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-chartjs-2": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz",
|
||||
"integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==",
|
||||
"peerDependencies": {
|
||||
"chart.js": "^4.1.1",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
|
||||
|
@ -18,12 +18,14 @@
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@reduxjs/toolkit": "^2.8.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
"chart.js": "^4.4.9",
|
||||
"date-fns": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.508.0",
|
||||
"react": "^19.1.0",
|
||||
"react-bootstrap": "^2.10.9",
|
||||
"react-bootstrap-range-slider": "^3.0.8",
|
||||
"react-chartjs-2": "^5.3.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.6.0",
|
||||
|
@ -3,6 +3,9 @@ import { library } from '@fortawesome/fontawesome-svg-core';
|
||||
import { fas } from '@fortawesome/free-solid-svg-icons';
|
||||
import Router from './router';
|
||||
import './styles/Campaign.scss';
|
||||
import { Chart as ChartJS, ArcElement, Tooltip, Legend } from "chart.js";
|
||||
|
||||
ChartJS.register(ArcElement, Tooltip, Legend);
|
||||
|
||||
// Add Font Awesome icons to library
|
||||
library.add(faTiktok, fas, faYoutube, faInstagram);
|
||||
|
@ -11,8 +11,9 @@ import {
|
||||
import { setSortBy } from '../store/slices/filtersSlice';
|
||||
import '../styles/DatabaseList.scss';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default function DatabaseList({ path }) {
|
||||
export default function CreatorList({ path, pageType = 'database' }) {
|
||||
const dispatch = useDispatch();
|
||||
const { creators, status, selectedCreators } = useSelector((state) => state.creators);
|
||||
const { sortBy, sortDirection } = useSelector((state) => state.filters);
|
||||
@ -20,7 +21,7 @@ export default function DatabaseList({ path }) {
|
||||
// 组件加载时获取创作者数据
|
||||
useEffect(() => {
|
||||
if (status === 'idle') {
|
||||
dispatch(fetchCreators({path}));
|
||||
dispatch(fetchCreators({ path }));
|
||||
}
|
||||
}, [dispatch, status]);
|
||||
|
||||
@ -121,6 +122,13 @@ export default function DatabaseList({ path }) {
|
||||
<th className='views text-center' onClick={() => handleSort('avgViews')}>
|
||||
Avg. Video Views {renderSortIcon('avgViews')}
|
||||
</th>
|
||||
{pageType === 'private' && (
|
||||
<>
|
||||
<th className='pricing text-center'>Pricing</th>
|
||||
<th className='collab-count text-center'># Collab</th>
|
||||
<th className='latest-collab text-center'>Latest Collab.</th>
|
||||
</>
|
||||
)}
|
||||
<th className='e-commerce text-center'>E-commerce</th>
|
||||
<th className='profile text-center'>Profile</th>
|
||||
</tr>
|
||||
@ -148,7 +156,9 @@ export default function DatabaseList({ path }) {
|
||||
<img src={creator.avatar} alt={creator.name} />
|
||||
{creator.verified && <span className='verified-badge'></span>}
|
||||
</div>
|
||||
<div className='creator-name'>{creator.name}</div>
|
||||
<Link to={`/creator/${creator.id}`} className='creator-name'>
|
||||
{creator.name}
|
||||
</Link>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
@ -170,6 +180,13 @@ export default function DatabaseList({ path }) {
|
||||
<div className='small text-muted'>Items Sold: {creator.soldPercentage}</div>
|
||||
</td>
|
||||
<td className='text-nowrap text-center'>{creator.avgViews}</td>
|
||||
{pageType === 'private' && (
|
||||
<>
|
||||
<td className='text-center'>{creator.pricing}</td>
|
||||
<td className='text-center'>{creator.collabCount}</td>
|
||||
<td className='text-center'>{creator.latestCollab}</td>
|
||||
</>
|
||||
)}
|
||||
<td className='text-center'>
|
||||
{creator.hasEcommerce ? <div className='colored-dot blue mx-auto'></div> : null}
|
||||
</td>
|
@ -9,15 +9,14 @@ import {
|
||||
toggleExposureRating,
|
||||
toggleGmvRange,
|
||||
setViewsRange,
|
||||
resetFilters,
|
||||
setPricingRange,
|
||||
} from '../store/slices/filtersSlice';
|
||||
import { fetchCreators } from '../store/slices/creatorsSlice';
|
||||
import '../styles/DatabaseFilter.scss';
|
||||
|
||||
export default function DatabaseFilter({ path }) {
|
||||
export default function DatabaseFilter({ path, pageType = 'database' }) {
|
||||
const dispatch = useDispatch();
|
||||
const filters = useSelector((state) => state.filters);
|
||||
|
||||
// 类别选项数据
|
||||
const categories = [
|
||||
'Phones & Electronics',
|
||||
@ -46,7 +45,7 @@ export default function DatabaseFilter({ path }) {
|
||||
|
||||
// 预定义的离散点值
|
||||
const discreteValues = [0, 100, 1000, 10000, 100000, 250000, 500000];
|
||||
|
||||
const discretePricingValues = [0, 200, 400, 600, 800, 1000, 3000];
|
||||
// 找到最接近的离散值索引
|
||||
const findClosestDiscreteIndex = (value) => {
|
||||
let closestIndex = 0;
|
||||
@ -66,12 +65,16 @@ export default function DatabaseFilter({ path }) {
|
||||
// 本地状态用于表单控制
|
||||
const [minViews, setMinViews] = useState(filters.viewsRange[0]);
|
||||
const [maxViews, setMaxViews] = useState(filters.viewsRange[1]);
|
||||
const [minPricing, setMinPricing] = useState(filters.pricingRange[0]);
|
||||
const [maxPricing, setMaxPricing] = useState(filters.pricingRange[1]);
|
||||
|
||||
// 监听Redux状态变化,更新本地表单状态
|
||||
useEffect(() => {
|
||||
setMinViews(filters.viewsRange[0]);
|
||||
setMaxViews(filters.viewsRange[1]);
|
||||
}, [filters.viewsRange]);
|
||||
setMinPricing(filters.pricingRange[0]);
|
||||
setMaxPricing(filters.pricingRange[1]);
|
||||
}, [filters.viewsRange, filters.pricingRange]);
|
||||
|
||||
// 组件加载时获取数据
|
||||
useEffect(() => {
|
||||
@ -115,6 +118,22 @@ export default function DatabaseFilter({ path }) {
|
||||
setMaxViews(inputValue);
|
||||
};
|
||||
|
||||
const handlePricingRangeChange = (newRange) => {
|
||||
dispatch(setPricingRange(newRange));
|
||||
};
|
||||
|
||||
// 处理min pricing input变更
|
||||
const handleMinPricingChange = (e) => {
|
||||
const inputValue = parseInt(e.target.value) || 0;
|
||||
setMinPricing(inputValue);
|
||||
};
|
||||
|
||||
// 处理max pricing input变更
|
||||
const handleMaxPricingChange = (e) => {
|
||||
const inputValue = parseInt(e.target.value) || 0;
|
||||
setMaxPricing(inputValue);
|
||||
};
|
||||
|
||||
// 当输入框失去焦点时,转换为最接近的离散值
|
||||
const handleInputBlur = (type) => {
|
||||
if (type === 'min') {
|
||||
@ -140,6 +159,29 @@ export default function DatabaseFilter({ path }) {
|
||||
}
|
||||
};
|
||||
|
||||
// 处理min pricing input失去焦点
|
||||
const handlePricingInputBlur = (type) => {
|
||||
if (type === 'min') {
|
||||
const closestIndex = findClosestDiscreteIndex(minPricing);
|
||||
const discreteValue = discretePricingValues[closestIndex];
|
||||
|
||||
// 确保最小值不超过最大值
|
||||
const finalValue = Math.min(discreteValue, maxPricing);
|
||||
|
||||
setMinPricing(finalValue);
|
||||
dispatch(setPricingRange([finalValue, filters.pricingRange[1]]));
|
||||
} else {
|
||||
const closestIndex = findClosestDiscreteIndex(maxPricing);
|
||||
const discreteValue = discretePricingValues[closestIndex];
|
||||
|
||||
// 确保最大值不小于最小值
|
||||
const finalValue = Math.max(discreteValue, minPricing);
|
||||
|
||||
setMaxPricing(finalValue);
|
||||
dispatch(setPricingRange([filters.pricingRange[0], finalValue]));
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化显示值的函数
|
||||
const formatValue = (value) => {
|
||||
if (value >= 1000000) {
|
||||
@ -227,7 +269,7 @@ export default function DatabaseFilter({ path }) {
|
||||
{/* 视频观看量筛选 */}
|
||||
<div className='filter-item'>
|
||||
<h5 className='filter-title'>Views</h5>
|
||||
<div className='filter-options filter-views'>
|
||||
<div className='filter-options filter-views filter-range-slider'>
|
||||
<RangeSlider
|
||||
min={0}
|
||||
max={500000}
|
||||
@ -262,6 +304,47 @@ export default function DatabaseFilter({ path }) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pricing 筛选 */}
|
||||
{pageType === 'private' && (
|
||||
<div className='filter-item'>
|
||||
<h5 className='filter-title'>Pricing</h5>
|
||||
<div className='filter-options filter-pricing filter-range-slider'>
|
||||
<RangeSlider
|
||||
min={0}
|
||||
max={500000}
|
||||
value={filters.pricingRange}
|
||||
onChange={handlePricingRangeChange}
|
||||
/>
|
||||
|
||||
<div className='range-input'>
|
||||
<InputGroup>
|
||||
<InputGroup.Text>
|
||||
<Eye size={16} />
|
||||
</InputGroup.Text>
|
||||
<Form.Control
|
||||
type='number'
|
||||
value={minPricing}
|
||||
onChange={handleMinPricingChange}
|
||||
onBlur={() => handlePricingInputBlur('min')}
|
||||
/>
|
||||
</InputGroup>
|
||||
<span>-</span>
|
||||
<InputGroup>
|
||||
<InputGroup.Text>
|
||||
<Eye size={16} />
|
||||
</InputGroup.Text>
|
||||
<Form.Control
|
||||
type='number'
|
||||
value={maxPricing}
|
||||
onChange={handleMaxPricingChange}
|
||||
onBlur={() => handlePricingInputBlur('max')}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card.Body>
|
||||
</div>
|
||||
);
|
||||
|
@ -59,7 +59,26 @@ const menuItems = [
|
||||
path: '/private-creators',
|
||||
icon: <Heart />,
|
||||
hasSubmenu: true,
|
||||
submenuItems: [],
|
||||
submenuItems: [
|
||||
{
|
||||
id: 'tiktok',
|
||||
title: 'TikTok',
|
||||
path: '/private-creators/tiktok',
|
||||
icon: <FontAwesomeIcon icon='fa-brands fa-tiktok' />,
|
||||
},
|
||||
{
|
||||
id: 'instagram',
|
||||
title: 'Instagram',
|
||||
path: '/private-creators/instagram',
|
||||
icon: <FontAwesomeIcon icon='fa-brands fa-instagram' />,
|
||||
},
|
||||
{
|
||||
id: 'youtube',
|
||||
title: 'YouTube',
|
||||
path: '/private-creators/youtube',
|
||||
icon: <FontAwesomeIcon icon='fa-brands fa-youtube' />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'deep-analysis',
|
||||
|
174
src/pages/CreatorDetail.jsx
Normal file
174
src/pages/CreatorDetail.jsx
Normal file
@ -0,0 +1,174 @@
|
||||
import { ArrowLeft, Instagram, Link, Mail, MapPin } from 'lucide-react';
|
||||
import { useEffect } from 'react';
|
||||
import { Card } from 'react-bootstrap';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { selectCreator, clearCreator } from '../store/slices/creatorsSlice';
|
||||
import { Doughnut } from 'react-chartjs-2';
|
||||
|
||||
const data = {
|
||||
labels: ['Red', 'Blue', 'Green', 'Purple'],
|
||||
datasets: [
|
||||
{
|
||||
label: 'GMV',
|
||||
data: [12, 19, 5, 2],
|
||||
backgroundColor: ['rgba(217, 107, 139)', 'rgba(101, 105, 225)', 'rgba(93, 200, 179)', 'rgba(122, 87, 218)'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const options = {
|
||||
cutout: 70,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: {
|
||||
generateLabels: function (chart) {
|
||||
return chart.data.labels.map((label, index) => {
|
||||
const value = chart.data.datasets[0].data[index];
|
||||
return {
|
||||
text: `${label} ${value}%`,
|
||||
fillStyle: chart.data.datasets[0].backgroundColor[index],
|
||||
strokeStyle: chart.data.datasets[0].backgroundColor[index],
|
||||
index: index,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default function CreatorDetail({}) {
|
||||
const { id } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useDispatch();
|
||||
const { selectedCreator } = useSelector((state) => state.creators);
|
||||
|
||||
const handleBack = () => {
|
||||
navigate(-1);
|
||||
};
|
||||
useEffect(() => {
|
||||
dispatch(selectCreator(id));
|
||||
return () => {
|
||||
dispatch(clearCreator());
|
||||
};
|
||||
}, [dispatch, id]);
|
||||
console.log(selectedCreator);
|
||||
return (
|
||||
<div className='creator-detail-page'>
|
||||
<div className='back-button' onClick={handleBack}>
|
||||
<ArrowLeft size={16} /> Go back
|
||||
</div>
|
||||
{selectedCreator ? (
|
||||
<div className='creator-info-detail-container'>
|
||||
<div className='creator-info-container'>
|
||||
<div className='creator-info-1'>
|
||||
<div className='creator-avatar'>
|
||||
<img src={selectedCreator.avatar} alt={selectedCreator.name} />
|
||||
</div>
|
||||
<div className='creator-info-right'>
|
||||
<div className='creator-name'>{selectedCreator.name}</div>
|
||||
<div className='creator-desc'>{selectedCreator.description || '--'}</div>
|
||||
<div className='creator-category'>{selectedCreator.category || '--'}</div>
|
||||
<div className='creator-location'>
|
||||
<MapPin size={16} />
|
||||
{selectedCreator.location || ' --'}
|
||||
</div>
|
||||
<div className='creator-live-time'>{selectedCreator.liveTime || '--'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='creator-info-2'>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label'>Category</div>
|
||||
<div className='creator-info-value'>{selectedCreator.category}</div>
|
||||
</div>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label'>MCN</div>
|
||||
<div className='creator-info-value'>{selectedCreator.mcn || '--'}</div>
|
||||
</div>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label'>Pricing</div>
|
||||
<div className='creator-info-value'>{selectedCreator.pricing}</div>
|
||||
</div>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label'>Collab.</div>
|
||||
<div className='creator-info-value'>{selectedCreator.collab || '--'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='creator-info-3'>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label mail'>
|
||||
<Mail size={18} />
|
||||
</div>
|
||||
<div className='creator-info-value'>{selectedCreator.email || '--'}</div>
|
||||
</div>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label social'>
|
||||
<Instagram size={18} />
|
||||
</div>
|
||||
<div className='creator-info-value'>{selectedCreator.instagram || '--'}</div>
|
||||
</div>
|
||||
<div className='creator-info-item'>
|
||||
<div className='creator-info-label link'>
|
||||
<Link size={18} />
|
||||
</div>
|
||||
<div className='creator-info-value'>{selectedCreator.url || '--'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='creator-data'>
|
||||
<div className='levels'>
|
||||
<div className='level-item'>
|
||||
<div className='name'>E-commerce Level</div>
|
||||
<div className='value'>{selectedCreator.ecommerceLevel || '--'}</div>
|
||||
</div>
|
||||
<div className='level-item'>
|
||||
<div className='name'>Exposure Level</div>
|
||||
<div className='value'>{selectedCreator.exposureLevel || '--'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='data-cards'>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.followers || '--'}</div>
|
||||
<div className='name'>Followers</div>
|
||||
</div>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.gmv || '--'}</div>
|
||||
<div className='name'>GMV</div>
|
||||
</div>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.avgVideoViews || '--'}</div>
|
||||
<div className='name'>Avg Video Views</div>
|
||||
</div>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.itemsSold || '--'}</div>
|
||||
<div className='name'>Items Sold</div>
|
||||
</div>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.gpm || '--'}</div>
|
||||
<div className='name'>GPM</div>
|
||||
</div>
|
||||
<div className='data-card'>
|
||||
<div className='value'>{selectedCreator.gpmPerCustomer || '--'}</div>
|
||||
<div className='name'>GMV per customer</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='data-charts'>
|
||||
<div className='data-chart'>
|
||||
<div className='chart-title'>GMV per sales channel</div>
|
||||
<Doughnut data={data} options={options} />
|
||||
</div>
|
||||
<div className='data-chart'>
|
||||
<div className='chart-title'>GMV by product category</div>
|
||||
<Doughnut data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div>No creator found</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import DatabaseFilter from '../components/DatabaseFilter';
|
||||
import DatabaseList from '../components/DatabaseList';
|
||||
import CreatorList from '../components/CreatorList';
|
||||
import SearchBar from '../components/SearchBar';
|
||||
import { Button } from 'react-bootstrap';
|
||||
export default function Database({ path }) {
|
||||
@ -16,8 +16,8 @@ export default function Database({ path }) {
|
||||
{path === 'instagram' && <div className='breadcrumb-item'>Instagram</div>}
|
||||
{path === 'youtube' && <div className='breadcrumb-item'>YouTube</div>}
|
||||
</div>
|
||||
<DatabaseFilter path={path} />
|
||||
<DatabaseList path={path} />
|
||||
<DatabaseFilter path={path} pageType={'database'} />
|
||||
<CreatorList path={path} pageType={'database'} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
25
src/pages/PrivateCreator.jsx
Normal file
25
src/pages/PrivateCreator.jsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import SearchBar from '../components/SearchBar';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import DatabaseFilter from '../components/DatabaseFilter';
|
||||
import CreatorList from '../components/CreatorList';
|
||||
|
||||
export default function PrivateCreator({ path }) {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className='function-bar'>
|
||||
<SearchBar />
|
||||
<Button>+ Add to Campaign</Button>
|
||||
</div>
|
||||
<div className='breadcrumb'>
|
||||
<div className='breadcrumb-item'>Private Creators</div>
|
||||
{path === 'tiktok' && <div className='breadcrumb-item'>TikTok</div>}
|
||||
{path === 'instagram' && <div className='breadcrumb-item'>Instagram</div>}
|
||||
{path === 'youtube' && <div className='breadcrumb-item'>YouTube</div>}
|
||||
</div>
|
||||
<DatabaseFilter path={path} pageType={'private'} />
|
||||
<CreatorList path={path} pageType={'private'} />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
@ -9,6 +9,8 @@ import BrandsDetail from '@/pages/BrandsDetail';
|
||||
import CampaignDetail from '@/pages/CampaignDetail';
|
||||
import Login from '@/pages/Login';
|
||||
import CreatorDiscovery from '@/pages/CreatorDiscovery';
|
||||
import PrivateCreator from '../pages/PrivateCreator';
|
||||
import CreatorDetail from '../pages/CreatorDetail';
|
||||
|
||||
// Routes configuration object
|
||||
const routes = [
|
||||
@ -25,7 +27,7 @@ const routes = [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
element: <Database />,
|
||||
element: <Database path='tiktok'/>,
|
||||
},
|
||||
{
|
||||
path: 'tiktok',
|
||||
@ -42,8 +44,25 @@ const routes = [
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/private-creators/*',
|
||||
element: <Home />,
|
||||
path: '/private-creators',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
element: <PrivateCreator path='tiktok' />,
|
||||
},
|
||||
{
|
||||
path: 'tiktok',
|
||||
element: <PrivateCreator path='tiktok' />,
|
||||
},
|
||||
{
|
||||
path: 'instagram',
|
||||
element: <PrivateCreator path='instagram' />,
|
||||
},
|
||||
{
|
||||
path: 'youtube',
|
||||
element: <PrivateCreator path='youtube' />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/deep-analysis',
|
||||
@ -65,6 +84,10 @@ const routes = [
|
||||
path: '/settings',
|
||||
element: <Home />,
|
||||
},
|
||||
{
|
||||
path: '/creator/:id',
|
||||
element: <CreatorDetail />,
|
||||
},
|
||||
];
|
||||
|
||||
// Create router with routes wrapped in the layout
|
||||
|
@ -158,6 +158,7 @@ const initialState = {
|
||||
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
|
||||
error: null,
|
||||
selectedCreators: [],
|
||||
selectedCreator: null,
|
||||
};
|
||||
|
||||
const creatorsSlice = createSlice({
|
||||
@ -169,7 +170,7 @@ const creatorsSlice = createSlice({
|
||||
const isSelected = state.selectedCreators.includes(creatorId);
|
||||
|
||||
if (isSelected) {
|
||||
state.selectedCreators = state.selectedCreators.filter((id) => id !== creatorId);
|
||||
state.selectedCreators = state.selectedCreators.filter((id) => id.toString() !== creatorId.toString());
|
||||
} else {
|
||||
state.selectedCreators.push(creatorId);
|
||||
}
|
||||
@ -180,6 +181,13 @@ const creatorsSlice = createSlice({
|
||||
clearCreatorSelection: (state) => {
|
||||
state.selectedCreators = [];
|
||||
},
|
||||
selectCreator: (state, action) => {
|
||||
const id = action.payload;
|
||||
state.selectedCreator = state.creators.find((creator) => creator.id.toString() === id.toString());
|
||||
},
|
||||
clearCreator: (state) => {
|
||||
state.selectedCreator = null;
|
||||
},
|
||||
},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
@ -198,6 +206,7 @@ const creatorsSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const { toggleCreatorSelection, selectAllCreators, clearCreatorSelection } = creatorsSlice.actions;
|
||||
export const { toggleCreatorSelection, selectAllCreators, clearCreatorSelection, selectCreator, clearCreator } =
|
||||
creatorsSlice.actions;
|
||||
|
||||
export default creatorsSlice.reducer;
|
||||
|
@ -6,10 +6,10 @@ const initialState = {
|
||||
exposureRatings: [],
|
||||
gmvRanges: ['$5k - $25k', '$25k - $60k'],
|
||||
viewsRange: [0, 100000],
|
||||
pricingRange: [0, 3000],
|
||||
sortBy: 'followers',
|
||||
sortDirection: 'desc',
|
||||
};
|
||||
|
||||
const filtersSlice = createSlice({
|
||||
name: 'filters',
|
||||
initialState,
|
||||
@ -49,6 +49,9 @@ const filtersSlice = createSlice({
|
||||
setViewsRange: (state, action) => {
|
||||
state.viewsRange = action.payload;
|
||||
},
|
||||
setPricingRange: (state, action) => {
|
||||
state.pricingRange = action.payload;
|
||||
},
|
||||
setSortBy: (state, action) => {
|
||||
// 如果选择了当前已激活的排序项,则切换排序方向
|
||||
if (state.sortBy === action.payload) {
|
||||
@ -71,6 +74,7 @@ export const {
|
||||
toggleExposureRating,
|
||||
toggleGmvRange,
|
||||
setViewsRange,
|
||||
setPricingRange,
|
||||
setSortBy,
|
||||
resetFilters,
|
||||
} = filtersSlice.actions;
|
||||
|
@ -51,3 +51,168 @@
|
||||
border: 1px solid #171a1f12;
|
||||
}
|
||||
}
|
||||
|
||||
.creator-detail-page {
|
||||
.creator-info-detail-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
|
||||
.creator-info-container {
|
||||
width: 40%;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
background: #ffffffff; /* white */
|
||||
border-radius: 8px; /* border-l */
|
||||
box-shadow: 0px 0px 1px #171a1f12, 0px 0px 2px #171a1f1f; /* shadow-xs */
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
|
||||
.creator-info-1 {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid $neutral-300;
|
||||
padding-bottom: 1rem;
|
||||
.creator-avatar {
|
||||
width: 115px;
|
||||
height: 115px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.creator-info-right {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 0.5rem;
|
||||
.creator-name {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
.creator-info-2 {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 1rem;
|
||||
border-bottom: 2px solid $neutral-300;
|
||||
padding-bottom: 1rem;
|
||||
.creator-info-item {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
color: $neutral-900;
|
||||
|
||||
.creator-info-label {
|
||||
font-weight: 700;
|
||||
width: 90px;
|
||||
}
|
||||
.creator-info-value {
|
||||
}
|
||||
}
|
||||
}
|
||||
.creator-info-3 {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 1rem;
|
||||
.creator-info-item {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
color: $neutral-900;
|
||||
gap: 0.5rem;
|
||||
|
||||
.creator-info-label {
|
||||
font-weight: 700;
|
||||
padding: 0.45rem;
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.mail {
|
||||
background-color: $primary-500;
|
||||
}
|
||||
&.social {
|
||||
background-color: $secondary-500;
|
||||
}
|
||||
&.link {
|
||||
background-color: $info-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.creator-data {
|
||||
width: 65%;
|
||||
background: #ffffffff; /* white */
|
||||
border-radius: 8px; /* border-l */
|
||||
box-shadow: 0px 0px 1px #171a1f12, 0px 0px 2px #171a1f1f; /* shadow-xs */
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
gap: 1rem;
|
||||
|
||||
.levels {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
.level-item {
|
||||
flex: 1;
|
||||
text-align: start;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
gap: 1rem;
|
||||
.name {
|
||||
font-weight: 700;
|
||||
}
|
||||
.value {
|
||||
border-radius: 1rem;
|
||||
background-color: $primary-100;
|
||||
color: $primary;
|
||||
font-size: .75rem;
|
||||
line-height: 1.5;
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.data-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: .5rem;
|
||||
.data-card {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: $neutral-150;
|
||||
border-radius: 6px;
|
||||
padding: 12px 0;
|
||||
.value {
|
||||
font-weight: 700;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
.name {
|
||||
color: $neutral-500;
|
||||
}
|
||||
}
|
||||
}
|
||||
.data-charts {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
.data-chart {
|
||||
flex: 1;
|
||||
.chart-title {
|
||||
font-weight: 700;
|
||||
color: $neutral-900;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
canvas {
|
||||
max-width: 260px;
|
||||
max-height: 260px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
gap: 0.5rem;
|
||||
flex: 1;
|
||||
|
||||
&.filter-views {
|
||||
&.filter-range-slider {
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
gap: 1rem;
|
||||
|
@ -36,7 +36,8 @@
|
||||
}
|
||||
|
||||
.creator-name {
|
||||
font-weight: 500;
|
||||
font-weight: 700;
|
||||
color: #090909
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
position: absolute;
|
||||
height: 5px;
|
||||
border-radius: 3px;
|
||||
background-color: $indigo-500;
|
||||
background-color: $primary;
|
||||
}
|
||||
|
||||
&__steps {
|
||||
@ -65,8 +65,8 @@
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&.active {
|
||||
background-color: $indigo-500;
|
||||
border-color: $indigo-500;
|
||||
background-color: $primary;
|
||||
border-color: $primary;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
@ -83,7 +83,7 @@
|
||||
transform: translateX(-50%);
|
||||
font-size: 0.75rem;
|
||||
color: white;
|
||||
background-color: $indigo-500;
|
||||
background-color: $primary;
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
white-space: nowrap;
|
||||
@ -100,7 +100,7 @@
|
||||
height: 0;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
border-bottom: 5px solid $indigo-500;
|
||||
border-bottom: 5px solid $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,13 +123,13 @@
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
border: 2px solid $indigo-500;
|
||||
border: 2px solid $primary;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: $indigo-500;
|
||||
background-color: $primary;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
@ -146,13 +146,13 @@
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: white;
|
||||
border: 2px solid $indigo-500;
|
||||
border: 2px solid $primary;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: $indigo-500;
|
||||
background-color: $primary;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@
|
||||
/* For Chrome browsers */
|
||||
.thumb::-webkit-slider-thumb {
|
||||
background-color: #fff;
|
||||
border: 2px solid $indigo-500;
|
||||
border: 2px solid $primary;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
@ -204,7 +204,7 @@
|
||||
/* For Firefox browsers */
|
||||
.thumb::-moz-range-thumb {
|
||||
background-color: #fff;
|
||||
border: 2px solid $indigo-500;
|
||||
border: 2px solid $primary;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
|
@ -1,26 +1,183 @@
|
||||
// 主题颜色变量
|
||||
$primary: #636AE8FF; // 靛蓝色
|
||||
$secondary: #6c757d; // 灰色
|
||||
$success: #198754; // 绿色
|
||||
$info: #0dcaf0; // 浅蓝色
|
||||
$warning: #ffc107; // 黄色
|
||||
$danger: #dc3545; // 红色
|
||||
$light: #f8f9fa; // 浅色
|
||||
$dark: #212529; // 深色
|
||||
|
||||
// 自定义颜色变量
|
||||
$primary-100: #F2F2FDFF;
|
||||
$primary-150: #E0E1FAFF;
|
||||
$primary-200: #CED0F8FF;
|
||||
$primary-250: #BCBFF5FF;
|
||||
$primary-300: #ABAEF2FF;
|
||||
$primary-350: #999DF0FF;
|
||||
$primary-400: #878CEDFF;
|
||||
$primary-450: #757BEAFF;
|
||||
$primary-500: #636AE8FF;
|
||||
$indigo-50: #eef2ff;
|
||||
$indigo-100: #e0e7ff;
|
||||
$indigo-500: #6366f1;
|
||||
$violet-50: #f5f3ff;
|
||||
$violet-100: #ede9fe;
|
||||
$violet-400: #a78bfa;
|
||||
$primary-550: #4850E4FF;
|
||||
$primary-600: #2C35E0FF;
|
||||
$primary-650: #1F27CDFF;
|
||||
$primary-700: #1B22B1FF;
|
||||
$primary-750: #161D96FF;
|
||||
$primary-800: #12177AFF;
|
||||
$primary-850: #0E125EFF;
|
||||
$primary-900: #0A0D42FF;
|
||||
$primary: #636AE8FF;
|
||||
|
||||
$secondary-100: #FDF1F5FF;
|
||||
$secondary-150: #FBE0E8FF;
|
||||
$secondary-200: #F8CEDBFF;
|
||||
$secondary-250: #F5BCCEFF;
|
||||
$secondary-300: #F3AAC1FF;
|
||||
$secondary-350: #F098B4FF;
|
||||
$secondary-400: #EE86A7FF;
|
||||
$secondary-450: #EB759AFF;
|
||||
$secondary-500: #E8618CFF;
|
||||
$secondary-550: #E44578FF;
|
||||
$secondary-600: #E02862FF;
|
||||
$secondary-650: #C91D53FF;
|
||||
$secondary-700: #AC1947FF;
|
||||
$secondary-750: #8E143BFF;
|
||||
$secondary-800: #71102FFF;
|
||||
$secondary-850: #530C22FF;
|
||||
$secondary-900: #360816FF;
|
||||
$secondary: #E8618CFF;
|
||||
|
||||
$info-100: #F1F8FDFF;
|
||||
$info-150: #DAECFAFF;
|
||||
$info-200: #C3E1F8FF;
|
||||
$info-250: #ACD5F5FF;
|
||||
$info-300: #94C9F2FF;
|
||||
$info-350: #7DBEEFFF;
|
||||
$info-400: #66B2ECFF;
|
||||
$info-450: #4FA6E9FF;
|
||||
$info-500: #379AE6FF;
|
||||
$info-550: #1D8DE3FF;
|
||||
$info-600: #197DCAFF;
|
||||
$info-650: #166DB0FF;
|
||||
$info-700: #125D95FF;
|
||||
$info-750: #0F4C7BFF;
|
||||
$info-800: #0C3C61FF;
|
||||
$info-850: #092C47FF;
|
||||
$info-900: #061C2DFF;
|
||||
$info: #379AE6FF;
|
||||
|
||||
$warning-100: #FEF9EEFF;
|
||||
$warning-150: #FCF0D7FF;
|
||||
$warning-200: #FAE7C0FF;
|
||||
$warning-250: #F8DEA9FF;
|
||||
$warning-300: #F6D491FF;
|
||||
$warning-350: #F4CB7AFF;
|
||||
$warning-400: #F2C263FF;
|
||||
$warning-450: #F0B94BFF;
|
||||
$warning-500: #EFB034FF;
|
||||
$warning-550: #ECA517FF;
|
||||
$warning-600: #D29211FF;
|
||||
$warning-650: #B57E0FFF;
|
||||
$warning-700: #98690CFF;
|
||||
$warning-750: #7A550AFF;
|
||||
$warning-800: #5D4108FF;
|
||||
$warning-850: #402C05FF;
|
||||
$warning-900: #221803FF;
|
||||
$warning: #EFB034FF;
|
||||
|
||||
$danger-100: #FDF2F2FF;
|
||||
$danger-150: #F9DBDCFF;
|
||||
$danger-200: #F5C4C6FF;
|
||||
$danger-250: #F1ADAF;
|
||||
$danger-300: #ED9699FF;
|
||||
$danger-350: #E97F83FF;
|
||||
$danger-400: #E5696DFF;
|
||||
$danger-450: #E25256FF;
|
||||
$danger-500: #DE3B40FF;
|
||||
$danger-550: #D9252BFF;
|
||||
$danger-600: #C12126FF;
|
||||
$danger-650: #AA1D22FF;
|
||||
$danger-700: #93191DFF;
|
||||
$danger-750: #7B1518FF;
|
||||
$danger-800: #641114FF;
|
||||
$danger-850: #4D0D0FFF;
|
||||
$danger-900: #36090BFF;
|
||||
$danger: #DE3B40FF;
|
||||
|
||||
$success-100: #EEFDF3FF;
|
||||
$success-150: #D3F9E0FF;
|
||||
$success-200: #B8F5CDFF;
|
||||
$success-250: #9DF2B9FF;
|
||||
$success-300: #82EEA6FF;
|
||||
$success-350: #67EA93FF;
|
||||
$success-400: #4CE77FFF;
|
||||
$success-450: #31E36CFF;
|
||||
$success-500: #1DD75BFF;
|
||||
$success-550: #1AC052FF;
|
||||
$success-600: #17A948FF;
|
||||
$success-650: #14923EFF;
|
||||
$success-700: #117B34FF;
|
||||
$success-750: #0E642AFF;
|
||||
$success-800: #0A4D20FF;
|
||||
$success-850: #073517FF;
|
||||
$success-900: #041E0DFF;
|
||||
$success: #1DD75BFF;
|
||||
|
||||
$color-3-100: #EFFCFAFF;
|
||||
$color-3-150: #D4F8F2FF;
|
||||
$color-3-200: #BAF3EBFF;
|
||||
$color-3-250: #9FEFE3FF;
|
||||
$color-3-300: #84EADBFF;
|
||||
$color-3-350: #69E6D3FF;
|
||||
$color-3-400: #4EE1CBFF;
|
||||
$color-3-450: #33DCC3FF;
|
||||
$color-3-500: #22CCB2FF;
|
||||
$color-3-550: #1FB7A0FF;
|
||||
$color-3-600: #1BA18DFF;
|
||||
$color-3-650: #188B7AFF;
|
||||
$color-3-700: #147567FF;
|
||||
$color-3-750: #105F53FF;
|
||||
$color-3-800: #0C4940FF;
|
||||
$color-3-850: #09332DFF;
|
||||
$color-3-900: #051D1AFF;
|
||||
$color-3: #22CCB2FF;
|
||||
|
||||
$color-4-100: #F5F2FDFF;
|
||||
$color-4-150: #E7DFF9FF;
|
||||
$color-4-200: #D8CBF5FF;
|
||||
$color-4-250: #C9B8F2FF;
|
||||
$color-4-300: #BBA4EEFF;
|
||||
$color-4-350: #AC91EBFF;
|
||||
$color-4-400: #9D7EE7FF;
|
||||
$color-4-450: #8F6AE4FF;
|
||||
$color-4-500: #7F55E0FF;
|
||||
$color-4-550: #6D3EDCFF;
|
||||
$color-4-600: #5B27D5FF;
|
||||
$color-4-650: #5123BCFF;
|
||||
$color-4-700: #461EA4FF;
|
||||
$color-4-750: #3B198BFF;
|
||||
$color-4-800: #311572FF;
|
||||
$color-4-850: #261059FF;
|
||||
$color-4-900: #1C0C40FF;
|
||||
$color-4: #7F55E0FF;
|
||||
|
||||
$color-5-100: #FDF5F1FF;
|
||||
$color-5-150: #FBE8E1FF;
|
||||
$color-5-200: #F8DBD0FF;
|
||||
$color-5-250: #F6CFBFFF;
|
||||
$color-5-300: #F4C2AFFF;
|
||||
$color-5-350: #F1B59EFF;
|
||||
$color-5-400: #EFA98DFF;
|
||||
$color-5-450: #EC9C7CFF;
|
||||
$color-5-500: #EA916EFF;
|
||||
$color-5-550: #E5784CFF;
|
||||
$color-5-600: #E1602CFF;
|
||||
$color-5-650: #CC4F1DFF;
|
||||
$color-5-700: #AC4219FF;
|
||||
$color-5-750: #8D3614FF;
|
||||
$color-5-800: #6D2A10FF;
|
||||
$color-5-850: #4D1E0BFF;
|
||||
$color-5-900: #2D1206FF;
|
||||
$color-5: #EA916EFF;
|
||||
|
||||
$neutral-150: #f8f9faff;
|
||||
$neutral-200: #f3f4f6ff;
|
||||
$neutral-300: #DEE1E6FF; /* neutral-300 */;
|
||||
$neutral-350: #cfd2daff;
|
||||
$neutral-500: #9095A0FF;
|
||||
$neutral-600: #565e6cff;
|
||||
$neutral-700: #323842ff;
|
||||
$neutral-900: #171a1fff;
|
||||
|
@ -55,7 +55,7 @@ a {
|
||||
.table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
|
||||
border: 1px solid #171a1f1f;
|
||||
th {
|
||||
background-color: #f8f9fa;
|
||||
border-top: none;
|
||||
|
@ -24,3 +24,7 @@
|
||||
gap: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.back-button {
|
||||
cursor: pointer;
|
||||
}
|
Loading…
Reference in New Issue
Block a user