From dfb8ffb94b2e61127a3f3442aea052cccd47cfe9 Mon Sep 17 00:00:00 2001 From: 0ry5 <oscar.bloch@posteo.de> Date: Fri, 13 Sep 2024 18:53:35 +0200 Subject: [PATCH 1/5] test --- .gitignore | 3 ++ createMR.py | 55 ++++++++++++++++++++++++++++++ createMR.sh | 79 +++++++++++++++++++++++++++++++++++++++++++ frontend/.gitignore | 1 + issues | 1 + middleware/.gitignore | 2 ++ 6 files changed, 141 insertions(+) create mode 100644 .gitignore create mode 100644 createMR.py create mode 100644 createMR.sh create mode 100644 frontend/.gitignore create mode 100644 issues create mode 100644 middleware/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c7e834 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +n39env +.vscode \ No newline at end of file diff --git a/createMR.py b/createMR.py new file mode 100644 index 0000000..699c2ac --- /dev/null +++ b/createMR.py @@ -0,0 +1,55 @@ +import os +import json +import argparse +from git import Repo +from pyforgejo import AuthenticatedClient +from dotenv import load_dotenv +from pyforgejo.api.issue import issue_list_issues +from pyforgejo.api.repository import repo_create_branch, repo_create_pull_request +from pyforgejo.models import CreateBranchRepoOption, CreatePullRequestOption + +load_dotenv() + +parser = argparse.ArgumentParser(description="") +parser.add_argument("-i", "--issue") +args = parser.parse_args() + +FORJEGO_ACCESS_TOKEN = os.getenv("FORJEGO_ACCESS_TOKEN") +OWNER = os.getenv("OWNER") +USER = os.getenv("USER") +REPO = os.getenv("REPO") + +client = AuthenticatedClient( + base_url="https://git.n39.eu/api/v1/", token=FORJEGO_ACCESS_TOKEN +) + +issues = json.loads(issue_list_issues.sync_detailed(OWNER, REPO, client=client).content) + + +def filterIssues(issue): + return args.issue in issue["title"] + + +issues = list(filter(filterIssues, issues)) + +branchName = issues[0]["title"].replace(" ", "-") + +if len(issues) > 1: + raise ValueError("found more than one ticket") +if len(issues) == 0: + raise ValueError("found more than one ticket") +else: + repo_create_branch.sync_detailed( + OWNER, REPO, body=CreateBranchRepoOption(branchName, "main"), client=client + ) + res = json.loads( + repo_create_pull_request.sync_detailed( + OWNER, + REPO, + body=CreatePullRequestOption( + base=branchName, head="main", title="merge" + branchName + ), + client=client, + ).content + ) + print(res) diff --git a/createMR.sh b/createMR.sh new file mode 100644 index 0000000..d7da326 --- /dev/null +++ b/createMR.sh @@ -0,0 +1,79 @@ +source './.env' + +PASSED_ISSUE='' + +while test $# -gt 0; do + case "$1" in + -i|--issue) + shift + if test $# -gt 0 + then + export PASSED_ISSUE=$1 + fi + shift + ;; + -h|--help) print_usage ;; + *) print_usage + break + ;; + esac +done + +if [[ -z $PASSED_ISSUE ]] +then + echo -e "missing issue; use -i \e[3missue\e[0m" + exit 1 +fi + +printf "\n" + +ISSUES=$(curl -X 'GET' \ + 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/issues' \ + -H 'accept: application/json' | tr ' ' -) + +printf "\n" +echo $ISSUES + +ISSUE=$(jq '.[] | select(.title|test("'$PASSED_ISSUE'"))' <<< $ISSUES) + +printf "\n" +echo $ISSUE + +NAME=$(jq '.title' <<< $ISSUE) + +printf "\n" +echo $NAME + +BRANCH=$(curl -X 'POST' 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/branches' \ + -H "accept: application/json" \ + -H 'Authorization: token '${FORJEGO_ACCESS_TOKEN} \ + -H "Content-Type: application/json" -d '{"new_branch_name": '$NAME', "old_branch_name": "main"}' -i) + +echo $BRANCH + +USER=$(git config --global user.name) + +MR=$(curl -X 'POST' 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/pulls' \ + -H "accept: application/json" \ + -H 'Authorization: token '${FORJEGO_ACCESS_TOKEN} \ + -H "Content-Type: application/json" -d '{ + "assignee": "'$USER'", + "assignees": [ + "string" + ], + "base": "string", + "body": "string", + "head": "string", + "labels": [ + 0 + ], + "milestone": 0, + "title": "string" + }' -i) + +USER=$(git checkout $BRANCH) + + +#git browse -- issues +#git checkout -b '' +#git push -o merge_request.create origin my-branch \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/issues b/issues new file mode 100644 index 0000000..7bb88ed --- /dev/null +++ b/issues @@ -0,0 +1 @@ +[{"id":844,"url":"https://git.n39.eu/api/v1/repos/0Ry5/n39librarian/issues/5","html_url":"https://git.n39.eu/0Ry5/n39librarian/issues/5","number":5,"user":{"id":118,"login":"0Ry5","login_name":"","full_name":"","email":"0ry5@git.n39.eu","avatar_url":"https://git.n39.eu/avatar/b3977e6b4b95a3a537127207119712a2","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2024-09-09T20:35:12+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"0Ry5"},"original_author":"","original_author_id":0,"title":"checkout modal can be submitted if its invalid","body":"","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2024-09-13T14:25:22+02:00","updated_at":"2024-09-13T14:25:22+02:00","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":65,"name":"n39librarian","owner":"0Ry5","full_name":"0Ry5/n39librarian"},"pin_order":0},{"id":843,"url":"https://git.n39.eu/api/v1/repos/0Ry5/n39librarian/issues/4","html_url":"https://git.n39.eu/0Ry5/n39librarian/issues/4","number":4,"user":{"id":118,"login":"0Ry5","login_name":"","full_name":"","email":"0ry5@git.n39.eu","avatar_url":"https://git.n39.eu/avatar/b3977e6b4b95a3a537127207119712a2","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2024-09-09T20:35:12+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"0Ry5"},"original_author":"","original_author_id":0,"title":"undefined should not be a valid input for the checkout modal","body":"","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2024-09-13T14:25:07+02:00","updated_at":"2024-09-13T14:25:07+02:00","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":65,"name":"n39librarian","owner":"0Ry5","full_name":"0Ry5/n39librarian"},"pin_order":0},{"id":839,"url":"https://git.n39.eu/api/v1/repos/0Ry5/n39librarian/issues/3","html_url":"https://git.n39.eu/0Ry5/n39librarian/issues/3","number":3,"user":{"id":118,"login":"0Ry5","login_name":"","full_name":"","email":"0ry5@git.n39.eu","avatar_url":"https://git.n39.eu/avatar/b3977e6b4b95a3a537127207119712a2","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2024-09-09T20:35:12+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"0Ry5"},"original_author":"","original_author_id":0,"title":"add unit tests","body":"","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2024-09-09T20:49:52+02:00","updated_at":"2024-09-09T20:49:52+02:00","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":65,"name":"n39librarian","owner":"0Ry5","full_name":"0Ry5/n39librarian"},"pin_order":0},{"id":838,"url":"https://git.n39.eu/api/v1/repos/0Ry5/n39librarian/issues/2","html_url":"https://git.n39.eu/0Ry5/n39librarian/issues/2","number":2,"user":{"id":118,"login":"0Ry5","login_name":"","full_name":"","email":"0ry5@git.n39.eu","avatar_url":"https://git.n39.eu/avatar/b3977e6b4b95a3a537127207119712a2","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2024-09-09T20:35:12+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"0Ry5"},"original_author":"","original_author_id":0,"title":"try google-books api for book identification by isbn","body":"https://www.npmjs.com/package/@googleapis/books\r\n\r\nadd to CreateBookModal","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2024-09-09T20:49:15+02:00","updated_at":"2024-09-09T20:49:15+02:00","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":65,"name":"n39librarian","owner":"0Ry5","full_name":"0Ry5/n39librarian"},"pin_order":0},{"id":837,"url":"https://git.n39.eu/api/v1/repos/0Ry5/n39librarian/issues/1","html_url":"https://git.n39.eu/0Ry5/n39librarian/issues/1","number":1,"user":{"id":118,"login":"0Ry5","login_name":"","full_name":"","email":"0ry5@git.n39.eu","avatar_url":"https://git.n39.eu/avatar/b3977e6b4b95a3a537127207119712a2","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2024-09-09T20:35:12+02:00","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"0Ry5"},"original_author":"","original_author_id":0,"title":"Darkmode","body":"","ref":"","assets":[],"labels":[],"milestone":null,"assignee":null,"assignees":null,"state":"open","is_locked":false,"comments":0,"created_at":"2024-09-09T20:48:27+02:00","updated_at":"2024-09-09T20:48:27+02:00","closed_at":null,"due_date":null,"pull_request":null,"repository":{"id":65,"name":"n39librarian","owner":"0Ry5","full_name":"0Ry5/n39librarian"},"pin_order":0}] diff --git a/middleware/.gitignore b/middleware/.gitignore new file mode 100644 index 0000000..db4c6d9 --- /dev/null +++ b/middleware/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules \ No newline at end of file From af569cbde626c556864ebc6ddcf37dcfde4e5b2a Mon Sep 17 00:00:00 2001 From: 0ry5 <oscar.bloch@posteo.de> Date: Fri, 13 Sep 2024 19:00:18 +0200 Subject: [PATCH 2/5] remove shell script --- createMR.py | 2 +- createMR.sh | 79 ----------------------------------------------------- 2 files changed, 1 insertion(+), 80 deletions(-) delete mode 100644 createMR.sh diff --git a/createMR.py b/createMR.py index 699c2ac..7026c71 100644 --- a/createMR.py +++ b/createMR.py @@ -47,7 +47,7 @@ else: OWNER, REPO, body=CreatePullRequestOption( - base=branchName, head="main", title="merge" + branchName + base="main", head=branchName, title="merge-" + branchName ), client=client, ).content diff --git a/createMR.sh b/createMR.sh deleted file mode 100644 index d7da326..0000000 --- a/createMR.sh +++ /dev/null @@ -1,79 +0,0 @@ -source './.env' - -PASSED_ISSUE='' - -while test $# -gt 0; do - case "$1" in - -i|--issue) - shift - if test $# -gt 0 - then - export PASSED_ISSUE=$1 - fi - shift - ;; - -h|--help) print_usage ;; - *) print_usage - break - ;; - esac -done - -if [[ -z $PASSED_ISSUE ]] -then - echo -e "missing issue; use -i \e[3missue\e[0m" - exit 1 -fi - -printf "\n" - -ISSUES=$(curl -X 'GET' \ - 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/issues' \ - -H 'accept: application/json' | tr ' ' -) - -printf "\n" -echo $ISSUES - -ISSUE=$(jq '.[] | select(.title|test("'$PASSED_ISSUE'"))' <<< $ISSUES) - -printf "\n" -echo $ISSUE - -NAME=$(jq '.title' <<< $ISSUE) - -printf "\n" -echo $NAME - -BRANCH=$(curl -X 'POST' 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/branches' \ - -H "accept: application/json" \ - -H 'Authorization: token '${FORJEGO_ACCESS_TOKEN} \ - -H "Content-Type: application/json" -d '{"new_branch_name": '$NAME', "old_branch_name": "main"}' -i) - -echo $BRANCH - -USER=$(git config --global user.name) - -MR=$(curl -X 'POST' 'https://git.n39.eu/api/v1/repos/'$OWNER'/'$REPO'/pulls' \ - -H "accept: application/json" \ - -H 'Authorization: token '${FORJEGO_ACCESS_TOKEN} \ - -H "Content-Type: application/json" -d '{ - "assignee": "'$USER'", - "assignees": [ - "string" - ], - "base": "string", - "body": "string", - "head": "string", - "labels": [ - 0 - ], - "milestone": 0, - "title": "string" - }' -i) - -USER=$(git checkout $BRANCH) - - -#git browse -- issues -#git checkout -b '' -#git push -o merge_request.create origin my-branch \ No newline at end of file From f35c4c473d5040f1aa7d5ebf34b2af6fa226c623 Mon Sep 17 00:00:00 2001 From: 0ry5 <oscar.bloch@posteo.de> Date: Fri, 13 Sep 2024 19:38:46 +0200 Subject: [PATCH 3/5] feat(GoogleApi): add google api to BookModal --- .../shared/components/modals/BookModal.tsx | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/frontend/src/shared/components/modals/BookModal.tsx b/frontend/src/shared/components/modals/BookModal.tsx index fb852c1..5c086b6 100644 --- a/frontend/src/shared/components/modals/BookModal.tsx +++ b/frontend/src/shared/components/modals/BookModal.tsx @@ -29,7 +29,20 @@ export const BookModal = ({ }, [book, reset]); const { scannerError, setScannerRef } = useScanner({ - onDetected: (result) => { + onDetected: async (result) => { + const googleBooks = await ( + await fetch( + "https://www.googleapis.com/books/v1/volumes?q=isbn:" + result + ) + ).json(); + if ("items" in googleBooks) { + console.log(googleBooks); + setValue( + "published", + googleBooks.items[0].volumeInfo.publishedDate.substring(0, 4) + ); + setValue("title", googleBooks.items[0].volumeInfo.title); + } setValue("isbn", result); setShowScanner(false); }, @@ -38,6 +51,7 @@ export const BookModal = ({ const values = useWatch({ control }); const [submitError, setSubmitError] = useState<string | undefined>(); + const onSubmit = useCallback( async (data: Partial<BookForm>) => { setSubmitError(undefined); @@ -89,7 +103,7 @@ export const BookModal = ({ <ModalHeader onClose={onClose} title={`${!!book ? "Edit" : "Add new"} Book`} - icon={<ImBook size={50} className="ml-0 mr-auto" />} + icon={<ImBook size={50} className='ml-0 mr-auto' />} /> <Modal.Body style={{ @@ -100,18 +114,18 @@ export const BookModal = ({ > {!showScanner && ( <Form - className="mb-2" + className='mb-2' onSubmit={(ev) => { ev.preventDefault(); onSubmit(values); }} > - <Form.Group as={Row} className="mb-2"> - <Col sm="2"> + <Form.Group as={Row} className='mb-2'> + <Col sm='2'> <Form.Label>ISBN</Form.Label> </Col> - <Col className="d-flex flex-column"> - <div className="d-flex"> + <Col className='d-flex flex-column'> + <div className='d-flex'> <Form.Control {...register("isbn", { required: true, maxLength: 360 })} isInvalid={!!formState.errors.isbn} @@ -126,7 +140,7 @@ export const BookModal = ({ color: "black", border: "2px solid black", }} - className="mr-2 pt-0" + className='mr-2 pt-0' disabled={showScanner} onClick={() => setShowScanner(true)} > @@ -135,7 +149,7 @@ export const BookModal = ({ </div> <Form.Control.Feedback style={{ display: !formState.errors.isbn ? "none" : "block" }} - type="invalid" + type='invalid' > {!formState.errors.isbn ? "ISBN is required" @@ -143,8 +157,8 @@ export const BookModal = ({ </Form.Control.Feedback> </Col> </Form.Group> - <Form.Group as={Row} className="mb-2"> - <Col sm="2"> + <Form.Group as={Row} className='mb-2'> + <Col sm='2'> <Form.Label>Title</Form.Label> </Col> <Col> @@ -153,15 +167,15 @@ export const BookModal = ({ isInvalid={!!formState.errors.title} /> - <Form.Control.Feedback type="invalid"> + <Form.Control.Feedback type='invalid'> {!values.title ? "Title is required" : formState.errors.title?.message} </Form.Control.Feedback> </Col> </Form.Group> - <Form.Group as={Row} className="mb-2"> - <Col sm="2"> + <Form.Group as={Row} className='mb-2'> + <Col sm='2'> <Form.Label>Year published</Form.Label> </Col> <Col> @@ -187,15 +201,15 @@ export const BookModal = ({ isInvalid={!!formState.errors.published} /> - <Form.Control.Feedback type="invalid"> + <Form.Control.Feedback type='invalid'> {!values.published ? "Year published is required" : formState.errors.published?.message} </Form.Control.Feedback> </Col> </Form.Group> - <Form.Group as={Row} className="mb-2"> - <Col sm="2"> + <Form.Group as={Row} className='mb-2'> + <Col sm='2'> <Form.Label>Shelf</Form.Label> </Col> <Col> @@ -205,21 +219,21 @@ export const BookModal = ({ > {Object.keys(bookShelfs).map((key) => ( <option - key="key" + key='key' value={bookShelfs[key as keyof typeof bookShelfs]} > {key} </option> ))} </Form.Select> - <Form.Control.Feedback type="invalid"> + <Form.Control.Feedback type='invalid'> {!values.shelf ? "Shelf is required" : formState.errors.shelf?.message} </Form.Control.Feedback> </Col> </Form.Group> - <div className="d-flex mx-auto mb-auto mt-2 w-100"> + <div className='d-flex mx-auto mb-auto mt-2 w-100'> <Button style={{ borderRadius: "5px", @@ -238,12 +252,12 @@ export const BookModal = ({ )} {showScanner && ( <div - className="w-100 overflow-hidden" + className='w-100 overflow-hidden' ref={(ref) => setScannerRef(ref)} style={{ position: "relative", height: "25vh" }} > <canvas - className="drawingBuffer w-100 position-absolute" + className='drawingBuffer w-100 position-absolute' style={{ height: "100%", border: "2px solid black", @@ -258,7 +272,7 @@ export const BookModal = ({ </p> ) : null} {!!submitError && ( - <Form.Control.Feedback style={{ display: "block" }} type="invalid"> + <Form.Control.Feedback style={{ display: "block" }} type='invalid'> {submitError} </Form.Control.Feedback> )} From 6940fab53a5c1902f698b48050e15ddd3207967d Mon Sep 17 00:00:00 2001 From: 0ry5 <oscar.bloch@posteo.de> Date: Fri, 13 Sep 2024 19:46:16 +0200 Subject: [PATCH 4/5] fix(CheckoutModal): no submit if invalid form --- .../src/shared/components/modals/CheckoutModal.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/shared/components/modals/CheckoutModal.tsx b/frontend/src/shared/components/modals/CheckoutModal.tsx index 79d69ac..d3eb42c 100644 --- a/frontend/src/shared/components/modals/CheckoutModal.tsx +++ b/frontend/src/shared/components/modals/CheckoutModal.tsx @@ -30,6 +30,9 @@ export const CheckoutBookModal = ({ const onSubmit = useCallback( async (data: Partial<BookCheckoutForm>) => { + if (!formState.isValid) { + return; + } if (!data.checkoutBy) { setError("checkoutBy", { message: `please enter ${ @@ -61,7 +64,7 @@ export const CheckoutBookModal = ({ setFailed(await res.text()); } }, - [uuid, onClose, setError, isChechout] + [formState.isValid, isChechout, uuid, setError, onClose] ); return ( @@ -116,6 +119,12 @@ export const CheckoutBookModal = ({ "'null' is not a valid nickname" ); }, + notUndefinedString: (value) => { + return ( + value?.toLocaleLowerCase() !== "undefined" || + "'undefined' is not a valid nickname" + ); + }, }, })} isInvalid={!!formState.errors.checkoutBy} @@ -184,6 +193,7 @@ export const CheckoutBookModal = ({ marginLeft: "auto", marginRight: "10px", }} + disabled={!formState.isValid} onClick={() => onSubmit(values)} > {`${isChechout ? "Checkout" : "Return"} book`} From 2016a8619d2824d42e6b25b57607d87feabfe1a6 Mon Sep 17 00:00:00 2001 From: 0ry5 <oscar.bloch@posteo.de> Date: Fri, 13 Sep 2024 21:28:03 +0200 Subject: [PATCH 5/5] feat(Darkmode): add Darkmode --- frontend/src/App.tsx | 3 +- frontend/src/darkmodeColors.ts | 5 + frontend/src/index.css | 227 +++++++++++++++--- .../src/pages/Library/components/Actions.tsx | 34 +-- frontend/src/pages/Main/Main.tsx | 17 -- .../components/modals/AuthenticationModal.tsx | 16 +- .../shared/components/modals/BookModal.tsx | 17 +- .../components/modals/CheckoutModal.tsx | 14 +- .../components/modals/DeleteBookModal.tsx | 17 +- .../shared/components/modals/ModalHeader.tsx | 11 +- .../shared/components/modals/ScannerModal.tsx | 14 +- 11 files changed, 216 insertions(+), 159 deletions(-) create mode 100644 frontend/src/darkmodeColors.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f86f282..b2dae2a 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -6,7 +6,7 @@ import "./App.css"; import { Main } from "./pages"; import { Library } from "./pages/Library"; import { Book } from "./pages/Book"; -import { primary } from "./colors"; +import * as colors from "./colors"; import { ActiveModalProps } from "./shared/components/modals/types"; export const AuthContext = createContext<{ @@ -50,7 +50,6 @@ function App() { style={{ height: "100vh", width: "100vw", - backgroundColor: primary, fontFamily: "New Amsterdam", overflow: "scroll", }} diff --git a/frontend/src/darkmodeColors.ts b/frontend/src/darkmodeColors.ts new file mode 100644 index 0000000..61021a2 --- /dev/null +++ b/frontend/src/darkmodeColors.ts @@ -0,0 +1,5 @@ +export const primary = "#5e6268"; +export const primaryRGBA = "rgba(83,86,91, 0.8)"; +export const secondary = "#5f5e68"; +export const tertiary = "#5e6768"; +export const danger = "#685e62"; diff --git a/frontend/src/index.css b/frontend/src/index.css index 336c05e..052c22e 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -12,49 +12,208 @@ body { } } -#bootstrap-overrides .form-select .form-control { - background-color: #f2f2e8 !important; - border-color: #f2f2e8 !important; +#bootstrap-overrides { + background-color: #f2f3f4; + color: #5e6268; + + .btn-primary { + background-color: #5e6268; + color: #f2f3f4; + border: 2px solid #5e6268; + } + + form-control { + background-color: #f2f2e8 !important; + border-color: #5e6268 !important; + } + + .form-select .form-control { + background-color: #f2f2e8 !important; + border-color: #f2f2e8 !important; + } + + .dropdown-toggle::after { + display: none; + } + + .form-label { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", + "Helvetica Neue", sans-serif !important; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + letter-spacing: normal; + } + + .table > :not(caption) > * > * { + background-color: #f2f2e8 !important; + color: #5e6268 !important; + } + + table { + letter-spacing: 0.25em; + } + + .bg-primary { + background-color: #f2f3f4 !important; + } + + .modal-content { + background-color: #f2f3f4 !important; + border-radius: 10px; + } + + .modal-body { + background-color: #f2f3f4 !important; + border-radius: 0px 0px 10px 10px; + } + + .modal-header { + background-color: #f2f3f4 !important; + border-radius: 10px 10px 0px 0px; + border-bottom: none; + } + + .dropdown button { + background-color: #f2f2e8 !important; + color: #5e6268 !important; + border: 2px solid #5e6268; + } + + .dropdown-menu { + background-color: #f2f2e8 !important; + color: #5e6268 !important; + border: 2px solid #f2f2e8; + } + + .danger { + background-color: #f9a9ab !important; + } + + .page-link { + color: #5e6268 !important; + border: 2px solid #5e6268 !important; + background-color: transparent !important; + } + + .active > .page-link { + background-color: #5e6268 !important; + color: #f2f3f4 !important; + } + + .pagination { + margin-top: 10px !important; + + li { + min-width: 40px; + } + } } -#bootstrap-overrides .dropdown-toggle::after { - display: none; -} +@media (prefers-color-scheme: dark) { + #bootstrap-overrides { + background-color: #5e6268; + color: #f2f3f4; -#bootstrap-overrides .form-label { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif !important; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - letter-spacing: normal; -} + .btn-primary { + background-color: #f2f3f4; + color: #5e6268; + border: 2px solid #5e6268; + } -#bootstrap-overrides table { - letter-spacing: 0.25em; -} + .form-control { + background-color: #f2f2e8 !important; + border-color: #5e6268 !important; + border-right: none; + } -#bootstrap-overrides .bg-primary { - background-color: #f2f3f4 !important; -} + .form-select .form-control { + background-color: #f2f2e8 !important; + border-color: #f2f2e8 !important; + } -#bootstrap-overrides .modal-body { - background-color: #f2f3f4 !important; -} + .dropdown-toggle::after { + display: none; + } -#bootstrap-overrides .danger { - background-color: #f9a9ab !important; -} + .form-label { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", + "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", + "Helvetica Neue", sans-serif !important; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + letter-spacing: normal; + } -#bootstrap-overrides .page-link { - color: black !important; - border: 2px solid black !important; - background-color: transparent !important; -} + .table > :not(caption) > * > * { + background-color: #5e6268 !important; + color: #f2f2e8 !important; + } -#bootstrap-overrides .active > .page-link { - background-color: black !important; - color: #f2f3f4 !important; + table { + letter-spacing: 0.25em; + } + + .bg-primary { + background-color: #5e6268 !important; + } + + .dropdown button { + background-color: #f2f2e8 !important; + color: #5e6268 !important; + } + + .dropdown-menu { + background-color: #5e6268 !important; + border: 2px solid #5e6268; + } + + .dropdown-item { + color: #f2f2e8 !important; + svg { + color: #f2f2e8 !important; + } + } + .dropdown-item:hover { + color: #5e6268 !important; + background-color: #f2f2e8 !important; + } + + .modal-content { + background-color: #5e6268 !important; + border-radius: 10px; + } + + .modal-body { + background-color: #5e6268 !important; + border-radius: 0px 0px 10px 10px; + } + + .modal-header { + background-color: #5e6268 !important; + border-radius: 10px 10px 0px 0px; + border-bottom: none; + } + + .danger { + background-color: #c94414 !important; + } + + .page-link { + color: #f2f3f4 !important; + border: 2px solid #f2f3f4 !important; + background-color: transparent !important; + } + + .active > .page-link { + background-color: #f2f3f4 !important; + color: #5e6268 !important; + } + + .pagination { + margin-top: 10px !important; + } + } } code { diff --git a/frontend/src/pages/Library/components/Actions.tsx b/frontend/src/pages/Library/components/Actions.tsx index 2bc5dd4..59077ad 100644 --- a/frontend/src/pages/Library/components/Actions.tsx +++ b/frontend/src/pages/Library/components/Actions.tsx @@ -2,7 +2,8 @@ import { Badge, Dropdown } from "react-bootstrap"; import { Book } from "../../../types/Book"; import { ImBin, ImBook, ImBoxAdd, ImBoxRemove, ImMenu } from "react-icons/im"; import { useMutation } from "@tanstack/react-query"; -import { secondary } from "../../../colors"; +import * as colors from "../../../colors"; +import * as dark from "../../../darkmodeColors"; import { ModalContextType } from "../../../App"; import { modalTypes } from "../../../shared/components/modals/types"; import { useCallback } from "react"; @@ -44,11 +45,7 @@ export const Actions = ({ return ( <> <Dropdown> - <Dropdown.Toggle - variant='success' - id='dropdown-basic' - style={{ backgroundColor: secondary, border: "2px solid black" }} - > + <Dropdown.Toggle variant='success' id='dropdown-basic'> <ImMenu size={25} color='black' /> </Dropdown.Toggle> @@ -59,14 +56,7 @@ export const Actions = ({ className='d-flex' onClick={() => setActiveModal({ type: bookModal, book, onClose })} > - <Badge - pill - className='ml-2 d-flex mr-2' - style={{ - border: "2px solid black", - backgroundColor: "transparent", - }} - > + <Badge pill className='ml-2 d-flex mr-2'> <ImBook size={25} color='black' className='m-auto' /> </Badge> <p className='m-auto' style={{ paddingLeft: "10px" }}> @@ -87,13 +77,7 @@ export const Actions = ({ }) } > - <Badge - pill - className='ml-2 d-flex mr-2' - style={{ - border: "2px solid black", - }} - > + <Badge pill className='ml-2 d-flex mr-2'> <ImBoxRemove size={25} color='black' className='m-auto' /> </Badge>{" "} <p className='m-auto' style={{ paddingLeft: "10px" }}> @@ -130,13 +114,7 @@ export const Actions = ({ setActiveModal({ type: del, uuid: book.uuid, onClose }) } > - <Badge - pill - className='ml-2 d-flex danger mr-2' - style={{ - border: "2px solid black", - }} - > + <Badge pill className='ml-2 d-flex danger mr-2'> <ImBin size={25} color='black' className='m-auto' /> </Badge>{" "} <p className='m-auto' style={{ paddingLeft: "10px" }}> diff --git a/frontend/src/pages/Main/Main.tsx b/frontend/src/pages/Main/Main.tsx index 090b13d..a1c7197 100644 --- a/frontend/src/pages/Main/Main.tsx +++ b/frontend/src/pages/Main/Main.tsx @@ -13,7 +13,6 @@ import { TfiKey } from "react-icons/tfi"; import { Link, useNavigate } from "react-router-dom"; import { Book } from "../../types/Book"; -import { secondary } from "../../colors"; import { useAuth } from "../../shared/utils/useAuthentication"; import { ModalContext } from "../../App"; import { modalTypes } from "../../shared/components/modals/types"; @@ -95,16 +94,12 @@ export const Main = (): React.JSX.Element => { onChange={(ev) => setTitle(ev.target.value)} style={{ borderRadius: "20px 0px 0px 20px", - border: "2px solid black", borderRight: "none", }} /> <Button style={{ borderRadius: "0px 5px 5px 0px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", }} className='mr-2' disabled={activeModal?.type === scanner || isFetching} @@ -135,9 +130,6 @@ export const Main = (): React.JSX.Element => { <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} @@ -151,9 +143,6 @@ export const Main = (): React.JSX.Element => { <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} @@ -174,9 +163,6 @@ export const Main = (): React.JSX.Element => { <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", }} > <ImBooks /> Browse library{" "} @@ -186,9 +172,6 @@ export const Main = (): React.JSX.Element => { <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginRight: "auto", marginLeft: "10px", }} diff --git a/frontend/src/shared/components/modals/AuthenticationModal.tsx b/frontend/src/shared/components/modals/AuthenticationModal.tsx index c5c0aa3..af3616c 100644 --- a/frontend/src/shared/components/modals/AuthenticationModal.tsx +++ b/frontend/src/shared/components/modals/AuthenticationModal.tsx @@ -2,7 +2,6 @@ import { useCallback, useContext } from "react"; import { Button, Col, Form, Modal, Row } from "react-bootstrap"; import { useForm, useWatch } from "react-hook-form"; import { TfiKey } from "react-icons/tfi"; -import { primaryRGBA, primary, secondary } from "../../../colors"; import { ModalHeader } from "./ModalHeader"; import { AuthContext } from "../../../App"; import { AuthModalProps } from "./types"; @@ -71,12 +70,7 @@ export const AuthenticationModal = ({ ); return ( - <Modal - show={open} - onHide={onClose} - style={{ backgroundColor: primaryRGBA }} - centered - > + <Modal show={open} onHide={onClose} centered> <ModalHeader onClose={onClose} title={isUpdate ? "Set new Admin key" : "Admin Login"} @@ -84,9 +78,7 @@ export const AuthenticationModal = ({ /> <Modal.Body style={{ - border: "2px solid black", borderTop: "none", - backgroundColor: primary, }} > <Form @@ -141,9 +133,6 @@ export const AuthenticationModal = ({ {!isUpdate && ( <Form.Group as={Row} className='mb-2'> - <Col sm='4'> - <Form.Label>Password</Form.Label> - </Col> <Col> <Form.Control {...register("password", { @@ -166,9 +155,6 @@ export const AuthenticationModal = ({ <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} diff --git a/frontend/src/shared/components/modals/BookModal.tsx b/frontend/src/shared/components/modals/BookModal.tsx index 5c086b6..3a097ca 100644 --- a/frontend/src/shared/components/modals/BookModal.tsx +++ b/frontend/src/shared/components/modals/BookModal.tsx @@ -5,7 +5,6 @@ import { ModalHeader } from "./ModalHeader"; import { useForm, useWatch } from "react-hook-form"; import { Book, bookShelfs } from "../../../types/Book"; import { useScanner } from "../../utils/useScanner"; -import { primary, primaryRGBA, secondary } from "../../../colors"; import { BookModalProps } from "./types"; type BookForm = Pick<Book, "isbn" | "title" | "shelf" | "published">; @@ -94,12 +93,7 @@ export const BookModal = ({ ); return ( - <Modal - show={open} - onHide={onClose} - style={{ backgroundColor: primaryRGBA }} - centered - > + <Modal show={open} onHide={onClose} centered> <ModalHeader onClose={onClose} title={`${!!book ? "Edit" : "Add new"} Book`} @@ -107,9 +101,7 @@ export const BookModal = ({ /> <Modal.Body style={{ - border: "2px solid black", borderTop: "none", - backgroundColor: primary, }} > {!showScanner && ( @@ -136,9 +128,6 @@ export const BookModal = ({ <Button style={{ borderRadius: "0px 5px 5px 0px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", }} className='mr-2 pt-0' disabled={showScanner} @@ -237,9 +226,6 @@ export const BookModal = ({ <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} @@ -260,7 +246,6 @@ export const BookModal = ({ className='drawingBuffer w-100 position-absolute' style={{ height: "100%", - border: "2px solid black", }} /> </div> diff --git a/frontend/src/shared/components/modals/CheckoutModal.tsx b/frontend/src/shared/components/modals/CheckoutModal.tsx index d3eb42c..41f4077 100644 --- a/frontend/src/shared/components/modals/CheckoutModal.tsx +++ b/frontend/src/shared/components/modals/CheckoutModal.tsx @@ -3,7 +3,7 @@ import { Alert, Button, Col, Form, Modal, Row } from "react-bootstrap"; import { ImBoxAdd, ImBoxRemove } from "react-icons/im"; import { useForm, useWatch } from "react-hook-form"; import { Book } from "../../../types/Book"; -import { primary, primaryRGBA, secondary } from "../../../colors"; +import { primary, secondary } from "../../../colors"; import { ModalHeader } from "./ModalHeader"; import { CheckoutBookModalProps } from "./types"; import { AiOutlineExclamationCircle } from "react-icons/ai"; @@ -68,12 +68,7 @@ export const CheckoutBookModal = ({ ); return ( - <Modal - show={open} - onHide={onClose} - style={{ backgroundColor: primaryRGBA }} - centered - > + <Modal show={open} onHide={onClose} centered> <ModalHeader onClose={onClose} title={`${isChechout ? "Checkout" : "Return"} book '${title}'`} @@ -87,9 +82,7 @@ export const CheckoutBookModal = ({ /> <Modal.Body style={{ - border: "2px solid black", borderTop: "none", - backgroundColor: primary, }} > <Alert className='w-80 m-auto my-4' variant='warning'> @@ -187,9 +180,6 @@ export const CheckoutBookModal = ({ <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} diff --git a/frontend/src/shared/components/modals/DeleteBookModal.tsx b/frontend/src/shared/components/modals/DeleteBookModal.tsx index e352705..eada158 100644 --- a/frontend/src/shared/components/modals/DeleteBookModal.tsx +++ b/frontend/src/shared/components/modals/DeleteBookModal.tsx @@ -1,5 +1,5 @@ import { Button, Modal } from "react-bootstrap"; -import { primary, primaryRGBA, secondary } from "../../../colors"; +import { primary, secondary } from "../../../colors"; import { ModalHeader } from "./ModalHeader"; import { ImBin } from "react-icons/im"; import { useMutation } from "@tanstack/react-query"; @@ -24,12 +24,7 @@ export const DeleteBookModal = ({ }); return ( - <Modal - show={open} - onHide={onClose} - style={{ backgroundColor: primaryRGBA }} - centered - > + <Modal show={open} onHide={onClose} centered> <ModalHeader onClose={onClose} title={"Move to Shelf"} @@ -37,18 +32,13 @@ export const DeleteBookModal = ({ /> <Modal.Body style={{ - border: "2px solid black", borderTop: "none", - backgroundColor: primary, }} > <div className='d-flex mx-auto mb-auto mt-2 w-100'> <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} @@ -59,9 +49,6 @@ export const DeleteBookModal = ({ <Button style={{ borderRadius: "5px", - backgroundColor: secondary, - color: "black", - border: "2px solid black", marginLeft: "auto", marginRight: "10px", }} diff --git a/frontend/src/shared/components/modals/ModalHeader.tsx b/frontend/src/shared/components/modals/ModalHeader.tsx index 9b681d4..115ab79 100644 --- a/frontend/src/shared/components/modals/ModalHeader.tsx +++ b/frontend/src/shared/components/modals/ModalHeader.tsx @@ -13,13 +13,7 @@ export const ModalHeader = ({ icon?: JSX.Element; }): React.JSX.Element => { return ( - <Modal.Header - style={{ - border: "2px solid black", - borderBottom: "none", - backgroundColor: primary, - }} - > + <Modal.Header> <Modal.Title className='w-100 d-flex' style={{ height: "fit-content" }}> {typeof title === "string" ? ( <> @@ -34,9 +28,6 @@ export const ModalHeader = ({ <Button className='ml-auto mr-0' style={{ - backgroundColor: secondary, - color: "black", - border: "2px solid black", width: "fit-content", height: "fit-content", }} diff --git a/frontend/src/shared/components/modals/ScannerModal.tsx b/frontend/src/shared/components/modals/ScannerModal.tsx index a5bdd25..488ee0b 100644 --- a/frontend/src/shared/components/modals/ScannerModal.tsx +++ b/frontend/src/shared/components/modals/ScannerModal.tsx @@ -1,7 +1,6 @@ -import React from "react"; +import React, { useContext } from "react"; import { Modal } from "react-bootstrap"; import { ImCamera } from "react-icons/im"; -import { primaryRGBA } from "../../../colors"; import { useScanner } from "../../utils/useScanner"; import { ModalHeader } from "./ModalHeader"; @@ -17,18 +16,13 @@ export const ScannerModal = ({ const { scannerError, setScannerRef } = useScanner({ onDetected }); return ( - <Modal - show={open} - onHide={onClose} - style={{ backgroundColor: primaryRGBA }} - centered - > + <Modal show={open} onHide={onClose} centered> <ModalHeader onClose={onClose} title={"Scan barcode"} icon={<ImCamera size={50} className='ml-0 mr-auto' />} /> - <Modal.Body style={{ border: "2px solid black", borderTop: "none" }}> + <Modal.Body> <div className='w-100 overflow-hidden' ref={(ref) => setScannerRef(ref)} @@ -41,7 +35,7 @@ export const ScannerModal = ({ className='drawingBuffer w-100 position-absolute' style={{ height: "100%", - border: "2px solid black", + border: `2px solid black`, }} /> </div>