@canmingir/link 1.2.30 → 1.2.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canmingir/link",
3
- "version": "1.2.30",
3
+ "version": "1.2.31",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./index.js",
@@ -5,107 +5,72 @@ import { Outlet } from "react-router";
5
5
  import React from "react";
6
6
  import Stack from "@mui/material/Stack";
7
7
  import { alpha } from "@mui/material/styles";
8
- import { useResponsive } from "../../hooks/use-responsive";
9
8
 
10
9
  // ----------------------------------------------------------------------
11
10
 
12
- export default function AuthModernLayout({ image }) {
13
- const mdUp = useResponsive("up", "md");
14
-
15
- const renderContent = (
11
+ export default function AuthModernLayout() {
12
+ return (
16
13
  <Stack
14
+ component="main"
17
15
  sx={{
18
- width: 1,
19
- mx: "auto",
20
- maxWidth: 600,
21
- px: { xs: 3, md: 10 },
22
- py: { xs: 4, md: 0 },
23
- height: "100vh",
24
- justifyContent: "center",
16
+ minHeight: "100vh",
25
17
  alignItems: "center",
18
+ justifyContent: "center",
19
+ position: "relative",
26
20
  }}
27
21
  >
28
- <Logo
29
- maxSize={140}
22
+ <Box
30
23
  sx={{
31
- mb: 1,
32
- width: 80,
33
- height: 80,
24
+ position: "fixed",
25
+ inset: 0,
26
+ backgroundImage: (theme) => `
27
+ radial-gradient(
28
+ ${alpha(theme.palette.divider, 0.08)} 1px,
29
+ transparent 1px
30
+ )
31
+ `,
32
+ backgroundSize: "16px 16px",
33
+ pointerEvents: "none",
34
+ zIndex: 0,
34
35
  }}
35
36
  />
36
-
37
- <Card
37
+ <Stack
38
38
  sx={{
39
39
  width: 1,
40
- py: { xs: 6, md: 4 },
41
- px: { xs: 4, md: 6 },
42
- boxShadow: {
43
- xs: (theme) =>
40
+ mx: "auto",
41
+ maxWidth: 480,
42
+ px: { xs: 3, md: 6 },
43
+ py: { xs: 4, md: 0 },
44
+ position: "relative",
45
+ zIndex: 1,
46
+ }}
47
+ >
48
+ <Logo
49
+ maxSize={140}
50
+ sx={{
51
+ mb: 2,
52
+ width: 72,
53
+ height: 72,
54
+ alignSelf: "center",
55
+ }}
56
+ />
57
+
58
+ <Card
59
+ sx={{
60
+ width: 1,
61
+ py: { xs: 5, md: 5 },
62
+ px: { xs: 4, md: 5 },
63
+ boxShadow: (theme) =>
44
64
  `0 0 2px ${alpha(
45
65
  theme.palette.grey[500],
46
66
  0.16
47
67
  )}, 0 12px 24px -4px ${alpha(theme.palette.grey[500], 0.12)}`,
48
- md: "none",
49
- },
50
- overflow: { md: "unset" },
51
- bgcolor: { md: "transparent" },
52
- borderRadius: 2,
53
- }}
54
- >
55
- <Outlet />
56
- </Card>
57
- </Stack>
58
- );
59
-
60
- const renderSection = (
61
- <Stack
62
- sx={{
63
- flexGrow: 1,
64
- position: "relative"
65
- }}>
66
- <Box
67
- component="img"
68
- alt="auth"
69
- src={image || "/assets/background/overlay_3.jpg"}
70
- sx={{
71
- top: "50%",
72
- left: "50%",
73
- transform: "translate(-50%, -50%)",
74
- objectFit: "cover",
75
- position: "absolute",
76
- width: "calc(60% - 32px)",
77
- height: "calc(60% - 32px)",
78
- borderRadius: 3,
79
- }}
80
- />
81
- </Stack>
82
- );
83
-
84
- return (
85
- <Stack
86
- component="main"
87
- direction="row"
88
- sx={{
89
- minHeight: "100vh",
90
- position: "relative",
91
- "&:before": {
92
- width: 1,
93
- height: 1,
94
- zIndex: -1,
95
- content: "''",
96
- position: "absolute",
97
- backgroundSize: "cover",
98
- opacity: { xs: 0.24, md: 0 },
99
- backgroundRepeat: "no-repeat",
100
- backgroundPosition: "center center",
101
- backgroundImage:
102
- "url(https://minimals.cc/assets/background/overlay_4.jpg)",
103
- },
104
- }}
105
- >
106
- {renderContent}
107
-
108
- {mdUp && renderSection}
68
+ borderRadius: 2,
69
+ }}
70
+ >
71
+ <Outlet />
72
+ </Card>
73
+ </Stack>
109
74
  </Stack>
110
75
  );
111
76
  }
