react-frontend-common-components 0.0.1

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.
Files changed (78) hide show
  1. package/dist/index.d.ts +85 -0
  2. package/dist/index.js +26 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/index.mjs +26 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +34 -0
  7. package/rollup.config.js +44 -0
  8. package/src/components/app-avatar/app-avatar.tsx +24 -0
  9. package/src/components/app-back-arrow/app-back-arrow.css +17 -0
  10. package/src/components/app-back-arrow/app-back-arrow.tsx +30 -0
  11. package/src/components/app-badge/app-badge.css +11 -0
  12. package/src/components/app-badge/app-badge.tsx +44 -0
  13. package/src/components/app-bread-crumb/app-bread-crumb.tsx +16 -0
  14. package/src/components/app-button/app-button.css +13 -0
  15. package/src/components/app-button/app-button.tsx +51 -0
  16. package/src/components/app-card/app-card.css +8 -0
  17. package/src/components/app-card/app-card.tsx +43 -0
  18. package/src/components/app-carousel/app-carousel.css +68 -0
  19. package/src/components/app-carousel/app-carousel.tsx +62 -0
  20. package/src/components/app-chart/app-chart.css +6 -0
  21. package/src/components/app-chart/app-chart.tsx +97 -0
  22. package/src/components/app-checkbox-text/app-checkbox-text.css +12 -0
  23. package/src/components/app-checkbox-text/app-checkbox-text.tsx +20 -0
  24. package/src/components/app-collapse/app-collapse.tsx +57 -0
  25. package/src/components/app-custom-loader/app-custom-loader.css +116 -0
  26. package/src/components/app-custom-loader/app-custom-loader.tsx +23 -0
  27. package/src/components/app-divider/app-divider.tsx +16 -0
  28. package/src/components/app-float-button/app-float-button.tsx +23 -0
  29. package/src/components/app-image-box/app-image-box.css +23 -0
  30. package/src/components/app-image-box/app-image-box.tsx +38 -0
  31. package/src/components/app-input/app-input.css +61 -0
  32. package/src/components/app-input/app-input.tsx +89 -0
  33. package/src/components/app-label/app-label.css +5 -0
  34. package/src/components/app-label/app-label.tsx +34 -0
  35. package/src/components/app-list/app-list.tsx +26 -0
  36. package/src/components/app-loader/app-loader.css +16 -0
  37. package/src/components/app-loader/app-loader.tsx +28 -0
  38. package/src/components/app-location-map/app-location-map.css +4 -0
  39. package/src/components/app-location-map/app-location-map.tsx +62 -0
  40. package/src/components/app-modal/app-modal.css +35 -0
  41. package/src/components/app-modal/app-modal.tsx +58 -0
  42. package/src/components/app-otp-field/app-otp-field.css +31 -0
  43. package/src/components/app-otp-field/app-otp-field.tsx +70 -0
  44. package/src/components/app-pagination/app-pagination.tsx +40 -0
  45. package/src/components/app-password-input/app-password-input.css +41 -0
  46. package/src/components/app-password-input/app-password-input.tsx +79 -0
  47. package/src/components/app-phone-field/app-phone-field.css +61 -0
  48. package/src/components/app-phone-field/app-phone-field.tsx +60 -0
  49. package/src/components/app-popover/app-popover.css +5 -0
  50. package/src/components/app-popover/app-popover.tsx +45 -0
  51. package/src/components/app-progress/app-progress.tsx +40 -0
  52. package/src/components/app-radio-group/app-radio-group.css +6 -0
  53. package/src/components/app-radio-group/app-radio-group.tsx +45 -0
  54. package/src/components/app-select/app-select.css +21 -0
  55. package/src/components/app-select/app-select.tsx +53 -0
  56. package/src/components/app-select-add/app-select-add.css +21 -0
  57. package/src/components/app-select-add/app-select-add.tsx +34 -0
  58. package/src/components/app-sidebar/app-sidebar.css +46 -0
  59. package/src/components/app-sidebar/app-sidebar.tsx +60 -0
  60. package/src/components/app-tab/app-tab.css +22 -0
  61. package/src/components/app-tab/app-tab.tsx +31 -0
  62. package/src/components/app-table/app-table.tsx +42 -0
  63. package/src/components/app-tag/app-tag.css +11 -0
  64. package/src/components/app-tag/app-tag.tsx +48 -0
  65. package/src/components/app-textarea/app-textarea.css +19 -0
  66. package/src/components/app-textarea/app-textarea.tsx +59 -0
  67. package/src/components/app-title/app-title.css +12 -0
  68. package/src/components/app-title/app-title.tsx +28 -0
  69. package/src/components/app-toggle-button/app-toggle-button.css +27 -0
  70. package/src/components/app-toggle-button/app-toggle-button.tsx +43 -0
  71. package/src/components/app-upload-image/app-upload-image.css +26 -0
  72. package/src/components/app-upload-image/app-upload-image.tsx +90 -0
  73. package/src/components/over-view-card/over-view-card.css +16 -0
  74. package/src/components/over-view-card/over-view-card.tsx +22 -0
  75. package/src/index.ts +5 -0
  76. package/src/themes/icons/icons.tsx +131 -0
  77. package/src/themes/images/profile-img.svg +14 -0
  78. package/tsconfig.json +20 -0
