提交 4608ddae 作者: ZhangLingKun

Merge branch 'review'

流水线 #7879 已失败 于阶段
in 3 分 50 秒
......@@ -3,7 +3,9 @@
"es6": true,
"node": true
},
"plugins": ["prettier"],
"plugins": [
"prettier"
],
"extends": [
"airbnb-base",
"next/core-web-vitals",
......@@ -16,15 +18,25 @@
"prettier/prettier": [
"error",
{
"singleQuote": true
"singleQuote": true,
"endOfLine": "auto",
"plugins": [
"prettier-plugin-tailwindcss"
]
}
]
},
"overrides": [
// Configuration for TypeScript files
{
"files": ["**/*.ts", "**/*.tsx"],
"plugins": ["@typescript-eslint", "unused-imports"],
"files": [
"**/*.ts",
"**/*.tsx"
],
"plugins": [
"@typescript-eslint",
"unused-imports"
],
"extends": [
"airbnb-typescript",
"next/core-web-vitals",
......@@ -34,22 +46,24 @@
"project": "./tsconfig.json"
},
"rules": {
"prettier/prettier": [
"error",
{
"singleQuote": true,
"endOfLine": "auto"
}
],
"react/destructuring-assignment": "off", // Vscode doesn't support automatically destructuring, it's a pain to add a new variable
"jsx-a11y/anchor-is-valid": "off", // Next.js use his own internal link system
"react/require-default-props": "off", // Allow non-defined react props as undefined
"react/jsx-props-no-spreading": "off", // _app.tsx uses spread operator and also, react-hook-form
"@next/next/no-img-element": "off", // We currently not using next/image because it isn't supported with SSG mode
"react/destructuring-assignment": "off",
// Vscode doesn't support automatically destructuring, it's a pain to add a new variable
"jsx-a11y/anchor-is-valid": "off",
// Next.js use his own internal link system
"react/require-default-props": "off",
// Allow non-defined react props as undefined
"react/jsx-props-no-spreading": "off",
// _app.tsx uses spread operator and also, react-hook-form
"@next/next/no-img-element": "off",
// We are currently not using next/image because it isn't supported with SSG mode
"import/order": [
"error",
{
"groups": ["builtin", "external", "internal"],
"groups": [
"builtin",
"external",
"internal"
],
"pathGroups": [
{
"pattern": "react",
......@@ -57,7 +71,9 @@
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["react"],
"pathGroupsExcludedImportTypes": [
"react"
],
"newlines-between": "never",
"alphabetize": {
"order": "asc",
......@@ -66,14 +82,19 @@
}
],
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/comma-dangle": "off", // Avoid conflict rule between Eslint and Prettier
"import/prefer-default-export": "off", // Named export is easier to refactor automatically
"class-methods-use-this": "off", // _document.tsx use render method without `this` keyword
"@typescript-eslint/comma-dangle": "off",
// Avoid conflict rule between Eslint and Prettier
"import/prefer-default-export": "off",
// Named export is easier to refactor automatically
"class-methods-use-this": "off",
// _document.tsx use render method without `this` keyword
"@typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "warn",
"unused-imports/no-unused-vars": [
"warn",
{ "argsIgnorePattern": "^_" }
{
"argsIgnorePattern": "^_"
}
],
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-static-element-interactions": "off",
......
......@@ -14,4 +14,4 @@ patches:
images:
- name: REGISTRY/NAMESPACE/IMAGE:TAG
newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/web
newTag: 818d779104308947c9cbd3615a4c3b39910c794c
newTag: 8a764a4e7eecfcfbb9106015e461aaa32e732755
......@@ -49,6 +49,7 @@
"@types/react-dom": "^18.2.15",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"autoprefixer": "^10.4.16",
"cross-env": "^7.0.3",
"eslint": "^8",
"eslint-config-airbnb-base": "^15.0.0",
......@@ -57,8 +58,11 @@
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"eslint-plugin-unused-imports": "^3.0.0",
"postcss": "^8.4.32",
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.10",
"sass": "^1.69.5",
"tailwindcss": "^3.4.0",
"typescript": "^5"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
......@@ -89,3 +89,19 @@ export type GetAccountInfo = InterFunction<
createTime: string;
}
>;
// 测试-手机号登录
export type TestPhoneLogin = InterFunction<
{
phone: string;
},
{
authStatus: null;
nickName: string;
phoneNum: string;
portType: number;
sessionKey: null;
token: string;
uid: string;
userAccountId: number;
}
>;
......@@ -2,6 +2,7 @@ import {
GetAccountInfo,
GetAppletQRCode,
GetLoginInfo,
TestPhoneLogin,
} from '@/api/interface/common';
import request from '../request';
......@@ -25,4 +26,8 @@ export class CommonAPI {
// 获取用户信息
static getAccountInfo: GetAccountInfo = (params) =>
request.get('/userapp/user-account/info', { params });
// 测试-手机号登录
static testPhoneLogin: TestPhoneLogin = (params) =>
request.get('/userapp/auth/testPhoneLogin', { params });
}
......@@ -56,14 +56,15 @@ service.interceptors.response.use(
const isServer = typeof window === 'undefined';
if (isServer) {
// 如果是服务端
return Promise.reject(data);
// eslint-disable-next-line no-alert
window.confirm(data.message || '啊呀,出错了');
// window.confirm(data.message || '啊呀,出错了');
// eslint-disable-next-line no-restricted-globals
history.back();
} else {
// 如果还有其他报错那么就弹出报错信息(不需要对每个接口的报错做单独判断)
message.error(data.message || '啊呀,出错了').then();
// history.back();
}
// 如果还有其他报错那么就弹出报错信息(不需要对每个接口的报错做单独判断)
message.error(data.message || '啊呀,出错了').then();
return Promise.reject(data);
}
// 网络错误或链接超时
......
......@@ -31,6 +31,8 @@ const BreadcrumbView: React.FC = () => {
{ name: '购物车', path: 'cart' },
{ name: '提交订单', path: 'submit' },
{ name: '服务详情', path: 'detail' },
{ name: '产品订单', path: 'order' },
{ name: '提交成功', path: 'success' },
];
// 转换路由
const getCurrentRouter = () => {
......
......@@ -134,14 +134,18 @@ const CategorySelectView: React.FC<{
</div>
<div className="category-list flex-start">
<div
className={`list-item ${secondIndex?.length === 0 && 'item-active'}`}
className={`list-item list-none ${
secondIndex?.length === 0 && 'item-active'
}`}
onClick={handleAll}
>
{allText || '全部商品'}
</div>
{list[currentIndex]?.children?.map((i, j) => (
<div
className={`list-item ${secondIndex?.includes(j) && 'item-active'}`}
className={`list-item list-none ${
secondIndex?.includes(j) && 'item-active'
}`}
key={j}
onClick={() => handleSecondary(j)}
>
......
......@@ -131,7 +131,7 @@ const HomeNewsView = () => {
{refresh &&
tabList?.[currentIndex]?.value?.map((i, j) => (
<div
className="list-item animate__animated animate__fast animate__fadeIn flex-start"
className="animate__animated animate__fast animate__fadeIn flex-start list-item"
key={j}
>
<div
......
import React, { useEffect, useState } from 'react';
import { ReloadOutlined } from '@ant-design/icons';
import { message, Modal } from 'antd';
import Cookies from 'js-cookie';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { CommonAPI } from '@/api';
import { RootState } from '@/store';
import { GlobalDataState } from '@/store/module/globalData';
import { setSystem } from '@/store/module/system';
import { setUserInfo } from '@/store/module/userInfo';
export const LoginModalWrap = styled.div`
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
box-sizing: border-box;
padding: 0.68rem 0;
.qrcode {
position: relative;
width: 10.68rem;
height: 10.68rem;
margin: 1.5rem 0 1rem 0;
//background-image: url('https://file.iuav.com/file/sharefly-qrcode-wx.jpg');
//background-size: 100% 100%;
//background-size: cover;
//background-position: center;
.image {
width: 100%;
height: 100%;
object-fit: cover;
}
.shadow {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
flex-direction: column;
background: rgba(0, 0, 0, 0.68);
.refresh {
position: relative;
width: 3rem;
height: 3rem;
border-radius: 50%;
background: #fff;
margin-bottom: 1rem;
&:active {
filter: brightness(0.9);
transform: rotate(360deg);
transition: all 0.3s ease-in-out;
}
}
.text {
color: #fff;
}
}
}
.title {
color: #222;
font-size: 16px;
font-weight: bold;
}
.text {
color: #333;
font-size: 12px;
line-height: 20px;
text-align: center;
}
.action {
color: #999;
font-size: 12px;
line-height: 20px;
text-align: center;
margin: 1rem 0;
text-decoration: underline;
cursor: pointer;
&:hover,
&:active {
color: #ff552d;
}
}
`;
// 定时器暂存
let timer: NodeJS.Timer;
const LoginModalView = ({
open,
onCancel,
}: {
open: boolean;
onCancel: () => void;
}) => {
// system
const globalData = useSelector(
(state: RootState) => state.globalData,
) as GlobalDataState;
// store
const dispatch = useDispatch();
// 获取小程序二维码唯一标识
const [randomLoginCode, setRandomLoginCode] = useState<string>(
`${parseInt(String(Math.random() * 10001), 10)}`,
);
// 二维码是否过期
const [qrCodeExpired, setQrCodeExpired] = useState<boolean>(false);
// 登录二维码的地址
const [qrCodeData, setQrCodeData] = useState<string>();
// 获取登录二维码
const getQrcodeLogin = async () => {
// 获取二维码
const res = await CommonAPI.getAppletQRCode({
page: 'page-identity/identity-empower/index',
scene: `randomLoginCode=${randomLoginCode}&port=0`,
});
if (res && res.code === '200') {
if (!res.result) {
message.warning('获取登录二维码失败');
return;
}
// 设置当前登录的二维码
setQrCodeData(`data:image/png;base64,${res.result}`);
// 设置二维码倒计时
setQrCodeExpiredTimer();
}
};
// 跳转管理平台
const handleBackEnd = () => {
window.open('https://admin.iuav.com');
};
// 刷新二维码
const handleRefresh = () => {
setRandomLoginCode(`${parseInt(String(Math.random() * 10001), 10)}`);
getQrcodeLogin().then(() => {
setQrCodeExpired(false);
});
};
// 定时器设置二维码过期
const setQrCodeExpiredTimer = () => {
setTimeout(
() => {
setQrCodeExpired(true);
// 关闭定时器
if (timer) clearInterval(timer);
},
1000 * 60 * 5,
);
};
// 获取登录信息
const getLoginInfo = async () => {
if (!randomLoginCode) return;
const res = await CommonAPI.getLoginInfo({
randomLoginCode,
});
// console.log('获取登录信息 --->', res);
if (res && res.code === '200') {
// 关闭定时器
if (timer) clearInterval(timer);
// 刷新二维码
setQrCodeExpired(true);
// 关闭弹窗
onCancel?.();
// 设置用户信息
dispatch(setUserInfo(res.result));
// 设置token
dispatch(setSystem({ token: res.result.token }));
// 设置token
Cookies.set('SHAREFLY-WEB-TOKEN', res.result.token);
message.success('登录成功');
// 刷新当前页面
window.location.reload();
}
};
// 设置定时器轮询获取信息
const setLoginInfoTimer = () => {
timer = setInterval(async () => {
await getLoginInfo();
}, 2500);
};
// 关闭弹窗
const handleClose = () => {
onCancel?.();
// 关闭定时器
if (timer) clearInterval(timer);
};
// 组件挂载
useEffect(() => {
if (!open) {
// 关闭定时器
if (timer) clearInterval(timer);
return;
}
// 获取二维码
getQrcodeLogin().then(() => {
setQrCodeExpired(false);
setLoginInfoTimer();
});
}, [open]);
return (
<Modal open={open} footer={null} onCancel={handleClose}>
<LoginModalWrap>
<div className="title">
{globalData?.loginModalTitle || `微信扫码登录`}
</div>
<div className="qrcode">
{qrCodeData && (
<img src={qrCodeData} alt="登录二维码" className="image" />
)}
{qrCodeExpired && (
<div className="flex-center animate__animated animate__fast animate__fadeIn shadow">
<div className="refresh flex-center" onClick={handleRefresh}>
<ReloadOutlined style={{ fontSize: '20px' }} />
</div>
<div className="text">二维码已过期,请重新扫描</div>
</div>
)}
</div>
<div className="text">微信扫一扫,打开小程序</div>
<div className="text">即可登录/注册</div>
<div
className="action"
onClick={handleBackEnd}
style={{ visibility: 'hidden' }}
>
管理平台登录 {'>'}
</div>
<div className="text">「云享飞,让天空为世界所用」</div>
</LoginModalWrap>
</Modal>
);
};
export default LoginModalView;
......@@ -94,7 +94,7 @@ const MapContainer: FC<{
return (
<div
id="container"
className={'container animate__animated animate__fast animate__fadeIn'}
className={'animate__animated animate__fast animate__fadeIn container'}
style={{
height: '100%',
padding: 0,
......
......@@ -124,9 +124,12 @@ const PaymentCheckout: React.FC<{ cost: number }> = ({ cost }) => {
useEffect(() => {
if (!system?.token) return;
getUserPayWalletInfo().then();
}, [cost]);
// 钱包金额副作用
useEffect(() => {
if (!cost) return;
setDefaultSelect();
}, [cost]);
}, [walletInfo]);
return (
<PaymentCheckoutWrap>
<Checkbox.Group value={paymentTypeValue} onChange={setPaymentTypeValue}>
......
import React from 'react';
import { Input, Modal } from 'antd';
import { Input, message, Modal } from 'antd';
import Big from 'big.js';
import { GetServerSidePropsContext } from 'next';
import { useRouter } from 'next/router';
......@@ -79,14 +79,12 @@ const MallCartSubmitView: React.FC<{
content: `确认提交订单?`,
onOk: () => {
dispatch(setGlobalData({ loadingSpinnerVisible: true }));
setTimeout(() => {
dispatch(
setGlobalData({
toastModalVisible: true,
toastModalBack: true,
loadingSpinnerVisible: false,
}),
);
setTimeout(async () => {
dispatch(setGlobalData({ loadingSpinnerVisible: false }));
await Promise.all([
message.success('订单提交成功'),
router.push('/order/success/236'),
]);
}, 1000);
},
});
......@@ -147,7 +145,7 @@ const MallCartSubmitView: React.FC<{
<PaymentCheckout cost={getCheckoutPrice()} />
</div>
<div
className="checkout-submit select-none cursor-pointer"
className="checkout-submit cursor-pointer select-none"
onClick={handleSubmit}
>
{router?.query?.type === '1' ? '提交订单' : '提交意向'}
......@@ -169,10 +167,11 @@ const MallCartSubmitWrap = styled.div`
.submit-remark {
position: relative;
width: 100%;
min-height: 4.5rem;
min-height: 4rem;
background: #f2f7ff;
border: 0.04rem solid #d0eaf5;
padding: 0.67rem;
padding: 0.67rem 0.67rem 1.3rem 0.67rem;
box-sizing: border-box;
margin-bottom: 1rem;
.remark-view {
position: relative;
......
......@@ -27,6 +27,6 @@ export async function getServerSideProps() {
}
const MallSecondView: React.FC<{
categoryList: CategoryListType;
}> = (props) => MallView(props);
}> = (props) => <MallView {...props} />;
export default MallSecondView;
......@@ -27,6 +27,6 @@ export async function getServerSideProps() {
}
const MallMainView: React.FC<{
categoryList: CategoryListType;
}> = (props) => MallView(props);
}> = (props) => <MallView {...props} />;
export default MallMainView;
import React, { useEffect, useState } from 'react';
import { CheckCircleFilled } from '@ant-design/icons';
import { Button } from 'antd';
import styled from 'styled-components';
import { HomeAPI } from '@/api';
import { InterDataType } from '@/api/interface';
import { RecommendGoodsType } from '@/api/interface/home';
import BreadcrumbView from '@/components/breadcrumb';
import LayoutView from '@/components/layout';
import ProductItemView from '@/components/productItem';
// 列表类型
type ListType = InterDataType<RecommendGoodsType>;
const OrderSuccessView = () => {
// 推荐商品列表
const [recommendGoodsList, setRecommendGoodsList] = useState<
ListType[0]['mallGoodsList']
>([]);
// 获取推荐商品
const getRecommendGoodsList = async () => {
const res = await HomeAPI.getRecommendGoods();
if (res && res.code === '200') {
const list = res.result || [];
setRecommendGoodsList(
list
?.map((i) => i.mallGoodsList)
?.flat()
?.slice(0, 10),
);
}
};
// 页面加载
useEffect(() => {
getRecommendGoodsList().then();
}, []);
return (
<LayoutView>
<OrderSuccessWrap>
<BreadcrumbView />
<div className="order-success">
<div className="success-title">
<CheckCircleFilled className="text-3xl text-[#54A536]" />
<div className="title">您已成功付款</div>
</div>
<div className="success-content">
<div className="content-item mb-2 flex">
<div className="item-label">收货地址:</div>
<div className="item-value">
浙江省杭州市富阳区银湖街道富闲路15号浙大网新银湖科技园25幢{' '}
吴彦祖 18888888888
</div>
</div>
<div className="content-item mb-2 flex">
<div className="item-label">实付款:</div>
<div className="item-value price">¥19.9</div>
</div>
<Button type="link" className="mb-2 px-0">
查看订单
</Button>
</div>
</div>
<div className="order-product">
{recommendGoodsList?.map((i, j) => (
<ProductItemView key={j} detail={i as any} />
))}
</div>
</OrderSuccessWrap>
</LayoutView>
);
};
export default OrderSuccessView;
// 样式
const OrderSuccessWrap = styled.div`
position: relative;
max-width: 1190px;
box-sizing: border-box;
padding: 2rem 0 0 0;
margin: 0 auto;
.order-success {
position: relative;
width: 100%;
box-sizing: border-box;
min-height: 8.25rem;
border: 0.02rem solid #e3e3e3;
margin-bottom: 1rem;
.success-title {
position: relative;
width: 100%;
height: 3.5rem;
background: #ecffdc;
display: flex;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
padding: 0 5rem;
margin-bottom: 1rem;
.title {
font-size: 16px;
font-weight: bold;
margin-left: 1rem;
}
}
.success-content {
position: relative;
width: 100%;
box-sizing: border-box;
padding: 0 5rem;
color: #999999;
.price {
color: #ea0000;
font-weight: bold;
}
}
}
.order-product {
position: relative;
width: 100%;
box-sizing: border-box;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
margin-bottom: 1rem;
}
`;
import React, { useEffect, useState } from 'react';
import { Button, Checkbox, Col, Form, Input, message, Row } from 'antd';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import LayoutView from '@/components/layout';
import { RootState } from '@/store';
import { setGlobalData } from '@/store/module/globalData';
import { SystemState } from '@/store/module/system';
const UserSignupView = () => {
// store
const dispatch = useDispatch();
// system
const system = useSelector((state: RootState) => state.system) as SystemState;
// 表单钩子
const [formRef] = Form.useForm<{
password: string;
username: string;
code: string;
}>();
// 是否选择协议
const [checkValue, setCheckValue] = useState<boolean>(false);
// 提交数据
const handleSubmit = async () => {
if (!checkValue) {
await message.warning('请先阅读并接受用户协议和隐私协议');
return;
}
const values = await formRef.validateFields().catch((err) => {
Promise.all(
err?.errorFields?.map((i: { errors: string[] }) =>
message.warning(i?.errors[0]),
),
);
});
if (!values) return;
message.loading('注册中...');
};
// 跳转回登录
const handleLogin = () => {
dispatch(setGlobalData({ loginModalVisible: true }));
};
// 获取二维码
const handleGetCode = async () => {
await message.loading('获取中...');
};
// 页面挂载
useEffect(() => {
if (!system?.token) return;
// 如果有token则跳转回首页
window.location.href = '/';
}, [system]);
return (
<LayoutView placeholder={false}>
<UserSignupBg />
<UserSignupWrap>
<div className="login-title"></div>
<div className="login-box">
<div className="title">欢迎注册</div>
<div className="already mb-14">
<span>已有账号?</span>
<span className="bold cursor-pointer" onClick={handleLogin}>
登录
</span>
</div>
<Form
name="signForm"
form={formRef}
autoComplete="off"
className="w-full"
size="large"
labelAlign="left"
labelCol={{ span: 4 }}
>
<Form.Item
label="手机号"
name="username"
required={false}
rules={[{ required: true, message: '请输入登录的账号' }]}
>
<Input placeholder="请输入手机号" maxLength={11} allowClear />
</Form.Item>
<Form.Item
label="密码"
name="password"
required={false}
rules={[{ required: true, message: '请输入密码' }]}
>
<Input
placeholder="请输入密码"
type="password"
maxLength={20}
allowClear
autoComplete="new-password"
/>
</Form.Item>
<Form.Item label="验证码">
<Row gutter={8}>
<Col span={15}>
<Form.Item
name="code"
noStyle
rules={[
{
required: true,
message: '请输入验证码',
},
]}
>
<Input
placeholder="请输入验证码"
maxLength={8}
allowClear
/>
</Form.Item>
</Col>
<Col span={8}>
<Button onClick={handleGetCode}>获取验证码</Button>
</Col>
</Row>
</Form.Item>
</Form>
<div
className={`submit mt-14 cursor-pointer ${checkValue && 'active'}`}
onClick={handleSubmit}
>
立即注册
</div>
<div className="checkbox mt-4">
<Checkbox
checked={checkValue}
onChange={(e) => setCheckValue(e.target?.checked)}
>
<span>阅读并接受</span>
<span className="bold cursor-pointer">云享飞用户协议</span>
<span></span>
<span className="bold cursor-pointer">隐私协议</span>
</Checkbox>
</div>
</div>
</UserSignupWrap>
</LayoutView>
);
};
export default UserSignupView;
// 样式
const UserSignupWrap = styled.div`
position: relative;
height: 99.8vh;
max-width: 1190px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
padding: 0 5% 0 0;
.login-title {
position: absolute;
top: 15%;
left: 0;
width: 9.25rem;
height: 2.08rem;
background-image: url('https://file.iuav.com/file/sharefly-signup-title.png');
background-size: cover;
}
.login-box {
position: relative;
width: 23.29rem;
height: 28.5rem;
background: rgba(255, 255, 255, 0.86);
border-radius: 0.58rem;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 1.83rem 1.83rem 0;
.title {
position: relative;
width: 100%;
font-size: 20px;
font-weight: bold;
color: #333333;
letter-spacing: 1px;
margin-bottom: 0.2rem;
}
.already {
position: relative;
width: 100%;
color: #999999;
.bold {
color: #fd562c;
}
}
.submit {
position: relative;
box-sizing: border-box;
width: 19.38rem;
height: 2.5rem;
background: #ffab95;
border-radius: 1.29rem;
text-align: center;
line-height: 2.25rem;
color: #ffffff;
}
.active {
background: #fd562c;
}
.checkbox {
.bold {
color: #fd562c;
margin: 0 0.25rem;
}
}
}
@media screen and (max-width: 1200px) {
padding: 0;
justify-content: center;
}
@media screen and (min-width: 1550px) {
padding: 0;
}
`;
// 图片
const UserSignupBg = styled.div`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 99.8vh;
background-image: url('https://file.iuav.com/file/sharefly-signup-bg.png');
background-size: cover;
`;
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--default-padding: 0 12rem;
--max-width: 1100px;
......
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{js,ts,jsx,tsx,mdx}',
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
// Or if using `src` directory:
'./src/**/*.{js,ts,jsx,tsx,mdx}',
],
corePlugins: {
preflight: false,
},
theme: {
extend: {
screens: {
xl: '1190px',
},
colors: {
333: '#333',
777: '#777',
999: '#999',
aaa: '#aaa',
},
},
},
plugins: [],
};
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论