@@ -7,9 +7,11 @@ import config from "../config/config";
7
7
  import { storage } from "@nucleoidjs/webstorage";
8
8
  import { useEffect } from "react";
9
9
  import { useNavigate } from "react-router-dom";
10
+
11
+ import { Box, Stack, Typography, alpha } from "@mui/material";
12
+
10
13
  function LoginPage() {
11
14
  const { name, template, credentials } = config();
12
- const formColor = "#a8a9ad";
13
15
  const navigate = useNavigate();
14
16
 
15
17
  function token() {
@@ -32,10 +34,78 @@ function LoginPage() {
32
34
 
33
35
  return (
34
36
  <Page title={`Sign in to ${name}`}>
37
+ <Stack
38
+ spacing={0}
39
+ sx={{
40
+ mb: 4,
41
+ position: "relative",
42
+ }}
43
+ >
44
+ <Typography
45
+ variant="overline"
46
+ sx={{
47
+ color: "primary.main",
48
+ fontWeight: 700,
49
+ letterSpacing: "0.2em",
50
+ fontSize: "0.65rem",
51
+ mb: 1,
52
+ }}
53
+ >
54
+ {name}
55
+ </Typography>
56
+
57
+ <Typography
58
+ variant="h3"
59
+ sx={{ fontWeight: 800, lineHeight: 1.1, letterSpacing: "-0.02em" }}
60
+ >
61
+ Welcome{" "}
62
+ <Box
63
+ component="span"
64
+ sx={{
65
+ background: (theme) =>
66
+ `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.primary.light})`,
67
+ backgroundClip: "text",
68
+ WebkitBackgroundClip: "text",
69
+ WebkitTextFillColor: "transparent",
70
+ }}
71
+ >
72
+ back.
73
+ </Box>
74
+ </Typography>
75
+
76
+ <Typography variant="body2" sx={{ color: "text.secondary", mt: 1.5 }}>
77
+ Enter your credentials to access the platform.
78
+ </Typography>
79
+
80
+ <Box
81
+ sx={{
82
+ mt: 2,
83
+ width: 32,
84
+ height: 3,
85
+ borderRadius: 2,
86
+ bgcolor: "primary.main",
87
+ }}
88
+ />
89
+ </Stack>
90
+
35
91
  {credentials?.provider === "COGNITO" && <CognitoLogin />}
36
92
  {credentials?.provider === "DEMO" && <DemoLogin />}
37
93
 
38
- <LoginForm icon={template.login.icon} name={name} formColor={formColor} />
94
+ <LoginForm icon={template.login.icon} name={name} formColor="#a8a9ad" />
95
+
96
+ <Box
97
+ sx={{
98
+ mt: 4,
99
+ pt: 3,
100
+ borderTop: (theme) =>
101
+ `1px solid ${alpha(theme.palette.divider, 0.5)}`,
102
+ textAlign: "center",
103
+ }}
104
+ >
105
+ <Typography variant="caption" sx={{ color: "text.disabled" }}>
106
+ Secure · Encrypted · Private
107
+ </Typography>
108
+ </Box>
39
109
  </Page>
40
110
  );
41
111
  }
@@ -15,31 +15,13 @@ import {
15
15
  alpha,
16
16
  } from "@mui/material";
17
17
  import {
18
- CheckOutlined,
19
- EmailOutlined,
20
18
  LockOutlined,
21
19
  MarkEmailReadOutlined,
22
20
  Visibility,
23
21
  VisibilityOff,
24
22
  } from "@mui/icons-material";
25
23
  import { confirmSignup, getTokens, login, signup } from "./amplifyAuth";
26
-
27
- const inputSx = {
28
- "& .MuiOutlinedInput-root": {
29
- fontSize: "1rem",
30
- "& input": { py: 1.5 },
31
- "&:hover fieldset": { borderColor: "primary.main" },
32
- },
33
- };
34
-
35
- const primaryButtonSx = {
36
- py: 1.5,
37
- fontSize: "1rem",
38
- fontWeight: 600,
39
- textTransform: "none",
40
- borderRadius: 1.5,
41
- "&:active": { transform: "translateY(0px)" },
42
- };
24
+ import { inputSx, primaryButtonSx } from "./styles";
43
25
 
44
26
  export default function CognitoLogin() {
45
27
  const [mode, setMode] = useState("login");
@@ -159,58 +141,49 @@ export default function CognitoLogin() {
159
141
 
160
142
  return (
161
143
  <Stack spacing={3} sx={{ mb: 2 }}>
162
- <Box sx={{ textAlign: "center" }}>
144
+ <Box sx={{ display: "flex", alignItems: "center", gap: 1.5 }}>
163
145
  <Box
164
146
  sx={{
165
- width: 52,
166
- height: 52,
167
- borderRadius: 2,
147
+ width: 40,
148
+ height: 40,
149
+ borderRadius: 1.5,
168
150
  display: "inline-flex",
169
151
  alignItems: "center",
170
152
  justifyContent: "center",
171
- mb: 2,
153
+ flexShrink: 0,
172
154
  bgcolor: (theme) => alpha(theme.palette.primary.main, 0.1),
173
155
  color: "primary.main",
174
156
  }}
175
157
  >
176
158
  {mode === "confirm" ? (
177
- <MarkEmailReadOutlined sx={{ fontSize: 26 }} />
159
+ <MarkEmailReadOutlined sx={{ fontSize: 22 }} />
178
160
  ) : (
179
- <LockOutlined sx={{ fontSize: 26 }} />
161
+ <LockOutlined sx={{ fontSize: 22 }} />
180
162
  )}
181
163
  </Box>
182
-
183
- <Typography variant="h4" gutterBottom sx={{
184
- fontWeight: 700
185
- }}>
186
- {titles[mode].heading}
187
- </Typography>
188
- <Typography variant="body2" sx={{
189
- color: "text.secondary"
190
- }}>
191
- {titles[mode].sub}
192
- </Typography>
164
+ <Box>
165
+ <Typography variant="h6" sx={{ fontWeight: 700, lineHeight: 1.2 }}>
166
+ {titles[mode].heading}
167
+ </Typography>
168
+ <Typography variant="caption" sx={{ color: "text.secondary" }}>
169
+ {titles[mode].sub}
170
+ </Typography>
171
+ </Box>
193
172
  </Box>
194
- <Stack spacing={2}>
173
+ <Stack spacing={1.5}>
195
174
  <TextField
175
+ variant="filled"
196
176
  label="Email"
197
177
  value={email}
198
178
  onChange={(e) => setEmail(e.target.value)}
199
179
  fullWidth
200
180
  sx={inputSx}
201
- slotProps={{
202
- input: {
203
- startAdornment: (
204
- <InputAdornment position="start">
205
- <EmailOutlined sx={{ color: "text.secondary", fontSize: 22 }} />
206
- </InputAdornment>
207
- ),
208
- }
209
- }}
181
+ slotProps={{ input: { disableUnderline: true } }}
210
182
  />
211
183
 
212
184
  {mode !== "confirm" && (
213
185
  <TextField
186
+ variant="filled"
214
187
  type={showPassword ? "text" : "password"}
215
188
  label="Password"
216
189
  value={password}
@@ -219,21 +192,16 @@ export default function CognitoLogin() {
219
192
  sx={inputSx}
220
193
  slotProps={{
221
194
  input: {
222
- startAdornment: (
223
- <InputAdornment position="start">
224
- <LockOutlined
225
- sx={{ color: "text.secondary", fontSize: 22 }}
226
- />
227
- </InputAdornment>
228
- ),
195
+ disableUnderline: true,
229
196
  endAdornment: passwordAdornment,
230
- }
197
+ },
231
198
  }}
232
199
  />
233
200
  )}
234
201
 
235
202
  {mode === "signup" && (
236
203
  <TextField
204
+ variant="filled"
237
205
  type={showConfirmPassword ? "text" : "password"}
238
206
  label="Confirm Password"
239
207
  value={confirmPassword}
@@ -242,17 +210,13 @@ export default function CognitoLogin() {
242
210
  sx={inputSx}
243
211
  slotProps={{
244
212
  input: {
245
- startAdornment: (
246
- <InputAdornment position="start">
247
- <LockOutlined
248
- sx={{ color: "text.secondary", fontSize: 22 }}
249
- />
250
- </InputAdornment>
251
- ),
213
+ disableUnderline: true,
252
214
  endAdornment: (
253
215
  <InputAdornment position="end">
254
216
  <IconButton
255
- onClick={() => setShowConfirmPassword(!showConfirmPassword)}
217
+ onClick={() =>
218
+ setShowConfirmPassword(!showConfirmPassword)
219
+ }
256
220
  edge="end"
257
221
  size="small"
258
222
  tabIndex={-1}
@@ -261,29 +225,20 @@ export default function CognitoLogin() {
261
225
  </IconButton>
262
226
  </InputAdornment>
263
227
  ),
264
- }
228
+ },
265
229
  }}
266
230
  />
267
231
  )}
268
232
 
269
233
  {mode === "confirm" && (
270
234
  <TextField
235
+ variant="filled"
271
236
  label="Confirmation Code"
272
237
  value={code}
273
238
  onChange={(e) => setCode(e.target.value)}
274
239
  fullWidth
275
240
  sx={inputSx}
276
- slotProps={{
277
- input: {
278
- startAdornment: (
279
- <InputAdornment position="start">
280
- <CheckOutlined
281
- sx={{ color: "text.secondary", fontSize: 22 }}
282
- />
283
- </InputAdornment>
284
- ),
285
- }
286
- }}
241
+ slotProps={{ input: { disableUnderline: true } }}
287
242
  />
288
243
  )}
289
244
  </Stack>
@@ -294,16 +249,21 @@ export default function CognitoLogin() {
294
249
  onClick={handleLogin}
295
250
  size="large"
296
251
  fullWidth
252
+ disableElevation
297
253
  sx={primaryButtonSx}
298
254
  >
299
- Sign in
255
+ Sign in &rarr;
300
256
  </Button>
301
257
  <Button
302
258
  onClick={() => setMode("signup")}
303
259
  fullWidth
304
- sx={{ textTransform: "none", fontWeight: 500 }}
260
+ sx={{
261
+ textTransform: "none",
262
+ fontWeight: 600,
263
+ color: "text.secondary",
264
+ }}
305
265
  >
306
- Create an account
266
+ No account? Create one
307
267
  </Button>
308
268
  </Stack>
309
269
  )}
@@ -314,16 +274,21 @@ export default function CognitoLogin() {
314
274
  onClick={handleSignup}
315
275
  size="large"
316
276
  fullWidth
277
+ disableElevation
317
278
  sx={primaryButtonSx}
318
279
  >
319
- Sign Up
280
+ Create account &rarr;
320
281
  </Button>
321
282
  <Button
322
283
  onClick={() => setMode("login")}
323
284
  fullWidth
324
- sx={{ textTransform: "none", fontWeight: 500 }}
285
+ sx={{
286
+ textTransform: "none",
287
+ fontWeight: 600,
288
+ color: "text.secondary",
289
+ }}
325
290
  >
326
- Back to login
291
+ &larr; Back to sign in
327
292
  </Button>
328
293
  </Stack>
329
294
  )}
@@ -333,9 +298,10 @@ export default function CognitoLogin() {
333
298
  onClick={handleConfirm}
334
299
  size="large"
335
300
  fullWidth
301
+ disableElevation
336
302
  sx={primaryButtonSx}
337
303
  >
338
- Confirm
304
+ Verify &rarr;
339
305
  </Button>
340
306
  )}
341
307
  </Stack>
@@ -12,13 +12,9 @@ import {
12
12
  Typography,
13
13
  alpha,
14
14
  } from "@mui/material";
15
- import {
16
- LockOutlined,
17
- PersonOutline,
18
- Visibility,
19
- VisibilityOff,
20
- } from "@mui/icons-material";
21
15
  import React, { useState } from "react";
16
+ import { Visibility, VisibilityOff } from "@mui/icons-material";
17
+ import { inputSx, primaryButtonSx } from "./styles";
22
18
 
23
19
  export default function DemoLogin() {
24
20
  const [username, setUsername] = useState("");
@@ -56,51 +52,25 @@ export default function DemoLogin() {
56
52
 
57
53
  return (
58
54
  <Stack spacing={2.5} sx={{ mb: 2 }}>
59
- <Stack spacing={2}>
55
+ <Stack spacing={1.5}>
60
56
  <TextField
57
+ variant="filled"
61
58
  label="Username"
62
59
  value={username}
63
60
  onChange={(e) => setUsername(e.target.value)}
64
61
  fullWidth
65
- sx={{
66
- "& .MuiOutlinedInput-root": {
67
- fontSize: "1rem",
68
- "& input": {
69
- py: 1.5,
70
- },
71
- "&:hover fieldset": {
72
- borderColor: "primary.main",
73
- },
74
- },
75
- }}
76
- slotProps={{
77
- input: {
78
- startAdornment: (
79
- <InputAdornment position="start">
80
- <PersonOutline sx={{ color: "text.secondary", fontSize: 22 }} />
81
- </InputAdornment>
82
- ),
83
- }
84
- }}
62
+ sx={inputSx}
63
+ slotProps={{ input: { disableUnderline: true } }}
85
64
  />
86
65
 
87
66
  <TextField
67
+ variant="filled"
88
68
  label="Password"
89
69
  type={showPassword ? "text" : "password"}
90
70
  value={password}
91
71
  onChange={(e) => setPassword(e.target.value)}
92
72
  fullWidth
93
- sx={{
94
- "& .MuiOutlinedInput-root": {
95
- fontSize: "1rem",
96
- "& input": {
97
- py: 1.5,
98
- },
99
- "&:hover fieldset": {
100
- borderColor: "primary.main",
101
- },
102
- },
103
- }}
73
+ sx={inputSx}
104
74
  onKeyPress={(e) => {
105
75
  if (e.key === "Enter") {
106
76
  handleLogin();
@@ -108,11 +78,7 @@ export default function DemoLogin() {
108
78
  }}
109
79
  slotProps={{
110
80
  input: {
111
- startAdornment: (
112
- <InputAdornment position="start">
113
- <LockOutlined sx={{ color: "text.secondary", fontSize: 22 }} />
114
- </InputAdornment>
115
- ),
81
+ disableUnderline: true,
116
82
  endAdornment: (
117
83
  <InputAdornment position="end">
118
84
  <IconButton
@@ -125,56 +91,37 @@ export default function DemoLogin() {
125
91
  </IconButton>
126
92
  </InputAdornment>
127
93
  ),
128
- }
94
+ },
129
95
  }}
130
96
  />
131
97
  </Stack>
98
+
132
99
  <Button
133
100
  variant="contained"
134
101
  onClick={handleLogin}
135
102
  size="large"
136
103
  fullWidth
137
- sx={{
138
- mt: 1,
139
- py: 1.5,
140
- fontSize: "1rem",
141
- fontWeight: 600,
142
- textTransform: "none",
143
- borderRadius: 1.5,
144
- boxShadow: (theme) =>
145
- `0 8px 16px ${alpha(theme.palette.primary.main, 0.24)}`,
146
- transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
147
- "&:hover": {
148
- transform: "translateY(-2px)",
149
- boxShadow: (theme) =>
150
- `0 12px 24px ${alpha(theme.palette.primary.main, 0.32)}`,
151
- },
152
- "&:active": {
153
- transform: "translateY(0px)",
154
- },
155
- }}
104
+ disableElevation
105
+ sx={primaryButtonSx}
156
106
  >
157
- Sign in
107
+ Sign in &rarr;
158
108
  </Button>
159
- <Box
160
- sx={{
161
- mt: 1,
162
- textAlign: "center",
163
- p: 2,
164
- borderRadius: 1.5,
165
- bgcolor: (theme) => alpha(theme.palette.info.main, 0.08),
166
- border: (theme) =>
167
- `1px dashed ${alpha(theme.palette.info.main, 0.24)}`,
168
- }}
169
- >
170
- <Typography
171
- variant="caption"
172
- sx={{
173
- color: "text.secondary",
174
- fontSize: "0.8125rem"
175
- }}>
176
- Demo credentials:{" "}
177
- <Box component="strong" sx={{ color: "text.primary" }}>
109
+
110
+ <Box sx={{ display: "flex", justifyContent: "center" }}>
111
+ <Typography variant="caption" sx={{ color: "text.disabled" }}>
112
+ Demo credentials:&nbsp;
113
+ <Box
114
+ component="span"
115
+ sx={{
116
+ color: "text.secondary",
117
+ fontWeight: 600,
118
+ fontFamily: "monospace",
119
+ px: 0.5,
120
+ py: 0.25,
121
+ borderRadius: 0.5,
122
+ bgcolor: (theme) => alpha(theme.palette.grey[500], 0.1),
123
+ }}
124
+ >
178
125
  admin / admin
179
126
  </Box>
180
127
  </Typography>
@@ -0,0 +1,35 @@
1
+ import { alpha } from "@mui/material";
2
+ export const inputSx = {
3
+ "& .MuiFilledInput-root": {
4
+ borderRadius: 1.5,
5
+ fontSize: "0.9375rem",
6
+ bgcolor: (theme) => alpha(theme.palette.grey[500], 0.08),
7
+ "&:hover": {
8
+ bgcolor: (theme) => alpha(theme.palette.grey[500], 0.12),
9
+ },
10
+ "&.Mui-focused": {
11
+ bgcolor: (theme) => alpha(theme.palette.primary.main, 0.06),
12
+ },
13
+ "&:before, &:after": { display: "none" },
14
+ },
15
+ "& .MuiInputLabel-root.Mui-focused": {
16
+ color: "primary.main",
17
+ },
18
+ };
19
+
20
+ export const primaryButtonSx = {
21
+ py: 1.5,
22
+ fontSize: "0.9375rem",
23
+ fontWeight: 700,
24
+ textTransform: "none",
25
+ borderRadius: 1.5,
26
+ letterSpacing: "0.01em",
27
+ background: (theme) =>
28
+ `linear-gradient(135deg, ${theme.palette.primary.dark} 0%, ${theme.palette.primary.main} 100%)`,
29
+ transition: "opacity 0.2s",
30
+ "&:hover": {
31
+ opacity: 0.88,
32
+ background: (theme) =>
33
+ `linear-gradient(135deg, ${theme.palette.primary.dark} 0%, ${theme.palette.primary.main} 100%)`,
34
+ },
35
+ };