@@ -0,0 +1,70 @@
1
+ import React, { useEffect } from "react";
2
+ import OTPInput from "react-otp-input";
3
+ import "./app-otp-field.css";
4
+
5
+ interface AppOtpFieldProps {
6
+ otp: string;
7
+ onChange: (otp: string) => void;
8
+ numInputs?: number;
9
+ otpError?: string;
10
+ resendTimeout?: number;
11
+ onResendOtp?: () => void;
12
+ setResendTimeout: (timeout: number) => void;
13
+ className?: string;
14
+ resendTxt?: string;
15
+ resendTime: string;
16
+ }
17
+
18
+ const AppOtpField = ({
19
+ otp,
20
+ onChange,
21
+ numInputs = 4,
22
+ otpError,
23
+ resendTimeout,
24
+ onResendOtp,
25
+ setResendTimeout,
26
+ className,
27
+ resendTxt,
28
+ resendTime,
29
+ }: AppOtpFieldProps) => {
30
+ useEffect(() => {
31
+ if (resendTimeout && resendTimeout > 0) {
32
+ const timer = setTimeout(() => {
33
+ setResendTimeout(resendTimeout - 1);
34
+ }, 1000);
35
+
36
+ return () => clearTimeout(timer);
37
+ }
38
+ }, [resendTimeout, setResendTimeout]);
39
+
40
+ return (
41
+ <div className={`appOtpField ${className}`}>
42
+ <OTPInput
43
+ value={otp}
44
+ onChange={onChange}
45
+ numInputs={numInputs}
46
+ containerStyle={"otpInputStyle"}
47
+ renderSeparator={<span>-</span>}
48
+ renderInput={(props) => <input {...props} />}
49
+ />
50
+ {otpError && <p className={"error"}>{otpError}</p>}{" "}
51
+ <div className={"resendWrap"}>
52
+ {resendTimeout !== undefined && (
53
+ <span className={"forgotPassword"}>
54
+ {resendTimeout > 0 ? (
55
+ <span className={"resendTimer"}>{resendTime}</span>
56
+ ) : (
57
+ onResendOtp && (
58
+ <span className={"resendBtn"} onClick={() => onResendOtp()}>
59
+ {resendTxt}
60
+ </span>
61
+ )
62
+ )}
63
+ </span>
64
+ )}
65
+ </div>
66
+ </div>
67
+ );
68
+ };
69
+
70
+ export default AppOtpField;
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import { Pagination } from "antd";
3
+ import { PaginationProps } from "antd/lib/pagination";
4
+
5
+ interface AppPaginationProps extends PaginationProps {
6
+ total: number;
7
+ currentPage: number;
8
+ pageSize?: number;
9
+ onPageChange: (page: number, pageSize: number) => void;
10
+ showGotoBox: boolean;
11
+ sizeChanger: boolean;
12
+ className?: string;
13
+ }
14
+
15
+ const AppPagination = ({
16
+ total,
17
+ currentPage,
18
+ pageSize = 10,
19
+ onPageChange,
20
+ showGotoBox = false,
21
+ sizeChanger = true,
22
+ className,
23
+ ...rest
24
+ }: AppPaginationProps) => {
25
+ return (
26
+ <div className={className}>
27
+ <Pagination
28
+ current={currentPage}
29
+ pageSize={pageSize}
30
+ total={total}
31
+ onChange={onPageChange}
32
+ showSizeChanger={sizeChanger}
33
+ showQuickJumper={showGotoBox}
34
+ {...rest}
35
+ />
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default AppPagination;
@@ -0,0 +1,41 @@
1
+ .appPasswordInput {
2
+ font-size: var(--font-14);
3
+ font-weight: 500;
4
+ color: #1e1f21;
5
+ border: none;
6
+ position: relative;
7
+
8
+ .icon {
9
+ position: absolute;
10
+ right: 1rem;
11
+ top: 50%;
12
+ transform: translateY(-50%);
13
+ display: flex;
14
+ align-items: center;
15
+ height: 100%;
16
+ cursor: pointer;
17
+ }
18
+
19
+ *:focus {
20
+ outline: 0 !important;
21
+ box-shadow: unset !important;
22
+ }
23
+ .ant-input-outlined {
24
+ &:hover {
25
+ border-color: #bfbebe !important;
26
+ }
27
+ &::placeholder {
28
+ color: #202123 !important;
29
+ font-size: 14px;
30
+ font-weight: 500;
31
+ line-height: 14px;
32
+ text-align: left;
33
+ }
34
+ }
35
+ }
36
+
37
+ .error {
38
+ color: red;
39
+ font-size: 0.875rem;
40
+ margin-top: 0.25rem;
41
+ }
@@ -0,0 +1,79 @@
1
+ import React, { useState } from "react";
2
+ import { Input } from "antd";
3
+ import {
4
+ ChangeEventHandler,
5
+ KeyboardEventHandler,
6
+ MouseEventHandler,
7
+ } from "react";
8
+ import Icons from "../../themes/icons/icons";
9
+ import "./app-password-input.css";
10
+
11
+ interface AppPasswordInputProps {
12
+ className?: string;
13
+ label?: string;
14
+ name?: string;
15
+ value?: string;
16
+ dataTestId?: string;
17
+ id?: string;
18
+ disabled?: boolean;
19
+ handleChange?: ChangeEventHandler<HTMLInputElement>;
20
+ onClick?: MouseEventHandler<HTMLElement>;
21
+ onPressEnter?: KeyboardEventHandler<HTMLInputElement>;
22
+ defaultValue?: string;
23
+ isAutoFocus?: boolean;
24
+ triggerFocus?: boolean;
25
+ errorMessage?: string;
26
+ autoComplete?: string;
27
+ }
28
+
29
+ const AppPasswordInput = ({
30
+ label,
31
+ name,
32
+ value,
33
+ dataTestId,
34
+ id,
35
+ disabled,
36
+ handleChange,
37
+ onClick,
38
+ defaultValue,
39
+ onPressEnter,
40
+ className,
41
+ errorMessage,
42
+ isAutoFocus,
43
+ autoComplete = "new-password",
44
+ }: AppPasswordInputProps) => {
45
+ const [showPassword, setShowPassword] = useState(false);
46
+
47
+ const togglePasswordVisibility = () => {
48
+ setShowPassword(!showPassword);
49
+ };
50
+
51
+ return (
52
+ <div className={`appPasswordInput ${className}`}>
53
+ <div className="position-relative w-100">
54
+ <Input
55
+ type={showPassword ? "text" : "password"}
56
+ className={"inputPassword"}
57
+ data-test-id={dataTestId}
58
+ id={id}
59
+ disabled={disabled}
60
+ name={name}
61
+ value={value}
62
+ onChange={handleChange}
63
+ onClick={onClick}
64
+ defaultValue={defaultValue}
65
+ onPressEnter={onPressEnter}
66
+ placeholder={label}
67
+ autoFocus={isAutoFocus}
68
+ autoComplete={autoComplete}
69
+ />
70
+ <span className={"icon"} onClick={togglePasswordVisibility}>
71
+ {Icons.eyePassword}
72
+ </span>
73
+ </div>
74
+ {errorMessage && <div className={"error"}>{errorMessage}</div>}
75
+ </div>
76
+ );
77
+ };
78
+
79
+ export default AppPasswordInput;
@@ -0,0 +1,61 @@
1
+ .appPhoneField {
2
+ .allow-dropdown {
3
+ width: 100%;
4
+ }
5
+ .intelWrapper {
6
+ .intl-tel-input.allow-dropdown .flag-container {
7
+ height: unset !important;
8
+
9
+ & > div:first-child {
10
+ display: flex;
11
+ align-items: center;
12
+ position: relative;
13
+ background-color: transparent;
14
+ .selected-dial-code {
15
+ padding-left: 0.5rem;
16
+ }
17
+
18
+ &::after {
19
+ content: "";
20
+ background-color: #dcdcdc;
21
+ height: 50%;
22
+ width: 1px;
23
+ position: absolute;
24
+ right: 0;
25
+ top: 50%;
26
+ bottom: 50%;
27
+ transform: translateY(-50%);
28
+ }
29
+
30
+ & > div:nth-child(2) {
31
+ margin-right: 0.2rem;
32
+ margin-bottom: 0 !important;
33
+ font-size: 12px;
34
+ font-weight: 500;
35
+ letter-spacing: -0.02em;
36
+ text-align: left;
37
+ }
38
+ }
39
+ }
40
+ }
41
+
42
+ .customintlinput {
43
+ width: 100%;
44
+ min-height: 40px;
45
+ font-size: var(--font-14);
46
+ font-weight: 500;
47
+ color: #000000 !important;
48
+ border: 1px solid #bfbebe;
49
+ border-radius: 10px;
50
+ height: 40px;
51
+ &:focus-visible {
52
+ outline: unset !important;
53
+ }
54
+ }
55
+ }
56
+
57
+ .error {
58
+ color: red;
59
+ font-size: 0.875rem;
60
+ margin-top: 0.25rem;
61
+ }
@@ -0,0 +1,60 @@
1
+ import React from "react";
2
+ import "react-intl-tel-input/dist/main.css";
3
+ import IntlTelInput from "react-intl-tel-input";
4
+ import "./app-phone-field.css";
5
+
6
+ interface AppPhoneFieldProps {
7
+ phone: string;
8
+ setPhone: (phone: string) => void;
9
+ phoneError: string;
10
+ setPhoneError: (error: string) => void;
11
+ setCustomerCountryCode: (code: string) => void;
12
+ className?: string;
13
+ }
14
+
15
+ const AppPhoneField = ({
16
+ phone,
17
+ setPhone,
18
+ phoneError,
19
+ setPhoneError,
20
+ setCustomerCountryCode,
21
+ className,
22
+ }: AppPhoneFieldProps) => {
23
+ return (
24
+ <div className={`appPhoneField ${className}`}>
25
+ <div className={"intelWrapper"}>
26
+ <IntlTelInput
27
+ containerClassName={`${"intltelinput"} intl-tel-input`}
28
+ inputClassName={`${"customintlinput"} custom-intl-input`}
29
+ separateDialCode={true}
30
+ defaultCountry="ae"
31
+ placeholder="50-1234567"
32
+ preferredCountries={["ae"]}
33
+ value={phone}
34
+ onPhoneNumberChange={(isValid, value, country, fullNumber) => {
35
+ if (!isNaN(Number(value))) {
36
+ setPhone(value);
37
+ setCustomerCountryCode("+" + country.dialCode);
38
+ setPhoneError("");
39
+ } else if (value === "") {
40
+ setPhoneError("");
41
+ } else {
42
+ setPhoneError("You can only enter numbers.");
43
+ }
44
+ }}
45
+ onSelectFlag={(
46
+ currentNumber,
47
+ selectedCountryData,
48
+ fullNumber,
49
+ isValid
50
+ ) => {
51
+ setCustomerCountryCode("+" + selectedCountryData.dialCode);
52
+ }}
53
+ />
54
+ </div>
55
+ <p className={"error"}>{phoneError && phoneError}</p>
56
+ </div>
57
+ );
58
+ };
59
+
60
+ export default AppPhoneField;
@@ -0,0 +1,5 @@
1
+ .appPopover {
2
+ .popoverComponent {
3
+ width: max-content;
4
+ }
5
+ }
@@ -0,0 +1,45 @@
1
+ import { Popover } from "antd";
2
+ import { PopoverProps } from "antd/lib/popover";
3
+ import "./app-popover.css";
4
+
5
+ interface AppPopoverProps extends PopoverProps {
6
+ content: React.ReactNode;
7
+ title?: React.ReactNode;
8
+ children: React.ReactNode;
9
+ bgColor?: string;
10
+ triggerType?: "hover" | "click";
11
+ color?: string;
12
+ className?: string;
13
+ }
14
+
15
+ const AppPopover = ({
16
+ content,
17
+ title,
18
+ children,
19
+ bgColor,
20
+ color,
21
+ triggerType = "hover",
22
+ className,
23
+ ...popoverProps
24
+ }: AppPopoverProps) => {
25
+ const popoverStyle = {
26
+ color: color ?? "inherit",
27
+ };
28
+
29
+ return (
30
+ <div className={`appPopover ${className}`}>
31
+ <Popover
32
+ color={bgColor}
33
+ content={<div style={popoverStyle}>{content}</div>}
34
+ title={title ? <div style={popoverStyle}>{title}</div> : null}
35
+ trigger={triggerType}
36
+ overlayClassName={className}
37
+ {...popoverProps}
38
+ >
39
+ <div className={"popoverComponent"}>{children}</div>
40
+ </Popover>
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default AppPopover;
@@ -0,0 +1,40 @@
1
+ import React from "react";
2
+ import { Progress } from "antd";
3
+
4
+ interface AppProgressProps {
5
+ percent: number;
6
+ type?: "line" | "circle" | "dashboard";
7
+ strokeColor?: string;
8
+ trailColor?: string;
9
+ size?: "default" | "small";
10
+ status?: "success" | "exception" | "normal" | "active";
11
+ showInfo?: boolean;
12
+ className?: string;
13
+ }
14
+
15
+ const AppProgress = ({
16
+ percent,
17
+ type = "line",
18
+ strokeColor,
19
+ trailColor,
20
+ size = "default",
21
+ status,
22
+ showInfo = true,
23
+ className,
24
+ }: AppProgressProps) => {
25
+ return (
26
+ <div className={className}>
27
+ <Progress
28
+ percent={percent}
29
+ type={type}
30
+ strokeColor={strokeColor}
31
+ trailColor={trailColor}
32
+ size={size}
33
+ status={status}
34
+ showInfo={showInfo}
35
+ />
36
+ </div>
37
+ );
38
+ };
39
+
40
+ export default AppProgress;
@@ -0,0 +1,6 @@
1
+ .appRadioGroup {
2
+ .radioGroup {
3
+ display: flex;
4
+ align-items: center;
5
+ }
6
+ }
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import { Radio } from "antd";
3
+ import type { RadioChangeEvent } from "antd";
4
+ import "./app-radio-group.css";
5
+
6
+ interface Option {
7
+ value: number;
8
+ text: string;
9
+ }
10
+
11
+ interface AppRadioGroupProps {
12
+ options: Option[];
13
+ selectedValue: number | null;
14
+ onChange: (value: number) => void;
15
+ className?: string;
16
+ }
17
+
18
+ const AppRadioGroup = ({
19
+ options,
20
+ selectedValue,
21
+ onChange,
22
+ className,
23
+ }: AppRadioGroupProps) => {
24
+ const handleChange = (e: RadioChangeEvent) => {
25
+ onChange(e.target.value);
26
+ };
27
+
28
+ return (
29
+ <div className={`appRadioGroup ${className}`}>
30
+ <Radio.Group
31
+ className={"radioGroup"}
32
+ onChange={handleChange}
33
+ value={selectedValue}
34
+ >
35
+ {options.map((option) => (
36
+ <Radio key={option.value} value={option.value}>
37
+ {option.text}
38
+ </Radio>
39
+ ))}
40
+ </Radio.Group>
41
+ </div>
42
+ );
43
+ };
44
+
45
+ export default AppRadioGroup;
@@ -0,0 +1,21 @@
1
+ .appselect {
2
+ *:focus,
3
+ *:active,
4
+ *:focus-within {
5
+ outline: 0 !important;
6
+ box-shadow: unset !important;
7
+ }
8
+ .ant-select {
9
+ &:hover {
10
+ .ant-select-selector {
11
+ border-color: #d9d9d9 !important;
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ .error {
18
+ color: red;
19
+ font-size: 0.875rem;
20
+ margin-top: 0.25rem;
21
+ }
@@ -0,0 +1,53 @@
1
+ import React from "react";
2
+ import { Select } from "antd";
3
+ import { MouseEventHandler } from "react";
4
+ import "./app-select.css";
5
+
6
+ interface AppSelectProps {
7
+ className?: string;
8
+ value?: string | null;
9
+ dataTestId?: string;
10
+ id?: string;
11
+ disabled?: boolean;
12
+ handleChange?: (value: string | string[]) => void;
13
+ onClick?: MouseEventHandler<HTMLElement>;
14
+ options?: Array<{ value: string; label: string }>;
15
+ onSelectChange?: (value: string) => void;
16
+ required?: boolean;
17
+ placeholder?: string;
18
+ errorMessage?: string;
19
+ }
20
+
21
+ const AppSelect = ({
22
+ value,
23
+ handleChange,
24
+ options,
25
+ disabled,
26
+ placeholder,
27
+ className,
28
+ errorMessage,
29
+ }: AppSelectProps) => {
30
+ return (
31
+ <div className={`appselect ${className}`}>
32
+ <Select
33
+ className={"select"}
34
+ disabled={disabled}
35
+ value={value}
36
+ placeholder={placeholder}
37
+ onChange={(value: string | string[]) =>
38
+ handleChange && handleChange(value)
39
+ }
40
+ >
41
+ {options &&
42
+ options.map((option, i) => (
43
+ <Select.Option key={option.value} value={option.value}>
44
+ {option.label}
45
+ </Select.Option>
46
+ ))}
47
+ </Select>
48
+ {errorMessage && <div className={"error"}>{errorMessage}</div>}
49
+ </div>
50
+ );
51
+ };
52
+
53
+ export default AppSelect;
@@ -0,0 +1,21 @@
1
+ .appSelectAdd {
2
+ *:focus,
3
+ *:active,
4
+ *:focus-within {
5
+ outline: 0 !important;
6
+ box-shadow: unset !important;
7
+ }
8
+ .ant-select {
9
+ &:hover {
10
+ .ant-select-selector {
11
+ border-color: #d9d9d9 !important;
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ .error {
18
+ color: red;
19
+ font-size: 0.875rem;
20
+ margin-top: 0.25rem;
21
+ }
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import { Select } from "antd";
3
+ import type { SelectProps } from "antd";
4
+ import "./app-select-add.css";
5
+
6
+ interface AppSelectAddProps extends SelectProps {
7
+ options?: SelectProps["options"];
8
+ placeholder?: string;
9
+ onChange?: (value: string) => void;
10
+ className?: string;
11
+ }
12
+
13
+ const AppSelectAdd = ({
14
+ options = [],
15
+ placeholder = "Tags Mode",
16
+ onChange,
17
+ className,
18
+ ...rest
19
+ }: AppSelectAddProps) => {
20
+ return (
21
+ <div className={`appSelectAdd ${className}`}>
22
+ <Select
23
+ mode="tags"
24
+ style={{ width: "100%" }}
25
+ placeholder={placeholder}
26
+ onChange={onChange}
27
+ options={options}
28
+ {...rest}
29
+ />
30
+ </div>
31
+ );
32
+ };
33
+
34
+ export default AppSelectAdd;
@@ -0,0 +1,46 @@
1
+ .sideBar {
2
+ height: 100vh;
3
+ .sider {
4
+ height: 100%;
5
+ .ant-layout-sider-children {
6
+ height: 100%;
7
+ display: flex;
8
+ flex-direction: column;
9
+ row-gap: 2.875rem;
10
+ .ant-menu {
11
+ border: none;
12
+ }
13
+ }
14
+ }
15
+ }
16
+
17
+ .logo {
18
+ height: 64px;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 16px;
23
+ }
24
+
25
+ .menu {
26
+ border-right: 0;
27
+ }
28
+
29
+ .footer {
30
+ position: relative;
31
+ &::before {
32
+ content: "";
33
+ height: 1px;
34
+ width: 80%;
35
+ position: absolute;
36
+ top: 0;
37
+ right: 50%;
38
+ left: 50%;
39
+ transform: translateX(-50%);
40
+ background-color: #acacac;
41
+ }
42
+ }
43
+
44
+ .tag {
45
+ margin-left: 8px;
46
+ }