@grantbii/design-system 1.0.66 → 1.0.67

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/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # Grantbii's Design System
2
2
 
3
+ Storybook's viewport triggers media query for small screen (e.g. mobile) by default.
4
+ View in full screen to see components for big screen (e.g. desktop).
5
+
3
6
  Based on Grantbii's Global Design Library in Figma.
4
7
 
5
8
  Approach: Atomic Design
@@ -1,5 +1 @@
1
1
  export * from "@phosphor-icons/react";
2
- type GrantMatchIconProps = {
3
- size?: number;
4
- };
5
- export declare const GrantMatchIcon: ({ size }: GrantMatchIconProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
1
  export * from "@phosphor-icons/react";
3
- import Image from "next/image";
4
- import grantMatchIcon from "../assets/icons/grant_match.webp";
5
- export const GrantMatchIcon = ({ size = 20 }) => (_jsx(Image, { src: grantMatchIcon, alt: "Grant Match", width: size, height: size }));
@@ -1,4 +1,4 @@
1
- export * as Breakpoints from "./breakpoints";
1
+ export * as Responsive from "./responsive";
2
2
  export * as Colors from "./colors";
3
3
  export * as Flags from "./flags";
4
4
  export * as Icons from "./icons";
@@ -1,4 +1,4 @@
1
- export * as Breakpoints from "./breakpoints";
1
+ export * as Responsive from "./responsive";
2
2
  export * as Colors from "./colors";
3
3
  export * as Flags from "./flags";
4
4
  export * as Icons from "./icons";
@@ -0,0 +1,3 @@
1
+ export declare const WIDTH_BREAKPOINTS: {
2
+ laptop: string;
3
+ };
@@ -0,0 +1,3 @@
1
+ export const WIDTH_BREAKPOINTS = {
2
+ laptop: "1024px",
3
+ };
@@ -1,3 +1,4 @@
1
+ export type ScreenSize = "big" | "small";
1
2
  export type Option = {
2
3
  label: string;
3
4
  value: string;
@@ -1,14 +1,10 @@
1
- export declare const FONT_SIZE_PIXELS_DESKTOP: {
2
- title: string;
3
- header: string;
4
- subheader: string;
5
- body: string;
6
- helper: string;
7
- };
8
- export declare const FONT_SIZE_PIXELS_MOBILE: {
9
- title: string;
10
- header: string;
11
- subheader: string;
12
- body: string;
13
- helper: string;
1
+ import { ScreenSize } from "./types";
2
+ type FontSizes = {
3
+ [screenSize in ScreenSize]: string;
14
4
  };
5
+ export declare const TITLE_FONT_SIZES: FontSizes;
6
+ export declare const HEADER_FONT_SIZES: FontSizes;
7
+ export declare const SUBHEADER_FONT_SIZES: FontSizes;
8
+ export declare const BODY_FONT_SIZES: FontSizes;
9
+ export declare const HELPER_FONT_SIZES: FontSizes;
10
+ export {};
@@ -1,14 +1,20 @@
1
- export const FONT_SIZE_PIXELS_DESKTOP = {
2
- title: "24px",
3
- header: "22px",
4
- subheader: "20px",
5
- body: "16px",
6
- helper: "14px",
7
- };
8
- export const FONT_SIZE_PIXELS_MOBILE = {
9
- title: "22px",
10
- header: "20px",
11
- subheader: "18px",
12
- body: "14px",
13
- helper: "12px",
1
+ export const TITLE_FONT_SIZES = {
2
+ big: "24px",
3
+ small: "22px",
4
+ };
5
+ export const HEADER_FONT_SIZES = {
6
+ big: "22px",
7
+ small: "20px",
8
+ };
9
+ export const SUBHEADER_FONT_SIZES = {
10
+ big: "20px",
11
+ small: "18px",
12
+ };
13
+ export const BODY_FONT_SIZES = {
14
+ big: "16px",
15
+ small: "14px",
16
+ };
17
+ export const HELPER_FONT_SIZES = {
18
+ big: "14px",
19
+ small: "12px",
14
20
  };
@@ -4,7 +4,7 @@ import { useState } from "react";
4
4
  import { useDropzone } from "react-dropzone";
5
5
  import styled from "styled-components";
6
6
  import { Badge } from "../atoms";
7
- import { Colors, Icons } from "../foundations";
7
+ import { Colors, Icons, Responsive, Typography } from "../foundations";
8
8
  const DEFAULT_MAX_FILE_SIZE_MB = 5;
9
9
  const DEFAULT_MAX_FILES = 5;
10
10
  const FileDrop = ({ uploadedFiles, uploadFiles, removeFile, errorMessage, maxFiles = DEFAULT_MAX_FILES, maxSizeMB = DEFAULT_MAX_FILE_SIZE_MB, }) => {
@@ -36,36 +36,47 @@ const Dropzone = styled.div `
36
36
  cursor: ${({ $reachedMaxUploads }) => $reachedMaxUploads ? "not-allowed" : "pointer"};
37
37
  }
38
38
  `;
39
- const DropzoneContent = ({ maxFiles, maxSizeMB }) => (_jsxs(BaseDropzoneContent, { children: [_jsx(Icons.FileDashedIcon, { weight: "thin", size: 48, color: Colors.neutral.grey1 }), _jsxs(DropzoneText, { children: [_jsx(DropzoneTitle, { children: `Drop up to ${maxFiles} files here ( ${maxSizeMB}MB each)` }), _jsx(DropzoneHighlightedSubtitle, { children: DROPZONE_BROWSE_TEXT }), _jsx(DropzoneSubtitle, { children: FILE_FORMAT_TEXT })] })] }));
39
+ const DropzoneContent = ({ maxFiles, maxSizeMB }) => (_jsxs(BaseDropzoneContent, { children: [_jsx(Icons.FileDashedIcon, { weight: "thin", size: 48, color: Colors.neutral.grey1 }), _jsxs(AllDropzoneText, { children: [_jsx(DropzoneText, { children: `Drop up to ${maxFiles} files here ( ${maxSizeMB}MB each)` }), _jsx(DropzoneSubtitle, { "$isHighlighted": true, children: DROPZONE_BROWSE_TEXT }), _jsx(DropzoneSubtitle, { children: FILE_FORMAT_TEXT })] })] }));
40
40
  const DROPZONE_BROWSE_TEXT = "or click to browse with your file explorer";
41
- const FILE_FORMAT_TEXT = "Accepted file formats: .pdf (Coming soon: .doc, .ppt, .csv)";
41
+ const FILE_FORMAT_TEXT = "Accepted file formats: .pdf (more coming soon)";
42
42
  const BaseDropzoneContent = styled.div `
43
43
  display: flex;
44
44
  flex-direction: column;
45
45
  gap: 24px;
46
46
  align-items: center;
47
47
  `;
48
- const DropzoneText = styled.div `
48
+ const AllDropzoneText = styled.div `
49
49
  display: flex;
50
50
  flex-direction: column;
51
51
  gap: 4px;
52
52
  `;
53
- const DropzoneTitle = styled.h3 `
54
- font-weight: 500;
55
- font-size: 14px;
53
+ const DropzoneText = styled.p `
56
54
  text-align: center;
57
- `;
58
- const DropzoneHighlightedSubtitle = styled.p `
59
- font-weight: 400;
60
- font-size: 12px;
61
- text-align: center;
62
- color: ${Colors.accent.yellow1};
55
+
56
+ font-weight: 500;
57
+
58
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
59
+ font-size: ${Typography.BODY_FONT_SIZES.small};
60
+ }
61
+
62
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
63
+ font-size: ${Typography.BODY_FONT_SIZES.big};
64
+ }
63
65
  `;
64
66
  const DropzoneSubtitle = styled.p `
65
- font-weight: 400;
66
- font-size: 12px;
67
67
  text-align: center;
68
- color: ${Colors.typography.blackLow};
68
+
69
+ font-weight: 400;
70
+
71
+ color: ${({ $isHighlighted = false }) => $isHighlighted ? Colors.accent.yellow1 : Colors.typography.blackLow};
72
+
73
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
74
+ font-size: ${Typography.HELPER_FONT_SIZES.small};
75
+ }
76
+
77
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
78
+ font-size: ${Typography.HELPER_FONT_SIZES.big};
79
+ }
69
80
  `;
70
81
  const ErrorMessage = styled.p `
71
82
  color: ${Colors.accent.red1};
@@ -5,10 +5,9 @@ type ModalProps = {
5
5
  footer?: ReactNode;
6
6
  width?: string;
7
7
  height?: string;
8
- isFullScreen?: boolean;
9
8
  onClickCancel: MouseEventHandler<HTMLButtonElement>;
10
9
  };
11
- declare const Modal: ({ header, content, footer, width, height, isFullScreen, onClickCancel, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
10
+ declare const Modal: ({ header, content, footer, width, height, onClickCancel, }: ModalProps) => import("react/jsx-runtime").JSX.Element;
12
11
  export default Modal;
13
12
  export declare const useModal: () => {
14
13
  showModal: boolean;
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useState } from "react";
4
- import styled, { css } from "styled-components";
4
+ import styled from "styled-components";
5
5
  import { Button } from "../atoms";
6
- import { Colors } from "../foundations";
7
- const Modal = ({ header, content, footer, width, height, isFullScreen, onClickCancel, }) => (_jsx(Overlay, { "$isFullScreen": isFullScreen, children: _jsxs(ModalWindow, { "$isFullScreen": isFullScreen, "$width": width, "$height": height, children: [header ? _jsx(ModalHeader, { children: header }) : _jsx(_Fragment, {}), _jsx(ModalBody, { children: content }), _jsxs(ModalFooter, { children: [_jsx(CancelButton, { onClick: onClickCancel }), footer ? footer : _jsx(_Fragment, {})] })] }) }));
6
+ import { Colors, Responsive } from "../foundations";
7
+ const Modal = ({ header, content, footer, width, height, onClickCancel, }) => (_jsx(Overlay, { children: _jsxs(ModalWindow, { "$width": width, "$height": height, children: [header ? _jsx(ModalHeader, { children: header }) : _jsx(_Fragment, {}), _jsx(ModalBody, { children: content }), _jsxs(ModalFooter, { children: [_jsx(CancelButton, { onClick: onClickCancel }), footer ? footer : _jsx(_Fragment, {})] })] }) }));
8
8
  export default Modal;
9
9
  export const useModal = () => {
10
10
  const [showModal, setShowModal] = useState(false);
@@ -31,7 +31,7 @@ export const useModal = () => {
31
31
  const Overlay = styled.div `
32
32
  background-color: ${Colors.semantic.overlay};
33
33
 
34
- z-index: ${({ $isFullScreen }) => $isFullScreen ? Number.MAX_SAFE_INTEGER - 1 : Number.MAX_SAFE_INTEGER};
34
+ z-index: ${Number.MAX_SAFE_INTEGER};
35
35
  position: fixed;
36
36
  top: 0px;
37
37
  left: 0px;
@@ -49,21 +49,31 @@ const ModalWindow = styled.div `
49
49
  flex-direction: column;
50
50
 
51
51
  background-color: ${Colors.base.white};
52
- border-radius: ${({ $isFullScreen }) => ($isFullScreen ? 0 : 6)}px;
53
-
54
- width: ${({ $isFullScreen, $width = "auto" }) => $isFullScreen ? "100%" : $width};
55
- height: ${({ $isFullScreen, $height = "auto" }) => $isFullScreen ? "100%" : $height};
56
52
 
57
53
  min-height: 100px;
58
54
  max-height: 100vh;
59
55
 
60
- ${({ $isFullScreen = false }) => $isFullScreen
61
- ? css `
62
- position: fixed;
63
- bottom: 0px;
64
- left: 0px;
65
- `
66
- : ""}
56
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
57
+ position: fixed;
58
+ bottom: 0px;
59
+ left: 0px;
60
+
61
+ width: 100%;
62
+ height: 100%;
63
+
64
+ border-radius: 0px;
65
+ }
66
+
67
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
68
+ position: static;
69
+ bottom: auto;
70
+ left: auto;
71
+
72
+ width: ${({ $width }) => $width};
73
+ height: ${({ $height }) => $height};
74
+
75
+ border-radius: 6px;
76
+ }
67
77
  `;
68
78
  const ModalHeader = styled.div `
69
79
  font-weight: 500;
@@ -1,14 +1,12 @@
1
+ import { GrantFilters } from "@grantbii/ui-base/grant/models";
1
2
  import { GrantMatchQuery } from "@grantbii/ui-base/match/models";
2
- type GrantMatchProps = GrantMatchQueryProps & {
3
- isSmallerThanLaptop?: boolean;
3
+ type GrantMatchProps = {
4
+ activeQuery: GrantMatchQuery;
5
+ updateActiveQuery: (newQuery: GrantMatchQuery) => void;
6
+ removeActiveQueryFile: (fileName: string) => void;
7
+ removeActiveQueryText: () => void;
8
+ resetActiveQuery: () => void;
4
9
  };
5
- declare const GrantMatch: ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }: GrantMatchProps) => import("react/jsx-runtime").JSX.Element;
10
+ declare const GrantMatch: ({ activeQuery, updateActiveQuery, removeActiveQueryFile, removeActiveQueryText, resetActiveQuery, }: GrantMatchProps) => import("react/jsx-runtime").JSX.Element;
6
11
  export default GrantMatch;
7
- type GrantMatchQueryProps = {
8
- query: GrantMatchQuery;
9
- updateQuery: (newQuery: GrantMatchQuery) => void;
10
- removeQueryFile: (fileName: string) => void;
11
- removeQueryText: () => void;
12
- resetQuery: () => void;
13
- };
14
- export declare const useGrantMatchQueryItems: (performGrantMatch: (newQuery: GrantMatchQuery) => void, resetGrantMatch: () => void) => GrantMatchQueryProps;
12
+ export declare const useGrantMatchActiveQuery: (filters: GrantFilters, performGrantMatch: (newQuery: GrantMatchQuery, filters: GrantFilters) => void, resetGrantMatch: () => void) => GrantMatchProps;
@@ -1,65 +1,50 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { isGrantMatchActive } from "@grantbii/ui-base/match/mappings";
4
4
  import { useState } from "react";
5
5
  import styled from "styled-components";
6
6
  import { Badge, Button, Textarea } from "../atoms";
7
- import { Colors, Icons } from "../foundations";
7
+ import { Colors, Icons, Responsive, Typography } from "../foundations";
8
8
  import { FileDrop, Modal, useFileDrop, useModal } from "../molecules";
9
- const GrantMatch = ({ query, updateQuery, removeQueryFile, removeQueryText, resetQuery, isSmallerThanLaptop, }) => {
9
+ const GrantMatch = ({ activeQuery, updateActiveQuery, removeActiveQueryFile, removeActiveQueryText, resetActiveQuery, }) => {
10
10
  const { showModal, openModal, closeModal } = useModal();
11
- const isActive = isGrantMatchActive(query);
12
- const updateActiveQuery = (newQuery) => {
13
- updateQuery(newQuery);
14
- closeModal();
15
- };
16
- return (_jsxs(BaseGrantMatch, { children: [_jsx(GrantMatchButtons, { isActive: isActive, onClickMatch: () => openModal(), onClickReset: () => resetQuery(), isSmallerThanLaptop: isSmallerThanLaptop }), isActive ? (_jsxs(QueryItemsRow, { children: [_jsx(QueryItems, { activeQuery: query, removeQueryFile: removeQueryFile, removeQueryText: removeQueryText }), isSmallerThanLaptop ? (_jsx(ResetButton, { onClick: () => resetQuery() })) : (_jsx(_Fragment, {}))] })) : (_jsx(_Fragment, {})), showModal ? (_jsx(GrantMatchModal, { activeQuery: query, updateActiveQuery: updateActiveQuery, onClickCancel: () => closeModal(), isFullScreen: isSmallerThanLaptop })) : (_jsx(_Fragment, {}))] }));
11
+ const isActive = isGrantMatchActive(activeQuery);
12
+ const [queryText, setQueryText] = useState(activeQuery.text);
13
+ const updateQueryText = (newText) => setQueryText(newText);
14
+ const onClickSearch = () => updateActiveQuery(Object.assign(Object.assign({}, activeQuery), { text: queryText }));
15
+ return (_jsxs(BaseGrantMatch, { children: [_jsx(GrantMatchActions, { queryText: queryText, updateQueryText: updateQueryText, onClickSearch: onClickSearch, onClickFileDrop: () => openModal(), onClickReset: () => resetActiveQuery(), isActive: isActive }), isActive ? (_jsxs(ActiveQueryRow, { children: [_jsx(ActiveQueryFiles, { activeQuery: activeQuery, removeQueryFile: removeActiveQueryFile, removeQueryText: removeActiveQueryText }), _jsx(SmallScreenResetButton, { onClick: () => resetActiveQuery() })] })) : (_jsx(_Fragment, {})), showModal ? (_jsx(GrantMatchModal, { activeQuery: activeQuery, updateActiveQuery: updateActiveQuery, queryText: queryText, updateQueryText: updateQueryText, closeModal: closeModal })) : (_jsx(_Fragment, {}))] }));
17
16
  };
18
17
  export default GrantMatch;
19
- export const useGrantMatchQueryItems = (performGrantMatch, resetGrantMatch) => {
20
- const [query, setQuery] = useState(() => (Object.assign({}, BLANK_GRANT_MATCH_QUERY)));
21
- const updateQuery = (newQuery) => {
22
- setQuery(Object.assign({}, newQuery));
23
- if (isGrantMatchActive(newQuery)) {
24
- performGrantMatch(newQuery);
18
+ // TODO: refactor
19
+ export const useGrantMatchActiveQuery = (filters, performGrantMatch, resetGrantMatch) => {
20
+ const [activeQuery, setActiveQuery] = useState(() => (Object.assign({}, BLANK_GRANT_MATCH_QUERY)));
21
+ const updateActiveQuery = (query) => {
22
+ setActiveQuery(Object.assign({}, query));
23
+ if (isGrantMatchActive(query)) {
24
+ performGrantMatch(query, filters);
25
25
  }
26
26
  else {
27
27
  resetGrantMatch();
28
28
  }
29
29
  };
30
- const removeQueryFile = (fileName) => {
30
+ const removeActiveQueryFile = (fileName) => {
31
31
  const newQuery = {
32
- files: query.files.filter((file) => file.name !== fileName),
33
- text: query.text,
32
+ files: activeQuery.files.filter((file) => file.name !== fileName),
33
+ text: activeQuery.text,
34
34
  };
35
- updateQuery(newQuery);
36
- if (isGrantMatchActive(newQuery)) {
37
- performGrantMatch(newQuery);
38
- }
39
- else {
40
- resetGrantMatch();
41
- }
42
- };
43
- const removeQueryText = () => {
44
- const newQuery = { files: query.files, text: "" };
45
- updateQuery(newQuery);
46
- if (isGrantMatchActive(newQuery)) {
47
- performGrantMatch(newQuery);
48
- }
49
- else {
50
- resetGrantMatch();
51
- }
35
+ updateActiveQuery(newQuery);
52
36
  };
53
- const resetQuery = () => {
54
- setQuery(Object.assign({}, BLANK_GRANT_MATCH_QUERY));
55
- resetGrantMatch();
37
+ const removeActiveQueryText = () => {
38
+ const newQuery = { files: activeQuery.files, text: "" };
39
+ updateActiveQuery(newQuery);
56
40
  };
41
+ const resetActiveQuery = () => updateActiveQuery(Object.assign({}, BLANK_GRANT_MATCH_QUERY));
57
42
  return {
58
- query,
59
- updateQuery,
60
- removeQueryFile,
61
- removeQueryText,
62
- resetQuery,
43
+ activeQuery,
44
+ updateActiveQuery,
45
+ removeActiveQueryFile,
46
+ removeActiveQueryText,
47
+ resetActiveQuery,
63
48
  };
64
49
  };
65
50
  const BLANK_GRANT_MATCH_QUERY = { files: [], text: "" };
@@ -71,50 +56,120 @@ const BaseGrantMatch = styled.div `
71
56
  width: 100%;
72
57
  max-width: 100vw;
73
58
  `;
74
- const GrantMatchButtons = ({ isActive, onClickMatch, onClickReset, isSmallerThanLaptop, }) => (_jsxs(Buttons, { children: [_jsx(GrantMatchButton, { isActive: isActive, isSmallerThanLaptop: isSmallerThanLaptop, onClick: onClickMatch }), !isSmallerThanLaptop && isActive ? (_jsx(ResetButton, { onClick: onClickReset })) : (_jsx(_Fragment, {}))] }));
75
- const Buttons = styled.div `
59
+ const GrantMatchActions = ({ queryText, updateQueryText, onClickSearch, onClickFileDrop, onClickReset, isActive, }) => (_jsxs(Actions, { children: [_jsxs(SearchBar, { "$isActive": isActive, children: [_jsx(Input, { value: queryText, onChange: (event) => updateQueryText(event.target.value), placeholder: "Find grants that match your needs" }), _jsx(SearchButton, { onClick: onClickSearch }), _jsx(FileDropButton, { onClick: onClickFileDrop })] }), isActive ? _jsx(BigScreenResetButton, { onClick: onClickReset }) : _jsx(_Fragment, {})] }));
60
+ const Actions = styled.div `
76
61
  display: flex;
77
62
  align-items: center;
78
63
  gap: 8px;
79
64
  `;
80
- const GrantMatchButton = ({ isActive, onClick, isSmallerThanLaptop, }) => (_jsxs(BaseGrantMatchButton, { type: "button", "$isSmallerThanLaptop": isSmallerThanLaptop, "$isActive": isActive, onClick: onClick, children: [_jsxs(GrantMatchButtonContent, { children: [_jsx(Icons.GrantMatchIcon, { size: 20 }), _jsx("p", { children: "Find grants that match your needs" })] }), _jsx(Icons.MagnifyingGlassIcon, { size: 20 })] }));
81
- const BaseGrantMatchButton = styled.button `
65
+ const SearchBar = styled.div `
82
66
  display: flex;
83
67
  align-items: center;
84
- justify-content: space-between;
85
- gap: 16px;
86
-
87
- padding: 10px 16px;
88
-
89
- height: 20px;
90
- width: ${({ $isSmallerThanLaptop = false }) => $isSmallerThanLaptop ? "100%" : "auto"};
91
68
 
92
- font-size: 14px;
93
- font-weight: 500;
69
+ padding: 6px 16px;
94
70
 
95
71
  background-color: ${Colors.base.white};
96
- color: ${Colors.typography.blackMedium};
72
+ color: ${Colors.typography.blackHigh};
97
73
 
98
74
  border: 1px solid
99
75
  ${({ $isActive }) => $isActive ? Colors.accent.yellow1 : Colors.neutral.grey3};
100
- border-radius: 200px;
76
+ border-radius: 12px;
77
+
78
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
79
+ gap: 8px;
80
+ width: 100%;
81
+ }
82
+
83
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
84
+ gap: 16px;
85
+ width: auto;
86
+ }
101
87
  `;
102
- const GrantMatchButtonContent = styled.div `
88
+ const Input = styled.input `
89
+ width: 300px;
90
+ border: none;
91
+ outline: none;
92
+ `;
93
+ const SearchButton = ({ onClick }) => (_jsx(BaseSearchButton, { type: "button", onClick: onClick, children: _jsx(Icons.MagnifyingGlassIcon, { size: 16, color: Colors.neutral.grey1 }) }));
94
+ const BaseSearchButton = styled.button `
103
95
  display: flex;
104
96
  align-items: center;
105
- gap: 8px;
97
+ justify-content: center;
98
+
99
+ height: 32px;
100
+ width: 32px;
101
+ min-width: 32px;
102
+
103
+ background-color: ${Colors.neutral.grey3};
104
+
105
+ border-radius: 8px;
106
+ `;
107
+ const FileDropButton = ({ onClick }) => (_jsxs(BaseFileDropButton, { onClick: onClick, children: [_jsx(Icons.FileArrowUpIcon, { size: 16 }), _jsx(FileDropButtonText, { children: "File Drop" })] }));
108
+ const BaseFileDropButton = styled.button `
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ gap: 4px;
113
+
114
+ height: 31px;
115
+ min-width: 31px;
116
+
117
+ background-color: ${Colors.base.white};
118
+ color: ${Colors.accent.blue1};
119
+
120
+ border: 1px solid ${Colors.accent.blue1};
121
+ border-radius: 8px;
122
+
123
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
124
+ padding: 0px;
125
+ font-size: ${Typography.HELPER_FONT_SIZES.small};
126
+ }
127
+
128
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
129
+ padding: 0px 8px;
130
+ font-size: ${Typography.HELPER_FONT_SIZES.big};
131
+ }
132
+ `;
133
+ const FileDropButtonText = styled.p `
134
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
135
+ display: none;
136
+ }
137
+
138
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
139
+ display: inline;
140
+ }
141
+ `;
142
+ const SmallScreenResetButton = ({ onClick }) => (_jsx(SmallScreenReset, { children: _jsx(ResetButton, { onClick: onClick }) }));
143
+ const SmallScreenReset = styled.div `
144
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
145
+ display: inline;
146
+ }
147
+
148
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
149
+ display: none;
150
+ }
151
+ `;
152
+ const BigScreenResetButton = ({ onClick }) => (_jsx(BigScreenReset, { children: _jsx(ResetButton, { onClick: onClick }) }));
153
+ const BigScreenReset = styled.div `
154
+ @media (width < ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
155
+ display: inline;
156
+ }
157
+
158
+ @media (width >= ${Responsive.WIDTH_BREAKPOINTS.laptop}) {
159
+ display: none;
160
+ }
106
161
  `;
107
162
  const ResetButton = ({ onClick }) => (_jsx(Button, { text: "Reset", onClick: onClick, color: Colors.typography.blackMedium, underline: true }));
108
- const QueryItemsRow = styled.div `
163
+ const ActiveQueryRow = styled.div `
109
164
  display: flex;
110
165
  align-items: center;
111
166
  justify-content: space-between;
112
167
  `;
113
- const QueryItems = ({ activeQuery, removeQueryFile, removeQueryText, }) => (_jsxs(BaseQueryItems, { children: [activeQuery.files.map((file) => {
114
- var _a;
115
- return (_jsx(Badge, { text: file.name, Icon: (_a = FILE_TYPE_ICON_MAP[file.type]) !== null && _a !== void 0 ? _a : Icons.FileIcon, onClickClose: () => removeQueryFile(file.name), textWidthPixels: 160 }, file.name));
116
- }), activeQuery.text === "" ? (_jsx(_Fragment, {})) : (_jsx(Badge, { text: "Additional Information", Icon: Icons.TextAaIcon, onClickClose: () => removeQueryText(), textWidthPixels: 180 }, "additional-information-query-item"))] }));
117
- const BaseQueryItems = styled.div `
168
+ const ActiveQueryFiles = ({ activeQuery, removeQueryFile, }) => (_jsx(BaseActiveQueryFiles, { children: activeQuery.files.map((file) => {
169
+ var _a;
170
+ return (_jsx(Badge, { text: file.name, Icon: (_a = FILE_TYPE_ICON_MAP[file.type]) !== null && _a !== void 0 ? _a : Icons.FileIcon, onClickClose: () => removeQueryFile(file.name), textWidthPixels: 160 }, file.name));
171
+ }) }));
172
+ const BaseActiveQueryFiles = styled.div `
118
173
  display: flex;
119
174
  align-items: center;
120
175
  gap: 8px;
@@ -135,19 +190,16 @@ const BaseQueryItems = styled.div `
135
190
  const FILE_TYPE_ICON_MAP = {
136
191
  "application/pdf": Icons.FilePdfIcon,
137
192
  };
138
- const GrantMatchModal = ({ activeQuery, updateActiveQuery, onClickCancel, isFullScreen, }) => {
193
+ const GrantMatchModal = ({ activeQuery, updateActiveQuery, queryText, updateQueryText, closeModal, }) => {
139
194
  const { files, uploadFiles, removeFile } = useFileDrop(activeQuery.files);
140
- const [text, setText] = useState(activeQuery.text);
141
- return (_jsx(Modal, { header: _jsx(Header, {}), content: _jsx(Content, { files: files, uploadFiles: uploadFiles, removeFile: removeFile, queryText: text, updateQueryText: (newText) => setText(newText) }), footer: _jsx(Button, { text: "Find My Grants", onClick: () => updateActiveQuery({ files, text }), backgroundColor: Colors.accent.yellow1 }), onClickCancel: onClickCancel, isFullScreen: isFullScreen, width: "480px", height: "600px" }));
195
+ const onClickFind = () => {
196
+ updateActiveQuery({ files, text: queryText });
197
+ closeModal();
198
+ };
199
+ return (_jsx(Modal, { header: _jsx("div", { children: "Grant Match" }), content: _jsx(Content, { files: files, uploadFiles: uploadFiles, removeFile: removeFile, queryText: queryText, updateQueryText: updateQueryText }), footer: _jsx(Button, { text: "Find My Grants", onClick: onClickFind, backgroundColor: Colors.accent.yellow1 }), onClickCancel: () => closeModal(), width: "480px", height: "600px" }));
142
200
  };
143
- const Header = () => (_jsxs(BaseHeader, { children: [_jsx(Icons.GrantMatchIcon, { size: 24 }), _jsx("div", { children: "Grant Match" })] }));
144
- const BaseHeader = styled.div `
145
- display: flex;
146
- align-items: center;
147
- gap: 12px;
148
- `;
149
- const Content = ({ files, uploadFiles, removeFile, queryText, updateQueryText, }) => (_jsxs(BaseContent, { children: [_jsx(FileDrop, { uploadedFiles: files, uploadFiles: uploadFiles, removeFile: removeFile }), _jsxs(QueryText, { children: [_jsx("label", { htmlFor: ADDITIONAL_INFORMATION_ID, children: "Additional Information" }), _jsx(Textarea, { id: ADDITIONAL_INFORMATION_ID, value: queryText, onChange: (event) => updateQueryText(event.target.value) })] })] }));
150
- const ADDITIONAL_INFORMATION_ID = "grant-match-additional-information";
201
+ const Content = ({ files, uploadFiles, removeFile, queryText, updateQueryText, }) => (_jsxs(BaseContent, { children: [_jsx(FileDrop, { uploadedFiles: files, uploadFiles: uploadFiles, removeFile: removeFile }), _jsxs(QueryText, { children: [_jsx("label", { htmlFor: QUERY_TEXTAREA_ID, children: "Search Grants Opportunities" }), _jsx(Textarea, { id: QUERY_TEXTAREA_ID, value: queryText, onChange: (event) => updateQueryText(event.target.value), placeholder: "Explore by grant name or share what your project is about..." })] })] }));
202
+ const QUERY_TEXTAREA_ID = "query-textarea";
151
203
  const BaseContent = styled.div `
152
204
  display: flex;
153
205
  flex-direction: column;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grantbii/design-system",
3
- "version": "1.0.66",
3
+ "version": "1.0.67",
4
4
  "description": "Grantbii's Design System",
5
5
  "homepage": "https://design.grantbii.com",
6
6
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "build-storybook": "storybook build"
19
19
  },
20
20
  "dependencies": {
21
- "@grantbii/ui-base": "1.0.17",
21
+ "@grantbii/ui-base": "1.0.18",
22
22
  "@phosphor-icons/react": "^2.1.10",
23
23
  "country-flag-icons": "^1.5.19",
24
24
  "next": "^15.5.0",
@@ -6,13 +6,10 @@ type ModalExampleProps = {
6
6
  footer?: ReactNode;
7
7
  width?: string;
8
8
  height?: string;
9
- isFullScreen?: boolean;
10
9
  };
11
10
  declare const ModalExample: (props: ModalExampleProps) => import("react/jsx-runtime").JSX.Element;
12
11
  declare const meta: Meta<typeof ModalExample>;
13
12
  export default meta;
14
13
  type Story = StoryObj<typeof meta>;
15
- export declare const PopUpWithShortContent: Story;
16
- export declare const FullScreenWithShortContent: Story;
17
- export declare const PopUpWithLongContent: Story;
18
- export declare const FullScreenWithLongContent: Story;
14
+ export declare const ShortContent: Story;
15
+ export declare const LongContent: Story;
@@ -16,32 +16,19 @@ export default meta;
16
16
  const header = "Grantbii";
17
17
  const shortContent = (_jsx("p", { children: "Amplifying Business Grant Impact for SMEs & Scale-ups" }));
18
18
  const longContent = (_jsxs("div", { children: [_jsx("p", { children: "Grantbii is an AI-powered grant intelligence and matching platform that helps grant seekers effortlessly find, match, prep & apply for the right business grants - maximizing grant funding success with minimal effort. Our platform connects businesses with a trusted Grant Enabler Network - solution providers, consulting experts, and delivery partners - ensuring that every dollar of grant funding leads to real business transformation impact." }), _jsx("p", { children: "In the future, Grantbii aims to automate the entire grant application lifecycle, from discovery to claims submission and guide you through the application process with minimal effort on your part." }), _jsx("p", { children: "To maximize your chances of grant success, you can expect to leverage on tools to assess your chances of success and offer expert support to ensure your application meets all necessary requirements." })] }));
19
- export const PopUpWithShortContent = {
19
+ export const ShortContent = {
20
20
  args: {
21
21
  header,
22
22
  content: shortContent,
23
23
  width: "600px",
24
+ height: "360px",
24
25
  },
25
26
  };
26
- export const FullScreenWithShortContent = {
27
- args: {
28
- header,
29
- content: shortContent,
30
- isFullScreen: true,
31
- },
32
- };
33
- export const PopUpWithLongContent = {
27
+ export const LongContent = {
34
28
  args: {
35
29
  header,
36
30
  content: longContent,
37
31
  width: "600px",
38
- height: "240px",
39
- },
40
- };
41
- export const FullScreenWithLongContent = {
42
- args: {
43
- header,
44
- content: longContent,
45
- isFullScreen: true,
32
+ height: "360px",
46
33
  },
47
34
  };
@@ -1,10 +1,6 @@
1
1
  import { Meta, StoryObj } from "@storybook/nextjs-vite";
2
- type GrantMatchExampleProps = {
3
- isMobile?: boolean;
4
- };
5
- declare const GrantMatchExample: ({ isMobile }: GrantMatchExampleProps) => import("react/jsx-runtime").JSX.Element;
2
+ declare const GrantMatchExample: () => import("react/jsx-runtime").JSX.Element;
6
3
  declare const meta: Meta<typeof GrantMatchExample>;
7
4
  export default meta;
8
5
  type Story = StoryObj<typeof meta>;
9
- export declare const Desktop: Story;
10
- export declare const Mobile: Story;
6
+ export declare const Example: Story;