diff --git a/.gitignore b/.gitignore
index 79c167c..214310f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ venv/
__pycache__
node_modules/
coverage/
+.bat
diff --git a/dnd-app/backend/buildSearch.js b/dnd-app/backend/buildSearch.js
index ec277e1..e1fbd7d 100644
--- a/dnd-app/backend/buildSearch.js
+++ b/dnd-app/backend/buildSearch.js
@@ -99,7 +99,6 @@ async function buildSlugDb() {
"armor",
"sections",
"spells",
- "spelllist",
];
await Promise.all(calls.map((prefix) => fetchAndInsertData(prefix, url)));
diff --git a/dnd-app/frontend/index.html b/dnd-app/frontend/index.html
index b73747c..4af26d0 100644
--- a/dnd-app/frontend/index.html
+++ b/dnd-app/frontend/index.html
@@ -4,7 +4,7 @@
-
Dnd Companion
+ Arcane Atlas
diff --git a/dnd-app/frontend/public/icons/armor.png b/dnd-app/frontend/public/icons/armor.png
deleted file mode 100644
index 3aaca63..0000000
Binary files a/dnd-app/frontend/public/icons/armor.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/backgrounds.png b/dnd-app/frontend/public/icons/backgrounds.png
deleted file mode 100644
index fc3b72c..0000000
Binary files a/dnd-app/frontend/public/icons/backgrounds.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/classes.png b/dnd-app/frontend/public/icons/classes.png
deleted file mode 100644
index 3c6c60b..0000000
Binary files a/dnd-app/frontend/public/icons/classes.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/conditions.png b/dnd-app/frontend/public/icons/conditions.png
deleted file mode 100644
index 372f998..0000000
Binary files a/dnd-app/frontend/public/icons/conditions.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/feats.png b/dnd-app/frontend/public/icons/feats.png
deleted file mode 100644
index 8acfa4e..0000000
Binary files a/dnd-app/frontend/public/icons/feats.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/magicitems.png b/dnd-app/frontend/public/icons/magicitems.png
deleted file mode 100644
index 2dab7cd..0000000
Binary files a/dnd-app/frontend/public/icons/magicitems.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/monsters.png b/dnd-app/frontend/public/icons/monsters.png
deleted file mode 100644
index 2e0acc8..0000000
Binary files a/dnd-app/frontend/public/icons/monsters.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/planes.png b/dnd-app/frontend/public/icons/planes.png
deleted file mode 100644
index 6351634..0000000
Binary files a/dnd-app/frontend/public/icons/planes.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/races.png b/dnd-app/frontend/public/icons/races.png
deleted file mode 100644
index 819c79f..0000000
Binary files a/dnd-app/frontend/public/icons/races.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/sections.png b/dnd-app/frontend/public/icons/sections.png
deleted file mode 100644
index 5c8a073..0000000
Binary files a/dnd-app/frontend/public/icons/sections.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/spelllist.png b/dnd-app/frontend/public/icons/spelllist.png
deleted file mode 100644
index e837c99..0000000
Binary files a/dnd-app/frontend/public/icons/spelllist.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/spells.png b/dnd-app/frontend/public/icons/spells.png
deleted file mode 100644
index 8f62725..0000000
Binary files a/dnd-app/frontend/public/icons/spells.png and /dev/null differ
diff --git a/dnd-app/frontend/public/icons/weapons.png b/dnd-app/frontend/public/icons/weapons.png
deleted file mode 100644
index 3360b86..0000000
Binary files a/dnd-app/frontend/public/icons/weapons.png and /dev/null differ
diff --git a/dnd-app/frontend/public/logo.png b/dnd-app/frontend/public/logo.png
index cb3bf70..e1b2250 100644
Binary files a/dnd-app/frontend/public/logo.png and b/dnd-app/frontend/public/logo.png differ
diff --git a/dnd-app/frontend/src/DetailRoutes/Armor.jsx b/dnd-app/frontend/src/DetailRoutes/Armor.jsx
index 6ffe3dd..4eb86d8 100644
--- a/dnd-app/frontend/src/DetailRoutes/Armor.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Armor.jsx
@@ -1,19 +1,9 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- Row,
- Spinner,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardText, CardTitle, Col, Container, Row } from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -44,87 +34,72 @@ export function Armor() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
- {data.name}
- {data.category ? (
- <>
- {data.category}
-
- {data.ac_string}
-
- >
+
+
+
+ {data.name}
+ {data.category ? (
+ <>
+ {data.category}
+ {data.ac_string}
+ >
+ ) : (
+ ""
+ )}
+
+ {data.cost ? (
+
+ Price:
+ {data.cost}
+
) : (
""
)}
-
- {data.cost ? (
-
- Price:
- {data.cost}
-
- ) : (
- ""
- )}
+
+ Strength Requirement:
+ {data.strength_requirement || "None"}
+
+
+ Stealth Disadvantage:
+ {data.stealth_disadvantage ? "Yes" : "No"}
+
+ {data.base_ac ? (
- Strength Requirement:
- {data.strength_requirement || "None"}
+ Armor Class:
+ {data.base_ac}
+ ) : (
+ ""
+ )}
+ {data.plus_max ? (
- Stealth Disadvantage:
- {data.stealth_disadvantage
- ? "Yes"
- : "No"}
+ Max Dex:
+ {"+"}
+ {data.plus_max}
- {data.base_ac ? (
-
- Armor Class:
- {data.base_ac}
-
- ) : (
- ""
- )}
- {data.plus_max ? (
-
- Max Dex:
- {"+"}
- {data.plus_max}
-
- ) : (
- ""
- )}
- {data.weight ? (
-
- Weight:
- {data.weight}
-
- ) : (
- ""
- )}
-
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+ ) : (
+ ""
+ )}
+ {data.weight ? (
+
+ Weight:
+ {data.weight}
+
+ ) : (
+ ""
+ )}
+
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/Backgrounds.jsx b/dnd-app/frontend/src/DetailRoutes/Backgrounds.jsx
index 92c7b0c..7f462f0 100644
--- a/dnd-app/frontend/src/DetailRoutes/Backgrounds.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Backgrounds.jsx
@@ -1,18 +1,8 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- Row,
- Spinner,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardText, CardTitle, Col, Container, Row } from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -46,67 +36,49 @@ export function Backgrounds() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
- {data.name}
- {data.type}
- {data.desc}
-
-
- Equipment: {" "}
- {data.equipment || "None"}
-
-
-
-
-
- Skill Proficiencies:
- {" "}
- {data.skill_proficiencies || "None"}
-
-
-
-
- Tool Proficiencies: {" "}
- {data.tool_proficiencies || "None"}
-
-
-
-
- Languages: {" "}
- {data.languages || "None"}
-
-
-
-
+
+
+
+ {data.name}
+ {data.type}
+ {data.desc}
+
+
+ Equipment: {data.equipment || "None"}
+
+
+
+
+ Skill Proficiencies: {data.skill_proficiencies || "None"}
+
+
+
+
+ Tool Proficiencies: {data.tool_proficiencies || "None"}
+
+
+
+
+ Languages: {data.languages || "None"}
+
+
+
+
-
- {data.feature}: {" "}
- {data.feature_desc}
-
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+
+ {data.feature}: {data.feature_desc}
+
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/BasicCard.jsx b/dnd-app/frontend/src/DetailRoutes/BasicCard.jsx
index 73481a9..3ea221b 100644
--- a/dnd-app/frontend/src/DetailRoutes/BasicCard.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/BasicCard.jsx
@@ -1,19 +1,9 @@
import { useEffect, useState } from "react";
+import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- Row,
- Spinner,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardText, CardTitle, Container } from "reactstrap";
import DndApi from "../api";
-import ReactMarkdown from "react-markdown";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -45,34 +35,23 @@ export function BasicCard({ type }) {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
- {data.name}
- {data.type}
- {data.desc}
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+
+
+
+ {data.name}
+ {data.type}
+ {data.desc}
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/Classes.jsx b/dnd-app/frontend/src/DetailRoutes/Classes.jsx
index 3b98e15..ab22abd 100644
--- a/dnd-app/frontend/src/DetailRoutes/Classes.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Classes.jsx
@@ -2,24 +2,10 @@
import { useEffect, useState } from "react";
import Markdown from "react-markdown";
import { useParams } from "react-router-dom";
-import {
- Accordion,
- AccordionBody,
- AccordionHeader,
- AccordionItem,
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- Row,
- Spinner,
-} from "reactstrap";
-import DndApi from "../api";
+import { Accordion, AccordionBody, AccordionHeader, AccordionItem, Badge, Card, CardBody, CardText, CardTitle, Container } from "reactstrap";
import remarkGfm from "remark-gfm";
+import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -56,56 +42,45 @@ export function Classes() {
}
};
- console.log(data);
-
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
- {data.name}
-
- {data.table || ""}
-
- {data.desc || ""}
-
-
- {data.archetypes
- ? data.archetypes.map((sub) => {
- return (
-
-
- {sub.name}
-
-
- {sub.desc}
-
-
- );
- })
- : ""}
-
-
- Source: {" "}
-
- {data.document__title}
-
-
-
-
-
-
+
+
+
+ {data.name}
+
+ {data.table || ""}
+
+ {data.desc || ""}
+
+
+ {data.archetypes
+ ? data.archetypes.map((sub) => {
+ return (
+
+
+ {sub.name}
+
+
+ {sub.desc}
+
+
+ );
+ })
+ : ""}
+
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/DetailRoutes.jsx b/dnd-app/frontend/src/DetailRoutes/DetailRoutes.jsx
index e46b59b..da811b3 100644
--- a/dnd-app/frontend/src/DetailRoutes/DetailRoutes.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/DetailRoutes.jsx
@@ -9,6 +9,7 @@ import { BasicCard } from "./BasicCard";
import { MagicItems } from "./MagicItems";
import { Races } from "./Races";
import { Classes } from "./Classes";
+import { Weapons } from "./Weapons";
/**
* Component that defines the detail routes for different sections of the application.
@@ -25,17 +26,12 @@ export function DetailRoutes() {
} />
} />
} />
+ } />
} />
} />
} />
- }
- />
- }
- />
+ } />
+ } />
>
);
}
diff --git a/dnd-app/frontend/src/DetailRoutes/Feats.jsx b/dnd-app/frontend/src/DetailRoutes/Feats.jsx
index e3cd9c6..99b7246 100644
--- a/dnd-app/frontend/src/DetailRoutes/Feats.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Feats.jsx
@@ -1,21 +1,8 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardSubtitle,
- CardText,
- CardTitle,
- Col,
- Container,
- ListGroup,
- ListGroupItem,
- Row,
- Spinner,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardSubtitle, CardText, CardTitle, Container, ListGroup, ListGroupItem } from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -47,48 +34,31 @@ export function Feats() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
- {data.name}
-
- {data.prerequisite}
-
-
- {data.desc}
-
- {data.effects_desc.map((effect, index) => (
-
- {effect}
-
- ))}
-
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+
+
+
+ {data.name}
+
+ {data.prerequisite}
+
+
+ {data.desc}
+
+ {data.effects_desc.map((effect, index) => (
+ {effect}
+ ))}
+
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/MagicItems.jsx b/dnd-app/frontend/src/DetailRoutes/MagicItems.jsx
index c882586..718845b 100644
--- a/dnd-app/frontend/src/DetailRoutes/MagicItems.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/MagicItems.jsx
@@ -1,22 +1,8 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- PopoverBody,
- PopoverHeader,
- Row,
- Spinner,
- Table,
- UncontrolledPopover,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardText, CardTitle, Container, PopoverBody, PopoverHeader, Table, UncontrolledPopover } from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
import("../assets/styles/MagicItems.css");
@@ -61,99 +47,71 @@ export function MagicItems() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
-
- {data.name}
- {" "}
-
- {data.rarity}
-
-
-
- Item Rarity
-
-
-
-
-
- Rarity
- Level
- Value (GP)
-
-
-
-
- Common
- 1+
- 50-100
-
-
- Uncommon
- 1+
- 101-500
-
-
- Rare
- 5+
- 501-5,000
-
-
- Very Rare
- 11+
- 5,001-50,000
-
-
- Legendary
- 17+
- 50,001+
-
-
-
-
-
-
- {data.type}
-
- {data.desc}
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+
+
+
+
+ {data.name}
+ {" "}
+
+ {data.rarity}
+
+
+ Item Rarity
+
+
+
+
+ Rarity
+ Level
+ Value (GP)
+
+
+
+
+ Common
+ 1+
+ 50-100
+
+
+ Uncommon
+ 1+
+ 101-500
+
+
+ Rare
+ 5+
+ 501-5,000
+
+
+ Very Rare
+ 11+
+ 5,001-50,000
+
+
+ Legendary
+ 17+
+ 50,001+
+
+
+
+
+
+
+ {data.type}
+
+ {data.desc}
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/Monster.jsx b/dnd-app/frontend/src/DetailRoutes/Monster.jsx
index 4d4728f..ada4674 100644
--- a/dnd-app/frontend/src/DetailRoutes/Monster.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Monster.jsx
@@ -1,24 +1,11 @@
/* eslint-disable no-mixed-spaces-and-tabs */
import { useEffect, useState } from "react";
+import ReactMarkdown from "react-markdown";
import { useParams } from "react-router-dom";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardSubtitle,
- CardText,
- CardTitle,
- Col,
- Container,
- ListGroup,
- ListGroupItem,
- Row,
- Spinner,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardText, CardTitle, Col, Container, ListGroup, ListGroupItem, Row } from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import { getScore } from "../tools";
-import ReactMarkdown from "react-markdown";
import("../assets/styles/Details.css");
@@ -49,267 +36,258 @@ export function Monster() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
-
-
- {data.name}
- {!data.desc && !data.legendary_desc ? "" : {data.desc || data.legendary_desc} }
-
-
-
- Type: {data.type} {data.subtype ? `(${data.subtype})` : ""}
-
-
- Size: {data.size}
-
-
- Alignment: {data.alignment}
-
-
- Armor Class: {data.armor_class}
-
-
- Hit Points: {data.hit_points}
-
-
- Hit Dice: {data.hit_dice}
+
+
+
+
+ {data.name}
+ {!data.desc && !data.legendary_desc ? "" : {data.desc || data.legendary_desc} }
+
+
+
+ Type: {data.type} {data.subtype ? `(${data.subtype})` : ""}
+
+
+ Size: {data.size}
+
+
+ Alignment: {data.alignment}
+
+
+ Armor Class: {data.armor_class}
+
+
+ Hit Points: {data.hit_points}
+
+
+ Hit Dice: {data.hit_dice}
+
+
+ Speed: {" "}
+ {Object.keys(data.speed).map((speed, index) => (
+
+ {speed} {data.speed[speed]} ft.
+
+ ))}
+
+
+ Senses: {data.senses}
+
+
+
+ Actions
+ {data.actions.map((action, index) => (
+
+
+ {action.name}: {action.desc}
-
- Speed: {" "}
- {Object.keys(data.speed).map((speed, index) => (
-
- {speed} {data.speed[speed]} ft.
+
+ ))}
+
+ Special Abilities
+ {!data.special_abilities.length > 0
+ ? "None"
+ : data.special_abilities.map((ability, index) => (
+
+
+ {ability.name}: {ability.desc}
+
+ ))}
+ {!data.legendary_actions.length > 0 ? (
+ <>>
+ ) : (
+ <>
+
+ Legendary Actions
+
+ {data.legendary_actions.map((action, index) => (
+
+ {action.name}
+ {": "}
+ {action.desc}
+
))}
-
- Senses: {data.senses}
-
-
-
- Actions
- {data.actions.map((action, index) => (
-
-
- {action.name}: {action.desc}
-
-
- ))}
-
- Special Abilities
- {!data.special_abilities
- ? "None"
- : data.special_abilities.map((ability, index) => (
-
-
- {ability.name}: {ability.desc}
-
-
- ))}
- {!data.legendary_actions ? (
+ >
+ )}
+
+
+
+
+ Languages: {data.languages}
+
+
+ Challenge Rating: {data.challenge_rating}
+
+
+
+
+
+ Immunities/Resistances
+
+
+ Damage Vulnerabilities: {data.damage_vulnerabilities || "None"}
+
+
+ Damage Resistances: {data.damage_resistances || "None"}
+
+
+ Damage Immunities: {data.damage_immunities || "None"}
+
+
+ Condition Immunities: {data.condition_immunities || "None"}
+
+
+
+
+ Other Actions
+
+
+ Bonus Actions: {" "}
+ {!data.bonus_actions
+ ? "None"
+ : data.bonus_actions.map((action, index) => (
+
+ {action.name}
+ {": "}
+ {action.desc}
+
+ ))}
+
+
+ Reactions: {" "}
+ {data.reactions
+ ? Object.keys(data.reactions).map((action, index) => (
+
+ {data.reactions[action].name}: {data.reactions[action].desc}
+
+ ))
+ : "None"}
+
+
+
+
+
+
+
+ Abilities
+
+
+ Strength: {data.strength} ({getScore(data.strength)})
+
+
+ Dexterity: {data.dexterity} ({getScore(data.dexterity)})
+
+
+ Constitution: {data.constitution} ({getScore(data.constitution)})
+
+
+ Intelligence: {data.intelligence} ({getScore(data.intelligence)})
+
+
+ Wisdom: {data.wisdom} ({getScore(data.wisdom)})
+
+
+ Charisma: {data.charisma} ({getScore(data.charisma)})
+
+
+
+
+ Saves
+
+
+ Strength Save: {data.strength_save || getScore(data.strength)}
+
+
+ Dexterity Save: {data.dexterity_save || getScore(data.dexterity)}
+
+
+ Constitution Save: {data.constitution_save || getScore(data.constitution)}
+
+
+ Intelligence Save: {data.intelligence_save || getScore(data.intelligence)}
+
+
+ Wisdom Save: {data.wisdom_save || getScore(data.wisdom)}
+
+
+ Charisma Save: {data.charisma_save || getScore(data.charisma)}
+
+
+ Perception: {data.perception || "0"}
+
+
+
+
+
+
+ {!data.skill ? (
<>>
) : (
<>
-
- Legendary Actions
-
- {data.legendary_actions.map((action, index) => (
-
- {action.name}
- {": "}
- {action.desc}
-
- ))}
-
- >
- )}
-
-
-
-
- Languages: {data.languages}
-
-
- Challenge Rating: {data.challenge_rating}
-
-
-
-
-
- Immunities/Resistances
-
-
- Damage Vulnerabilities: {data.damage_vulnerabilities || "None"}
-
-
- Damage Resistances: {data.damage_resistances || "None"}
-
-
- Damage Immunities: {data.damage_immunities || "None"}
-
-
- Condition Immunities: {data.condition_immunities || "None"}
-
-
-
-
- Other Actions
-
-
- Bonus Actions: {" "}
- {!data.bonus_actions
- ? "None"
- : data.bonus_actions.map((action, index) => (
-
- {action.name}
+
+ Skills: {" "}
+
+ {Object.keys(data.skills).map(
+ (skill, index) =>
+ (
+
+ {skill}
{": "}
- {action.desc}
-
- ))}
-
-
- Reactions: {" "}
- {data.reactions
- ? Object.keys(data.reactions).map((action, index) => (
-
- {action} {data.reactions[action]} ft.
-
- ))
- : "None"}
-
-
-
-
-
-
-
- Abilities
-
-
- Strength: {data.strength} ({getScore(data.strength)})
-
-
- Dexterity: {data.dexterity} ({getScore(data.dexterity)})
-
-
- Constitution: {data.constitution} ({getScore(data.constitution)})
-
-
- Intelligence: {data.intelligence} ({getScore(data.intelligence)})
-
-
- Wisdom: {data.wisdom} ({getScore(data.wisdom)})
-
-
- Charisma: {data.charisma} ({getScore(data.charisma)})
-
-
-
-
- Saves
-
-
- Strength Save: {data.strength_save || getScore(data.strength)}
-
-
- Dexterity Save: {data.dexterity_save || getScore(data.dexterity)}
-
-
- Constitution Save: {data.constitution_save || getScore(data.constitution)}
-
-
- Intelligence Save: {data.intelligence_save || getScore(data.intelligence)}
-
-
- Wisdom Save: {data.wisdom_save || getScore(data.wisdom)}
-
-
- Charisma Save: {data.charisma_save || getScore(data.charisma)}
-
-
- Perception: {data.perception || "0"}
-
-
-
-
-
-
- {!data.skill ? (
- <>>
- ) : (
- <>
-
- Skills: {" "}
-
- {Object.keys(data.skills).map(
- (skill, index) =>
- (
-
- {skill}
- {": "}
- {data.skills[skill]}
-
- ) || "None"
- )}
-
- {!data.armor_desc ? (
- <>>
- ) : (
-
- Armor Description: {data.armor_desc}
-
- )}
- {!data.group ? (
- <>>
- ) : (
- <>
-
- Group: {data.group}
-
- >
+ {data.skills[skill]}
+
+ ) || "None"
)}
-
- >
- )}
-
-
- {!data.environment ? (
- <>>
- ) : (
- <>
-
- Environments
-
- {data.environments.map((environment, index) => (
-
- {environment}
-
- ))}
-
+
+ {!data.armor_desc ? (
+ <>>
+ ) : (
+
+ Armor Description: {data.armor_desc}
+
+ )}
+ {!data.group ? (
+ <>>
+ ) : (
+ <>
+
+ Group: {data.group}
+
+ >
+ )}
+
>
)}
-
- Source: {" "}
-
- {data.document__title}
-
-
-
-
-
-
-
+
+
+ {!data.environment ? (
+ <>>
+ ) : (
+ <>
+
+ Environments
+
+ {data.environments.map((environment, index) => (
+
+ {environment}
+
+ ))}
+
+ >
+ )}
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/Races.jsx b/dnd-app/frontend/src/DetailRoutes/Races.jsx
index 9d6c922..9c40979 100644
--- a/dnd-app/frontend/src/DetailRoutes/Races.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Races.jsx
@@ -10,15 +10,14 @@ import {
Badge,
Card,
CardBody,
- CardImg,
CardText,
CardTitle,
Col,
Container,
Row,
- Spinner,
} from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -58,51 +57,39 @@ export function Races() {
return (
{loading ? (
-
-
-
-
-
-
-
+
) : (
-
-
-
-
- Ability Score
-
+
+
+
+ {data.name}
+
+ Ability Scores:
{data.asi.map((item, index) => (
-
-
-
- {item.attributes}
- {item.value}
-
-
-
+
+
+ {item.attributes} +{item.value}
+
+
))}
-
-
- Size
- {data.size_raw}
-
- Speed
-
- {Object.keys(data.speed).map((speed, index) => (
-
- {speed} {data.speed[speed]} ft.
-
- ))}
-
-
-
-
-
-
- {data.name}
+
+
+
+ Size:
+ {data.size_raw}
+
+
+ Speed:
+ {Object.keys(data.speed).map((speed, index) => (
+
+ {speed} {data.speed[speed]} ft.
+
+ ))}
+
+
+
{data.desc || ""}
{data.asi_desc ? {data.asi_desc} : ""}
{data.age ? {data.age} : ""}
@@ -112,30 +99,32 @@ export function Races() {
{data.languages || "Languages: None"}
{data.vision ? {data.vision} : ""}
{data.traits ? {data.traits} : ""}
-
- {data.subraces
- ? data.subraces.map((race) => {
- return (
-
-
- {race.name}
-
-
- {race.desc}
- {race.asi_desc ? {race.asi_desc} : ""}
- {race.age ? {race.age} : ""}
- {race.alignment ? {race.age} : ""}
- {race.size ? {race.age} : ""}
- {race.speed_desc ? {race.speed_desc} : ""}
- {race.languages ? {race.languages} : ""}
- {race.vision ? {race.vision} : ""}
- {race.traits ? {race.traits} : ""}
-
-
- );
- })
- : ""}
-
+ {!data.subraces ? (
+ <>>
+ ) : (
+
+ {data.subraces.map((race) => {
+ return (
+
+
+ {race.name}
+
+
+ {race.desc}
+ {race.asi_desc ? {race.asi_desc} : ""}
+ {race.age ? {race.age} : ""}
+ {race.alignment ? {race.age} : ""}
+ {race.size ? {race.age} : ""}
+ {race.speed_desc ? {race.speed_desc} : ""}
+ {race.languages ? {race.languages} : ""}
+ {race.vision ? {race.vision} : ""}
+ {race.traits ? {race.traits} : ""}
+
+
+ );
+ })}
+
+ )}
Source: {" "}
@@ -144,8 +133,7 @@ export function Races() {
-
-
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/SpellCard.jsx b/dnd-app/frontend/src/DetailRoutes/SpellCard.jsx
index 8ef9fd0..d46383a 100644
--- a/dnd-app/frontend/src/DetailRoutes/SpellCard.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/SpellCard.jsx
@@ -4,7 +4,6 @@ import {
Badge,
Card,
CardBody,
- CardImg,
CardSubtitle,
CardText,
CardTitle,
@@ -15,10 +14,10 @@ import {
PopoverBody,
PopoverHeader,
Row,
- Spinner,
UncontrolledPopover,
} from "reactstrap";
import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
import("../assets/styles/SpellCard.css");
@@ -50,372 +49,188 @@ export function SpellCard() {
return (
{loading ? (
-
+
) : (
-
-
-
-
-
- {data.name}
-
-
- {data.school} {data.level}
-
- {data.requires_verbal_components ? (
- <>
-
- V
-
-
-
- Verbal
-
-
- Most spells require the
- chanting of mystic words.
- The words themselves aren’t
- the source of the spell’s
- power; rather, the
- particular combination of
- sounds, with specific pitch
- and resonance, sets the
- threads of magic in motion.
- Thus, a character who is
- gagged or in an area of
- silence, such as one created
- by the silence spell, can’t
- cast a spell with a verbal
- component.
-
-
- >
- ) : (
- <>>
- )}
- {data.requires_somatic_components ? (
- <>
-
- S
-
-
-
- Somatic
-
-
- Spellcasting gestures might
- include a forceful
- gesticulation or an
- intricate set of gestures.
- If a spell requires a
- somatic component, the
- caster must have free use of
- at least one hand to perform
- these gestures.
-
-
- >
- ) : (
- <>>
- )}
- {data.requires_material_components ? (
- <>
-
- M
-
-
-
- Material
-
-
- Casting some spells requires
- particular objects,
- specified in parentheses in
- the component entry. A
- character can use a
- component pouch or a
- spellcasting focus (found in
- “Equipment”) in place of the
- components specified for a
- spell. But if a cost is
- indicated for a component, a
- character must have that
- specific component before he
- or she can cast the spell.
- If a spell states that a
- material component is
- consumed by the spell, the
- caster must provide this
- component for each casting
- of the spell. A spellcaster
- must have a hand free to
- access a spell’s material
- components—or to hold a
- spellcasting focus—but it
- can be the same hand that he
- or she uses to perform
- somatic components.
-
-
- >
- ) : (
- <>>
- )}
- {data.can_be_cast_as_ritual ? (
- <>
-
- R
-
-
-
- Ritual
-
-
- Certain spells have a
- special tag: ritual. Such a
- spell can be cast following
- the normal rules for
- spellcasting, or the spell
- can be cast as a ritual. The
- ritual version of a spell
- takes 10 minutes longer to
- cast than normal. It also
- doesn’t expend a spell slot,
- which means the ritual
- version of a spell can’t be
- cast at a higher level. To
- cast a spell as a ritual, a
- spellcaster must have a
- feature that grants the
- ability to do so. The cleric
- and the druid, for example,
- have such a feature. The
- caster must also have the
- spell prepared or on his or
- her list of spells known,
- unless the character’s
- ritual feature specifies
- otherwise, as the wizard’s
- does.
-
-
- >
- ) : (
- <>>
- )}
- {data.requires_concentration ? (
- <>
-
- C
-
-
-
- Concentration
-
-
- Some spells require you to
- maintain concentration in
- order to keep their magic
- active. If you lose
- concentration, such a spell
- ends. If a spell must be
- maintained with
- concentration, that fact
- appears in its Duration
- entry, and the spell
- specifies how long you can
- concentrate on it. You can
- end concentration at any
- time (no action required).
- Normal activity, such as
- moving and attacking,
- doesn’t interfere with
- concentration. The following
- factors can break
- concentration:
-
-
-
- Casting another
- spell that
- requires
- concentration.
- {" "}
- You lose
- concentration on a
- spell if you cast
- another spell that
- requires
- concentration. You
- can’t concentrate on
- two spells at once.
-
-
-
- Taking damage.
- {" "}
- Whenever you take
- damage while you are
- concentrating on a
- spell, you must make
- a Constitution
- saving throw to
- maintain your
- concentration. The
- DC equals 10 or half
- the damage you take,
- whichever number is
- higher. If you take
- damage from multiple
- sources, such as an
- arrow and a dragon’s
- breath, you make a
- separate saving
- throw for each
- source of damage.
-
-
-
- Being
- incapacitated or
- killed.
- {" "}
- You lose
- concentration on a
- spell if you are
- incapacitated or if
- you die.{" "}
-
-
- The GM might also decide
- that certain environmental
- phenomena, such as a wave
- crashing over you while
- you’re on a storm--tossed
- ship, require you to succeed
- on a DC 10 Constitution
- saving throw to maintain
- concentration on a spell.
-
-
- >
- ) : (
- <>>
- )}
-
-
- {data.spell_lists.map((b) => {
- return (
-
- {b}
-
- );
- })}
-
- {data.desc}
-
-
- Range: {data.range}
-
-
- Duration: {" "}
- {data.duration}
-
-
- Casting Time: {" "}
- {data.casting_time}
-
-
- {data.higher_level !== "" ? (
+
+
+
+ {data.name}
+
+
+ {data.school} {data.level}
+
+ {data.requires_verbal_components ? (
<>
-
-
- Higher Level: {" "}
- {data.higher_level}
-
+
+ V
+
+
+ Verbal
+
+ Most spells require the chanting of mystic words. The words themselves aren’t the source of the
+ spell’s power; rather, the particular combination of sounds, with specific pitch and resonance, sets
+ the threads of magic in motion. Thus, a character who is gagged or in an area of silence, such as one
+ created by the silence spell, can’t cast a spell with a verbal component.
+
+
>
) : (
<>>
)}
-
-
- Additional Info
-
- Material Components: {" "}
- {(data.requires_material_components &&
- `${data.material}`) ||
- `None`}
-
-
- Classes: {" "}
- {data.dnd_class}
-
-
- Cast as ritual:
- {data.can_be_cast_as_ritual
- ? "True"
- : "False"}
-
-
-
- Source: {" "}
-
-
- {data.document__title}
-
-
-
-
-
-
-
+ {data.requires_somatic_components ? (
+ <>
+
+ S
+
+
+ Somatic
+
+ Spellcasting gestures might include a forceful gesticulation or an intricate set of gestures. If a
+ spell requires a somatic component, the caster must have free use of at least one hand to perform
+ these gestures.
+
+
+ >
+ ) : (
+ <>>
+ )}
+ {data.requires_material_components ? (
+ <>
+
+ M
+
+
+ Material
+
+ Casting some spells requires particular objects, specified in parentheses in the component entry. A
+ character can use a component pouch or a spellcasting focus (found in “Equipment”) in place of the
+ components specified for a spell. But if a cost is indicated for a component, a character must have
+ that specific component before he or she can cast the spell. If a spell states that a material
+ component is consumed by the spell, the caster must provide this component for each casting of the
+ spell. A spellcaster must have a hand free to access a spell’s material components—or to hold a
+ spellcasting focus—but it can be the same hand that he or she uses to perform somatic components.
+
+
+ >
+ ) : (
+ <>>
+ )}
+ {data.can_be_cast_as_ritual ? (
+ <>
+
+ R
+
+
+ Ritual
+
+ Certain spells have a special tag: ritual. Such a spell can be cast following the normal rules for
+ spellcasting, or the spell can be cast as a ritual. The ritual version of a spell takes 10 minutes
+ longer to cast than normal. It also doesn’t expend a spell slot, which means the ritual version of a
+ spell can’t be cast at a higher level. To cast a spell as a ritual, a spellcaster must have a feature
+ that grants the ability to do so. The cleric and the druid, for example, have such a feature. The
+ caster must also have the spell prepared or on his or her list of spells known, unless the character’s
+ ritual feature specifies otherwise, as the wizard’s does.
+
+
+ >
+ ) : (
+ <>>
+ )}
+ {data.requires_concentration ? (
+ <>
+
+ C
+
+
+ Concentration
+
+ Some spells require you to maintain concentration in order to keep their magic active. If you lose
+ concentration, such a spell ends. If a spell must be maintained with concentration, that fact appears
+ in its Duration entry, and the spell specifies how long you can concentrate on it. You can end
+ concentration at any time (no action required). Normal activity, such as moving and attacking, doesn’t
+ interfere with concentration. The following factors can break concentration:
+
+
+ Casting another spell that requires concentration. You lose concentration on
+ a spell if you cast another spell that requires concentration. You can’t concentrate on two
+ spells at once.
+
+
+ Taking damage. Whenever you take damage while you are concentrating on a
+ spell, you must make a Constitution saving throw to maintain your concentration. The DC equals
+ 10 or half the damage you take, whichever number is higher. If you take damage from multiple
+ sources, such as an arrow and a dragon’s breath, you make a separate saving throw for each
+ source of damage.
+
+
+ Being incapacitated or killed. You lose concentration on a spell if you are
+ incapacitated or if you die.{" "}
+
+
+ The GM might also decide that certain environmental phenomena, such as a wave crashing over you while
+ you’re on a storm--tossed ship, require you to succeed on a DC 10 Constitution saving throw to
+ maintain concentration on a spell.
+
+
+ >
+ ) : (
+ <>>
+ )}
+
+
+ {data.spell_lists.map((b) => {
+ return (
+
+ {b}
+
+ );
+ })}
+
+ {data.desc}
+
+
+ Range: {data.range}
+
+
+ Duration: {data.duration}
+
+
+ Casting Time: {data.casting_time}
+
+
+ {data.higher_level !== "" ? (
+ <>
+
+
+ Higher Level: {data.higher_level}
+
+ >
+ ) : (
+ <>>
+ )}
+
+
+ Additional Info
+
+ Material Components: {(data.requires_material_components && `${data.material}`) || `None`}
+
+
+ Classes: {data.dnd_class}
+
+
+ Cast as ritual:
+ {data.can_be_cast_as_ritual ? "True" : "False"}
+
+
+
+ Source: {" "}
+
+ {data.document__title}
+
+
+
+
+
)}
);
diff --git a/dnd-app/frontend/src/DetailRoutes/Weapons.jsx b/dnd-app/frontend/src/DetailRoutes/Weapons.jsx
index 6652f50..1563f11 100644
--- a/dnd-app/frontend/src/DetailRoutes/Weapons.jsx
+++ b/dnd-app/frontend/src/DetailRoutes/Weapons.jsx
@@ -1,17 +1,10 @@
/* eslint-disable no-mixed-spaces-and-tabs */
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardText,
- CardTitle,
- Col,
- Container,
- ListGroup,
- ListGroupItem,
- Row,
-} from "reactstrap";
+import { useEffect, useState } from "react";
+import ReactMarkdown from "react-markdown";
+import { useParams } from "react-router-dom";
+import { Badge, Card, CardBody, CardText, CardTitle, Col, Container, ListGroup, ListGroupItem, Row } from "reactstrap";
+import DndApi from "../api";
+import { Loading } from "../Loading";
import("../assets/styles/Details.css");
@@ -20,20 +13,36 @@ import("../assets/styles/Details.css");
* @param {{data}} data - The data object containing information about the weapon.
* @returns JSX element displaying the weapon information.
*/
-export function Weapons({ data }) {
+export function Weapons() {
+ const { slug } = useParams();
+ const [loading, setLoading] = useState(true);
+ const [data, setData] = useState(null);
+
+ useEffect(() => {
+ /**
+ * Asynchronously fetches information about a specific weapon from an external API.
+ * Sets loading state to true before making the API call and sets it to false after receiving the response.
+ * @returns None
+ */
+ async function getInfo() {
+ setLoading(true);
+ let res = await DndApi.getFromExternal({ type: "weapons", slug });
+ setData(res);
+ setLoading(false);
+ }
+ getInfo();
+ }, [slug]);
+
return (
-
-
-
+ {loading ? (
+
+ ) : (
+
{data.name}
- {data.category ? (
- {data.category}
- ) : (
- ""
- )}
+ {data.category ? {data.category} : ""}
{data.cost ? (
@@ -46,10 +55,7 @@ export function Weapons({ data }) {
{data.damage_dice ? (
Damage:
- {data.damage_dice}{" "}
-
- {data.damage_type}
-
+ {data.damage_dice} {data.damage_type}
) : (
""
@@ -75,10 +81,7 @@ export function Weapons({ data }) {
Properties:
{data.properties.map((item) => (
-
+
{item}
)) || "None"}
@@ -87,15 +90,13 @@ export function Weapons({ data }) {
Source: {" "}
-
- {data.document__title}
-
+ {data.document__title}
-
-
+
+ )}
);
}
diff --git a/dnd-app/frontend/src/Home.jsx b/dnd-app/frontend/src/Home.jsx
index 584ecca..25c3408 100644
--- a/dnd-app/frontend/src/Home.jsx
+++ b/dnd-app/frontend/src/Home.jsx
@@ -23,7 +23,7 @@ export function Home() {
- Welcome to a Dungeons and Dragons Companion
+ Welcome to Arcane Atlas
diff --git a/dnd-app/frontend/src/Loading.jsx b/dnd-app/frontend/src/Loading.jsx
new file mode 100644
index 0000000..a1c7aa4
--- /dev/null
+++ b/dnd-app/frontend/src/Loading.jsx
@@ -0,0 +1,18 @@
+import { Progress, Spinner, Toast, ToastBody, ToastHeader } from "reactstrap";
+
+import "./assets/styles/Loading.css";
+
+export function Loading() {
+ return (
+ <>
+
+ Loading...}>
+ Loading...
+
+
+
+
+
+ >
+ );
+}
diff --git a/dnd-app/frontend/src/NavBar.jsx b/dnd-app/frontend/src/NavBar.jsx
index 112f391..7d64af2 100644
--- a/dnd-app/frontend/src/NavBar.jsx
+++ b/dnd-app/frontend/src/NavBar.jsx
@@ -24,19 +24,13 @@ export function NavBar() {
const toggle = () => setDropdownOpen((prevState) => !prevState);
return (
-
+
-
+
-
+
@@ -51,9 +45,7 @@ export function NavBar() {
) : (
<>
-
- {user.user.username}
-
+ {user.user.username}
Logout
diff --git a/dnd-app/frontend/src/RouteList.jsx b/dnd-app/frontend/src/RouteList.jsx
index ed7c847..64fd652 100644
--- a/dnd-app/frontend/src/RouteList.jsx
+++ b/dnd-app/frontend/src/RouteList.jsx
@@ -1,10 +1,10 @@
import { Route, Routes } from "react-router-dom";
-import { Container } from "reactstrap";
import { NotFound } from "./404";
import { DetailRoutes } from "./DetailRoutes/DetailRoutes";
import { Home } from "./Home";
import { SearchResult } from "./SearchResults";
+import { Test } from "./Test";
import { UserRoutes } from "./UserRoutes/UserRoutes";
/**
@@ -14,15 +14,14 @@ import { UserRoutes } from "./UserRoutes/UserRoutes";
export function RouteList() {
return (
-
-
- } />
- {UserRoutes()}
- {DetailRoutes()}
- } />
- } />
-
-
+
+ } />
+ {UserRoutes()}
+ {DetailRoutes()}
+ } />
+ } />
+ } />
+
);
}
diff --git a/dnd-app/frontend/src/SearchCard.jsx b/dnd-app/frontend/src/SearchCard.jsx
index 3f9d216..7530f4b 100644
--- a/dnd-app/frontend/src/SearchCard.jsx
+++ b/dnd-app/frontend/src/SearchCard.jsx
@@ -1,18 +1,8 @@
import { useEffect, useState } from "react";
-import {
- Badge,
- Card,
- CardBody,
- CardImg,
- CardTitle,
- Col,
- Container,
- Row,
-} from "reactstrap";
+import { Badge, Card, CardBody, CardTitle, Container } from "reactstrap";
import DndApi from "./api";
import("./assets/styles/Details.css");
-import("./assets/styles/SearchCard.css");
/**
* Functional component for rendering a search card with data fetched from an external API.
@@ -36,34 +26,21 @@ export function SearchCard({ data }) {
}, [data]);
return (
-
-
-
-
-
-
-
-
-
- {info.name} {" "}
-
- Tag: {data.type}
-
-
- {info.document__title}
-
-
-
-
-
-
-
+
+
+
+
+ {info.name} {" "}
+
+
+ Tag: {data.type}
+
+
+ {info.document__title}
+
+
+
+
);
}
diff --git a/dnd-app/frontend/src/SearchResults.jsx b/dnd-app/frontend/src/SearchResults.jsx
index 07997d7..ba941a4 100644
--- a/dnd-app/frontend/src/SearchResults.jsx
+++ b/dnd-app/frontend/src/SearchResults.jsx
@@ -1,9 +1,10 @@
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
-import { Button, Col, Container, Row, Spinner } from "reactstrap";
+import { Button, Container, Row } from "reactstrap";
+import DndApi from "./api";
+import { Loading } from "./Loading";
import { SearchCard } from "./SearchCard";
import { SuggestionDropdown } from "./SuggestionDropdown";
-import DndApi from "./api";
/**
* Functional component that displays search results based on the query parameter in the URL.
@@ -46,9 +47,7 @@ export function SearchResult() {
No results found
);
- return currentNode.data.map((item) => (
-
- ));
+ return currentNode.data.map((item) => );
};
/**
@@ -79,34 +78,31 @@ export function SearchResult() {
<>
+ {list ? (
+
+
+ Found {list.results || 0} results. Showing results {currentNode.index * 10 + 1} to{" "}
+ {currentNode.index * 10 + 1 + currentNode.data.length}{" "}
+
+
+ ) : (
+ ""
+ )}
{loading ? (
-
+
) : (
<>
{renderSearchCards()}
-
-
-
- Previous
-
-
-
-
-
- Next
-
-
-
+
+
+ Previous
+
+
+ Next
+
+
>
)}
diff --git a/dnd-app/frontend/src/SuggestionDropdown.jsx b/dnd-app/frontend/src/SuggestionDropdown.jsx
index 8490485..3f440db 100644
--- a/dnd-app/frontend/src/SuggestionDropdown.jsx
+++ b/dnd-app/frontend/src/SuggestionDropdown.jsx
@@ -101,14 +101,11 @@ export function SuggestionDropdown() {
};
return (
-
-
+ <>
+
- setDropdownOpen(!dropdownOpen)}
- >
-
+ setDropdownOpen(!dropdownOpen)}>
+
{filteredResults.length > 0 ? (
filteredResults.map((item) => (
- handleItemClick(item)}
- >
+ handleItemClick(item)}>
{getHighlightedText(item.name, query)}
))
) : (
-
- Search results: None
-
+ Search results: None
)}
-
+ >
);
}
diff --git a/dnd-app/frontend/src/Test.jsx b/dnd-app/frontend/src/Test.jsx
new file mode 100644
index 0000000..c8f1a4f
--- /dev/null
+++ b/dnd-app/frontend/src/Test.jsx
@@ -0,0 +1,18 @@
+import { Progress, Spinner, Toast, ToastBody, ToastHeader } from "reactstrap";
+
+import "./assets/styles/Loading.css";
+
+export function Test() {
+ return (
+ <>
+
+ Loading...}>
+ Loading...
+
+
+
+
+
+ >
+ );
+}
diff --git a/dnd-app/frontend/src/api.js b/dnd-app/frontend/src/api.js
index bbdc5c7..9f87926 100644
--- a/dnd-app/frontend/src/api.js
+++ b/dnd-app/frontend/src/api.js
@@ -1,7 +1,7 @@
import axios from "axios";
import { LinkedList, getDescription } from "./tools";
-const BASE_URL = "https://dnd-util-backend.onrender.com";
+const BASE_URL = "http://localhost:3001";
/**
* A class for making API requests to the D&D API.
@@ -150,6 +150,8 @@ class DndApi {
list.push(chunk);
}
+ list.results = res.results.length;
+
return list;
}
diff --git a/dnd-app/frontend/src/assets/styles/Loading.css b/dnd-app/frontend/src/assets/styles/Loading.css
new file mode 100644
index 0000000..1e357b2
--- /dev/null
+++ b/dnd-app/frontend/src/assets/styles/Loading.css
@@ -0,0 +1,3 @@
+#load{
+ top: 100px;
+}
diff --git a/dnd-app/frontend/src/assets/styles/NavBar.css b/dnd-app/frontend/src/assets/styles/NavBar.css
index 5a62b1e..232118a 100644
--- a/dnd-app/frontend/src/assets/styles/NavBar.css
+++ b/dnd-app/frontend/src/assets/styles/NavBar.css
@@ -5,12 +5,11 @@ nav {
0 3px 1px -2px rgba(0, 0, 0, 0.12),
0 1px 5px 0 rgba(0, 0, 0, 0.2);
border-radius: 0px 0px 20px 0px;
- margin-bottom: 10px;
+ position: sticky;
}
nav a {
color: #000000;
- margin: 0px 10px 0px 0px;
text-decoration: none;
}
@@ -21,11 +20,9 @@ nav a.active {
nav a:hover {
text-decoration: none;
- color: rgb(212, 82, 82);
}
.navbar-brand img {
- height: 5vh;
border-radius: 10px;
border: black 1px solid;
}
@@ -40,3 +37,4 @@ div.dropdown-menu{
nav button:hover{
background-color: #00000042 !important;
}
+
diff --git a/dnd-app/frontend/src/assets/styles/SearchCard.css b/dnd-app/frontend/src/assets/styles/SearchCard.css
index 21ab498..fa1a15a 100644
--- a/dnd-app/frontend/src/assets/styles/SearchCard.css
+++ b/dnd-app/frontend/src/assets/styles/SearchCard.css
@@ -1,5 +1,5 @@
div #search-img{
height: 100px;
- border-radius: 25px;
+ border-radius: 50px;
width: 100px;
}
diff --git a/dnd-app/frontend/src/assets/styles/SuggestionDropdown.css b/dnd-app/frontend/src/assets/styles/SuggestionDropdown.css
index 449e3d0..36ea1aa 100644
--- a/dnd-app/frontend/src/assets/styles/SuggestionDropdown.css
+++ b/dnd-app/frontend/src/assets/styles/SuggestionDropdown.css
@@ -6,7 +6,6 @@
max-height: 15vh;
overflow-y: auto;
overflow-x: hidden;
- width: 50vw;
background-color: aliceblue;
}
diff --git a/dnd-app/frontend/src/assets/styles/index.css b/dnd-app/frontend/src/assets/styles/index.css
index 2b2163a..9af4727 100644
--- a/dnd-app/frontend/src/assets/styles/index.css
+++ b/dnd-app/frontend/src/assets/styles/index.css
@@ -3,10 +3,6 @@
line-height: 1.5;
font-weight: 400;
- color-scheme: light dark;
- color: rgba(0, 0, 0, 0.87);
-
- font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -23,10 +19,7 @@ a:hover {
}
body {
- margin: 0;
display: flex;
- min-width: 99vw;
- min-height: 100vh;
background-color: #ffcf76;
@@ -34,39 +27,7 @@ body {
background-repeat: no-repeat, repeat;
}
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
+main{
+ position: relative;
+ top: 15vh;
}
diff --git a/dnd-app/frontend/src/tools.js b/dnd-app/frontend/src/tools.js
index e05995e..f743e1c 100644
--- a/dnd-app/frontend/src/tools.js
+++ b/dnd-app/frontend/src/tools.js
@@ -3,8 +3,9 @@
* Represents a node in a linked list.
*/
class Node {
- constructor(data) {
+ constructor(data, index) {
this.data = data;
+ this.index = index;
this.next = null;
this.prev = null;
}
@@ -17,6 +18,8 @@ class LinkedList {
constructor() {
this.head = null;
this.length = 0;
+ this.results = 0;
+ this.data = []
}
/**
@@ -27,16 +30,19 @@ class LinkedList {
* @returns None
*/
push(val) {
+ let new_node = new Node(val, this.length);
+
if (this.head === null) {
- let new_node = new Node(val);
this.head = new_node;
this.tail = new_node;
} else {
- let new_node = new Node(val);
new_node.prev = this.tail;
this.tail.next = new_node;
this.tail = new_node;
}
+
+ this.data.push(new_node);
+
this.length += 1;
}
}
@@ -50,9 +56,6 @@ function getDescription(data) {
return data.desc || data.description || null;
}
-
-
-
/**
* Calculates an ability's modifier based on the input ability score.
* The score is calculated by subtracting 10 from the input number and then dividing the result by 2.
@@ -85,10 +88,4 @@ const parseTableString = (tableString) => {
return { headers, info };
};
-export {
- LinkedList,
- Node,
- getDescription,
- getScore,
- parseTableString,
-};
+export { LinkedList, Node, getDescription, getScore, parseTableString };
diff --git a/dnd-app/package.json b/dnd-app/package.json
index ce2a5f3..699ed27 100644
--- a/dnd-app/package.json
+++ b/dnd-app/package.json
@@ -4,9 +4,7 @@
"description": "",
"main": "",
"scripts": {
- "start": "npm-run-all --parallel backend frontend",
- "backend": "nodemon ./backend/server.js",
- "frontend": "cd ./frontend && npm run dev"
+ "start": "cmd /c start-app.bat"
},
"jest": {
"testPathIgnorePatterns": [
diff --git a/dnd-app/start-app.bat b/dnd-app/start-app.bat
new file mode 100644
index 0000000..39f4b98
--- /dev/null
+++ b/dnd-app/start-app.bat
@@ -0,0 +1,3 @@
+@echo off
+start powershell -NoExit -Command "cd ./backend; nodemon server.js"
+start powershell -NoExit -Command "cd ./frontend; npm run dev"