feat: notifications, redux, tailwind
This commit is contained in:
16
src/.storybook/main.ts
Normal file
16
src/.storybook/main.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import type { StorybookConfig } from '@storybook/nextjs';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
core: {
|
||||
disableWhatsNewNotifications: true,
|
||||
disableTelemetry: true,
|
||||
enableCrashReports: false,
|
||||
},
|
||||
stories: ['../components/**/*.(stories|story).@(js|jsx|ts|tsx)'],
|
||||
addons: ['storybook-dark-mode'],
|
||||
framework: {
|
||||
name: '@storybook/nextjs',
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
36
src/.storybook/preview.tsx
Normal file
36
src/.storybook/preview.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import '@mantine/core/styles.css';
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { addons } from '@storybook/preview-api';
|
||||
import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';
|
||||
import { MantineProvider, useMantineColorScheme } from '@mantine/core';
|
||||
import { theme } from '../theme';
|
||||
|
||||
export const parameters = {
|
||||
layout: 'fullscreen',
|
||||
options: {
|
||||
showPanel: false,
|
||||
storySort: (a, b) => {
|
||||
return a.title.localeCompare(b.title, undefined, { numeric: true });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const channel = addons.getChannel();
|
||||
|
||||
function ColorSchemeWrapper({ children }: { children: React.ReactNode }) {
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
const handleColorScheme = (value: boolean) => setColorScheme(value ? 'dark' : 'light');
|
||||
|
||||
useEffect(() => {
|
||||
channel.on(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||
return () => channel.off(DARK_MODE_EVENT_NAME, handleColorScheme);
|
||||
}, [channel]);
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export const decorators = [
|
||||
(renderStory: any) => <ColorSchemeWrapper>{renderStory()}</ColorSchemeWrapper>,
|
||||
(renderStory: any) => <MantineProvider theme={theme}>{renderStory()}</MantineProvider>,
|
||||
];
|
||||
7
src/app/global.css
Normal file
7
src/app/global.css
Normal file
@ -0,0 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
body {
|
||||
@mixin light {
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
@import "tailwind-preset-mantine";
|
||||
@import "./theme.css";
|
||||
@ -1,41 +1,54 @@
|
||||
import "@mantine/core/styles.css"
|
||||
import "@mantine/dates/styles.css"
|
||||
import "@mantine/notifications/styles.css"
|
||||
import '@mantine/dropzone/styles.css';
|
||||
|
||||
import React from "react"
|
||||
import "@mantine/core/styles.css";
|
||||
import "@mantine/notifications/styles.css";
|
||||
import React, { ReactNode } from "react";
|
||||
import {
|
||||
ColorSchemeScript,
|
||||
mantineHtmlProps,
|
||||
MantineProvider,
|
||||
} from "@mantine/core"
|
||||
import { theme } from "./theme"
|
||||
import "./globals.css"
|
||||
import { Notifications } from "@mantine/notifications"
|
||||
import { ModalsProvider } from "@mantine/modals"
|
||||
} from "@mantine/core";
|
||||
import { theme } from "@/theme";
|
||||
import "@/app/global.css";
|
||||
import { Notifications } from "@mantine/notifications";
|
||||
import ReduxProvider from "@/providers/ReduxProvider";
|
||||
|
||||
export const metadata = {
|
||||
title: "Mantine Next.js template",
|
||||
description: "I am using Mantine with Next.js!",
|
||||
}
|
||||
title: "CRM LogiDex",
|
||||
description: "CRM LogiDex",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: any }) {
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: Props) {
|
||||
return (
|
||||
<html lang="en" {...mantineHtmlProps}>
|
||||
<html
|
||||
lang="ru"
|
||||
{...mantineHtmlProps}>
|
||||
<head>
|
||||
<ColorSchemeScript />
|
||||
<link rel="shortcut icon" href="/favicon.svg" />
|
||||
<ColorSchemeScript defaultColorScheme={"auto"} />
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
href="/favicon.svg"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="global.css"
|
||||
/>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="minimum-scale=1, initial-scale=1, width=device-width, user-scalable=no"
|
||||
/>
|
||||
<title />
|
||||
</head>
|
||||
<body>
|
||||
<MantineProvider theme={theme}>
|
||||
<Notifications />
|
||||
<ModalsProvider>{children}</ModalsProvider>
|
||||
<MantineProvider
|
||||
theme={theme}
|
||||
defaultColorScheme={"auto"}>
|
||||
<ReduxProvider>{children}</ReduxProvider>
|
||||
<Notifications position="bottom-right" />
|
||||
</MantineProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,52 +1,11 @@
|
||||
import { ColorSchemesSwitcher } from "@/components/color-schemes-switcher"
|
||||
import {
|
||||
AppShell,
|
||||
AppShellHeader,
|
||||
AppShellMain,
|
||||
Text,
|
||||
Title,
|
||||
} from "@mantine/core"
|
||||
import { ColorSchemeToggle } from "@/components/ColorSchemeToggle/ColorSchemeToggle";
|
||||
import { Welcome } from "@/components/Welcome/Welcome";
|
||||
|
||||
export default function Home() {
|
||||
export default function HomePage() {
|
||||
return (
|
||||
<AppShell header={{ height: 60 }} padding="md">
|
||||
<AppShellHeader></AppShellHeader>
|
||||
<AppShellMain>
|
||||
<Title className="text-center mt-20">
|
||||
Welcome to{" "}
|
||||
<Text
|
||||
inherit
|
||||
variant="gradient"
|
||||
component="span"
|
||||
gradient={{ from: "pink", to: "yellow" }}
|
||||
>
|
||||
Mantine
|
||||
</Text>{" "}
|
||||
+
|
||||
<Text
|
||||
inherit
|
||||
variant="gradient"
|
||||
component="span"
|
||||
gradient={{ from: "blue", to: "green" }}
|
||||
>
|
||||
TailwindCSS
|
||||
</Text>
|
||||
</Title>
|
||||
<Text
|
||||
className="text-bold text-center text-gray-700 dark:text-gray-300 max-w-[500px] mx-auto mt-xl"
|
||||
ta="center"
|
||||
size="lg"
|
||||
maw={580}
|
||||
mx="auto"
|
||||
mt="xl"
|
||||
>
|
||||
This starter Next.js project includes a minimal setup for
|
||||
Mantine with TailwindCSS. To get started edit page.tsx file.
|
||||
</Text>
|
||||
<div className="flex justify-center mt-10">
|
||||
<ColorSchemesSwitcher />
|
||||
</div>
|
||||
</AppShellMain>
|
||||
</AppShell>
|
||||
)
|
||||
<>
|
||||
<Welcome />
|
||||
<ColorSchemeToggle />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,133 +0,0 @@
|
||||
/** This file is autogenerated by the script. Do not edit it manually. */
|
||||
|
||||
|
||||
@theme {
|
||||
|
||||
|
||||
/* colors - all */
|
||||
|
||||
|
||||
/* colors - variant specific */
|
||||
|
||||
|
||||
/* breakpoints */
|
||||
--breakpoint-*: initial;
|
||||
--breakpoint-xs: 36em;
|
||||
--breakpoint-sm: 48em;
|
||||
--breakpoint-md: 62em;
|
||||
--breakpoint-lg: 75em;
|
||||
--breakpoint-xl: 88em;
|
||||
|
||||
/* readd back tailwind's default containers vars to fix #24 */
|
||||
--size-3xs: 16rem;
|
||||
--size-2xs: 18rem;
|
||||
--size-xs: 20rem;
|
||||
--size-sm: 24rem;
|
||||
--size-md: 28rem;
|
||||
--size-lg: 32rem;
|
||||
--size-xl: 36rem;
|
||||
--size-2xl: 42rem;
|
||||
--size-3xl: 48rem;
|
||||
--size-4xl: 56rem;
|
||||
--size-5xl: 64rem;
|
||||
--size-6xl: 72rem;
|
||||
--size-7xl: 80rem;
|
||||
|
||||
--container-3xs: var(--size-3xs);
|
||||
--container-2xs: var(--size-2xs);
|
||||
--container-xs: var(--size-xs);
|
||||
--container-sm: var(--size-sm);
|
||||
--container-md: var(--size-md);
|
||||
--container-lg: var(--size-lg);
|
||||
--container-xl: var(--size-xl);
|
||||
--container-2xl: var(--size-2xl);
|
||||
--container-3xl: var(--size-3xl);
|
||||
--container-4xl: var(--size-4xl);
|
||||
--container-5xl: var(--size-5xl);
|
||||
--container-6xl: var(--size-6xl);
|
||||
--container-7xl: var(--size-7xl);
|
||||
|
||||
--width-3xs: var(--size-3xs);
|
||||
--width-2xs: var(--size-2xs);
|
||||
--width-xs: var(--size-xs);
|
||||
--width-sm: var(--size-sm);
|
||||
--width-md: var(--size-md);
|
||||
--width-lg: var(--size-lg);
|
||||
--width-xl: var(--size-xl);
|
||||
--width-2xl: var(--size-2xl);
|
||||
--width-3xl: var(--size-3xl);
|
||||
--width-4xl: var(--size-4xl);
|
||||
--width-5xl: var(--size-5xl);
|
||||
--width-6xl: var(--size-6xl);
|
||||
--width-7xl: var(--size-7xl);
|
||||
|
||||
--min-width-3xs: var(--size-3xs);
|
||||
--min-width-2xs: var(--size-2xs);
|
||||
--min-width-xs: var(--size-xs);
|
||||
--min-width-sm: var(--size-sm);
|
||||
--min-width-md: var(--size-md);
|
||||
--min-width-lg: var(--size-lg);
|
||||
--min-width-xl: var(--size-xl);
|
||||
--min-width-2xl: var(--size-2xl);
|
||||
--min-width-3xl: var(--size-3xl);
|
||||
--min-width-4xl: var(--size-4xl);
|
||||
--min-width-5xl: var(--size-5xl);
|
||||
--min-width-6xl: var(--size-6xl);
|
||||
--min-width-7xl: var(--size-7xl);
|
||||
|
||||
--max-width-3xs: var(--size-3xs);
|
||||
--max-width-2xs: var(--size-2xs);
|
||||
--max-width-xs: var(--size-xs);
|
||||
--max-width-sm: var(--size-sm);
|
||||
--max-width-md: var(--size-md);
|
||||
--max-width-lg: var(--size-lg);
|
||||
--max-width-xl: var(--size-xl);
|
||||
--max-width-2xl: var(--size-2xl);
|
||||
--max-width-3xl: var(--size-3xl);
|
||||
--max-width-4xl: var(--size-4xl);
|
||||
--max-width-5xl: var(--size-5xl);
|
||||
--max-width-6xl: var(--size-6xl);
|
||||
--max-width-7xl: var(--size-7xl);
|
||||
|
||||
--height-3xs: var(--size-3xs);
|
||||
--height-2xs: var(--size-2xs);
|
||||
--height-xs: var(--size-xs);
|
||||
--height-sm: var(--size-sm);
|
||||
--height-md: var(--size-md);
|
||||
--height-lg: var(--size-lg);
|
||||
--height-xl: var(--size-xl);
|
||||
--height-2xl: var(--size-2xl);
|
||||
--height-3xl: var(--size-3xl);
|
||||
--height-4xl: var(--size-4xl);
|
||||
--height-5xl: var(--size-5xl);
|
||||
--height-6xl: var(--size-6xl);
|
||||
--height-7xl: var(--size-7xl);
|
||||
|
||||
--min-height-3xs: var(--size-3xs);
|
||||
--min-height-2xs: var(--size-2xs);
|
||||
--min-height-xs: var(--size-xs);
|
||||
--min-height-sm: var(--size-sm);
|
||||
--min-height-md: var(--size-md);
|
||||
--min-height-lg: var(--size-lg);
|
||||
--min-height-xl: var(--size-xl);
|
||||
--min-height-2xl: var(--size-2xl);
|
||||
--min-height-3xl: var(--size-3xl);
|
||||
--min-height-4xl: var(--size-4xl);
|
||||
--min-height-5xl: var(--size-5xl);
|
||||
--min-height-6xl: var(--size-6xl);
|
||||
--min-height-7xl: var(--size-7xl);
|
||||
|
||||
--max-height-3xs: var(--size-3xs);
|
||||
--max-height-2xs: var(--size-2xs);
|
||||
--max-height-xs: var(--size-xs);
|
||||
--max-height-sm: var(--size-sm);
|
||||
--max-height-md: var(--size-md);
|
||||
--max-height-lg: var(--size-lg);
|
||||
--max-height-xl: var(--size-xl);
|
||||
--max-height-2xl: var(--size-2xl);
|
||||
--max-height-3xl: var(--size-3xl);
|
||||
--max-height-4xl: var(--size-4xl);
|
||||
--max-height-5xl: var(--size-5xl);
|
||||
--max-height-6xl: var(--size-6xl);
|
||||
--max-height-7xl: var(--size-7xl);
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { createTheme } from "@mantine/core"
|
||||
|
||||
export const theme = createTheme({
|
||||
breakpoints: {
|
||||
xs: "36em",
|
||||
sm: "48em",
|
||||
md: "62em",
|
||||
lg: "75em",
|
||||
xl: "88em",
|
||||
},
|
||||
})
|
||||
|
||||
export default theme
|
||||
17
src/components/ColorSchemeToggle/ColorSchemeToggle.tsx
Normal file
17
src/components/ColorSchemeToggle/ColorSchemeToggle.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { Button, Group, useMantineColorScheme } from "@mantine/core";
|
||||
|
||||
export function ColorSchemeToggle() {
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
|
||||
return (
|
||||
<Group
|
||||
justify="center"
|
||||
mt="xl">
|
||||
<Button onClick={() => setColorScheme("light")}>Light</Button>
|
||||
<Button onClick={() => setColorScheme("dark")}>Dark</Button>
|
||||
<Button onClick={() => setColorScheme("auto")}>Auto</Button>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
31
src/components/Welcome/Welcome.tsx
Normal file
31
src/components/Welcome/Welcome.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { Anchor, Text, Title } from "@mantine/core";
|
||||
|
||||
export function Welcome() {
|
||||
return (
|
||||
<>
|
||||
<Title
|
||||
ta="center"
|
||||
mt={100}
|
||||
className={"font-bold underline"}>
|
||||
Welcome to Mantine
|
||||
</Title>
|
||||
<Text
|
||||
c="dimmed"
|
||||
ta="center"
|
||||
size="lg"
|
||||
maw={580}
|
||||
mx="auto"
|
||||
mt="xl">
|
||||
This starter Next.js project includes a minimal setup for server
|
||||
side rendering, if you want to learn more on Mantine + Next.js
|
||||
integration follow{" "}
|
||||
<Anchor
|
||||
href="https://mantine.dev/guides/next/"
|
||||
size="lg">
|
||||
this guide
|
||||
</Anchor>
|
||||
. To get started edit page.tsx file.
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Button, Group, useMantineColorScheme } from "@mantine/core"
|
||||
|
||||
export function ColorSchemesSwitcher() {
|
||||
const { setColorScheme, clearColorScheme } = useMantineColorScheme()
|
||||
|
||||
return (
|
||||
<Group>
|
||||
<Button variant={"filled"} onClick={() => setColorScheme("light")}>
|
||||
Light
|
||||
</Button>
|
||||
<Button onClick={() => setColorScheme("dark")}>Dark</Button>
|
||||
<Button onClick={() => setColorScheme("auto")}>Auto</Button>
|
||||
<Button onClick={clearColorScheme}>Clear</Button>
|
||||
</Group>
|
||||
)
|
||||
}
|
||||
23
src/lib/features/auth/authSlice.ts
Normal file
23
src/lib/features/auth/authSlice.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
interface AuthState {
|
||||
phoneNumber: string | null;
|
||||
}
|
||||
|
||||
const initialState: AuthState = {
|
||||
phoneNumber: null,
|
||||
};
|
||||
|
||||
export const authSlice = createSlice({
|
||||
name: "authentication",
|
||||
initialState,
|
||||
reducers: {
|
||||
setPhoneNumber: (state, action: PayloadAction<string | null>) => {
|
||||
state.phoneNumber = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setPhoneNumber } = authSlice.actions;
|
||||
|
||||
export default authSlice.reducer;
|
||||
8
src/lib/features/rootReducer.ts
Normal file
8
src/lib/features/rootReducer.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { combineReducers } from "@reduxjs/toolkit";
|
||||
import authReducer from "@/lib/features/auth/authSlice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
auth: authReducer,
|
||||
});
|
||||
|
||||
export default rootReducer;
|
||||
1
src/lib/notifications/index.ts
Normal file
1
src/lib/notifications/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./notifications";
|
||||
46
src/lib/notifications/notifications.ts
Normal file
46
src/lib/notifications/notifications.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { notifications } from "@mantine/notifications";
|
||||
|
||||
type CustomNotifications = {
|
||||
notify: (...params: Parameters<typeof notifications.show>) => void;
|
||||
success: (...params: Parameters<typeof notifications.show>) => void;
|
||||
warn: (...params: Parameters<typeof notifications.show>) => void;
|
||||
error: (...params: Parameters<typeof notifications.show>) => void;
|
||||
guess: (
|
||||
ok: boolean,
|
||||
...params: Parameters<typeof notifications.show>
|
||||
) => void;
|
||||
} & typeof notifications;
|
||||
|
||||
const customNotifications: CustomNotifications = {
|
||||
...notifications,
|
||||
notify: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "blue",
|
||||
});
|
||||
},
|
||||
success: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "green",
|
||||
});
|
||||
},
|
||||
warn: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "yellow",
|
||||
});
|
||||
},
|
||||
error: params => {
|
||||
return notifications.show({
|
||||
...params,
|
||||
color: "red",
|
||||
});
|
||||
},
|
||||
guess: (ok: boolean, params) => {
|
||||
if (ok) return customNotifications.success(params);
|
||||
return customNotifications.error(params);
|
||||
},
|
||||
};
|
||||
|
||||
export { customNotifications as notifications };
|
||||
28
src/lib/store.ts
Normal file
28
src/lib/store.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { persistReducer, persistStore } from "redux-persist";
|
||||
import storage from "redux-persist/lib/storage";
|
||||
import rootReducer from "@/lib/features/rootReducer";
|
||||
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
whitelist: ["targetService", "verification", "auth"],
|
||||
};
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: persistedReducer,
|
||||
middleware: getDefaultMiddleware =>
|
||||
getDefaultMiddleware({
|
||||
serializableCheck: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export const persistor = persistStore(store);
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
|
||||
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||
23
src/providers/ReduxProvider.tsx
Normal file
23
src/providers/ReduxProvider.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { Provider } from "react-redux";
|
||||
import { PersistGate } from "redux-persist/integration/react";
|
||||
import { persistor, store } from "@/lib/store";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function ReduxProvider({ children }: Props) {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
{" "}
|
||||
<PersistGate
|
||||
loading={null}
|
||||
persistor={persistor}>
|
||||
{children}
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
5
src/redux-persist.d.ts
vendored
Normal file
5
src/redux-persist.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module "redux-persist/lib/storage" {
|
||||
import { WebStorage } from "redux-persist/es/types";
|
||||
const localStorage: WebStorage;
|
||||
export default localStorage;
|
||||
}
|
||||
38
src/theme.ts
Normal file
38
src/theme.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { createTheme, MantineColorsTuple } from "@mantine/core";
|
||||
|
||||
export const myColor: MantineColorsTuple = [
|
||||
"#e2faff",
|
||||
"#d4eff8",
|
||||
"#afdce9",
|
||||
"#87c8db",
|
||||
"#65b7cf",
|
||||
"#4aaac7",
|
||||
"#3fa7c6",
|
||||
"#2c92af",
|
||||
"#1b829e",
|
||||
"#00718c",
|
||||
];
|
||||
|
||||
const radius = "lg";
|
||||
const size = "lg";
|
||||
|
||||
export const theme = createTheme({
|
||||
colors: {
|
||||
myColor,
|
||||
},
|
||||
primaryColor: "myColor",
|
||||
components: {
|
||||
Button: {
|
||||
defaultProps: {
|
||||
radius,
|
||||
size,
|
||||
},
|
||||
},
|
||||
InputBase: {
|
||||
defaultProps: {
|
||||
radius,
|
||||
size,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user