Updated spells modal

This commit is contained in:
Benjamin Sherriff
2023-10-11 15:06:41 -04:00
parent 09925251dd
commit f4a47e8d4b
3 changed files with 73 additions and 86 deletions

View File

@@ -177,54 +177,13 @@ pub struct Range {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Area { pub struct Area {
#[serde(rename = "type")] #[serde(rename = "type")]
pub area_type: AreaType, pub area_type: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<i32>, pub value: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub unit: Option<String> pub unit: Option<String>
} }
#[derive(Debug, Serialize, Deserialize)]
pub enum AreaType {
#[serde(rename = "cone")]
Cone,
#[serde(rename = "cube")]
Cube,
#[serde(rename = "cylinder")]
Cylinder,
#[serde(rename = "line")]
Line,
#[serde(rename = "sphere")]
Sphere
}
// impl AreaType {
// pub fn to_string(&self) -> String {
// match self {
// AreaType::Cone => "cone".to_string(),
// AreaType::Cube => "cube".to_string(),
// AreaType::Cylinder => "cylinder".to_string(),
// AreaType::Line => "line".to_string(),
// AreaType::Sphere => "sphere".to_string()
// }
// }
// }
// impl FromStr for AreaType {
// type Err = ();
// fn from_str(s: &str) -> Result<Self, Self::Err> {
// match s {
// "cone" => Ok(AreaType::Cone),
// "cube" => Ok(AreaType::Cube),
// "cylinder" => Ok(AreaType::Cylinder),
// "line" => Ok(AreaType::Line),
// "sphere" => Ok(AreaType::Sphere),
// _ => Err(())
// }
// }
// }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Duration { pub struct Duration {
#[serde(rename = "type")] #[serde(rename = "type")]

View File

@@ -22,6 +22,16 @@ export default function Page() {
const [activeSpell, setActiveSpell] = useState<Spell | undefined>(undefined); const [activeSpell, setActiveSpell] = useState<Spell | undefined>(undefined);
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [searchName, setSearchName] = useState(''); const [searchName, setSearchName] = useState('');
const [includeCantrips, setIncludeCantrips] = useState(true);
const [includeLevel1, setIncludeLevel1] = useState(true);
const [includeLevel2, setIncludeLevel2] = useState(true);
const [includeLevel3, setIncludeLevel3] = useState(true);
const [includeLevel4, setIncludeLevel4] = useState(true);
const [includeLevel5, setIncludeLevel5] = useState(true);
const [includeLevel6, setIncludeLevel6] = useState(true);
const [includeLevel7, setIncludeLevel7] = useState(true);
const [includeLevel8, setIncludeLevel8] = useState(true);
const [includeLevel9, setIncludeLevel9] = useState(true);
useEffect(() => { useEffect(() => {
getSpells({ levels: [0] }).then((s) => setCantrips(s.data)); getSpells({ levels: [0] }).then((s) => setCantrips(s.data));
@@ -54,6 +64,15 @@ export default function Page() {
}} }}
/> />
<hr /> <hr />
<SpellSection
title='Level 1'
spells={level1.filter((s) => s.name.toLowerCase().includes(searchName.toLowerCase()))}
onClick={(spell) => {
setActiveSpell(spell);
setIsOpen(true);
}}
/>
<hr />
{activeSpell && <SpellModal spell={activeSpell} isOpen={isOpen} onClose={() => setIsOpen(false)} />} {activeSpell && <SpellModal spell={activeSpell} isOpen={isOpen} onClose={() => setIsOpen(false)} />}
</Box> </Box>
); );

View File

@@ -50,7 +50,7 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps)
<span style={{ overflowWrap: 'break-word' }}> <span style={{ overflowWrap: 'break-word' }}>
{spell.classes.map((c) => ( {spell.classes.map((c) => (
<span style={{ paddingRight: '0.6em', display: 'inline-block' }} className='link'> <span style={{ paddingRight: '0.6em', display: 'inline-block' }} className='link'>
{capitalize(c)} {parseText(c, true)}
</span> </span>
))} ))}
</span> </span>
@@ -86,65 +86,74 @@ export default function SpellModal({ spell, isOpen, onClose }: SpellModalProps)
); );
} }
function SpellDescription({ spell }: { spell: Spell }) { function parseText(text: string, capitalizeFirst?: boolean) {
function parseText(text: string) { const regex = /{@(.*?) (.*?)}/g;
const regex = /{@(.*?) (.*?)}/g; const matches = text.matchAll(regex);
const matches = text.matchAll(regex); const result = [];
const result = []; let lastIndex = 0;
let lastIndex = 0; for (const match of matches) {
for (const match of matches) { const [full, type, name] = match;
const [full, type, name] = match; result.push(text.slice(lastIndex, match.index));
result.push(text.slice(lastIndex, match.index)); if (match.index !== undefined) {
if (match.index !== undefined) { if (type == 'dice') {
result.push( result.push(
<span onClick={() => handleLink(type, name)} className='link'> <span onClick={() => handleLink(type, name)} className='link'>
{name} {name}
</span> </span>
); );
lastIndex = match.index + full.length; } else if (type == 'scaledice') {
// scaledice format is {@scaledice 1d6|1-9|1d6|}. Parse this out into dice, levels, and dice again.
const [dice, levels] = name.split('|');
result.push(
<span onClick={() => handleLink('dice', dice)} className='link'>
{dice}
</span>
);
} else if (type == 'bold') {
result.push(<span style={{ fontWeight: 'bold' }}>{name}</span>);
} else if (type == 'subclass') {
const [className, subclassName] = name.split('|');
result.push(
<span>
{capitalize(className)} ({capitalize(subclassName)})
</span>
);
} else {
result.push(<span>{capitalizeFirst ? capitalize(name) : name}</span>);
} }
lastIndex = match.index + full.length;
} }
result.push(text.slice(lastIndex));
return result;
} }
result.push(text.slice(lastIndex));
return result;
}
function handleLink(type: string, name: string) { function handleLink(type: string, name: string) {
if (type == 'spell') { if (type == 'spell') {
console.log(`Link to spell: ${name}`); console.log(`Link to spell: ${name}`);
} else if (type == 'dice' || type == 'damage') { } else if (type == 'dice') {
const rolls = rollDice(name); const rolls = rollDice(name);
notifications.show({ notifications.show({
title: `Rolling ${name}`, title: `Rolling ${name}`,
message: `${rolls.join(' + ')} = ${rolls.reduce((a, b) => a + b, 0)}`, message: `${rolls.join(' + ')} = ${rolls.reduce((a, b) => a + b, 0)}`,
color: 'blue', color: 'blue',
autoClose: 5000, autoClose: 5000,
withCloseButton: false withCloseButton: false
}); });
} else { } else if (type == 'scaledice') {
console.error(`Unknown link type: ${type}`); console.log(`Link to scaledice: ${name}`);
} } else {
console.error(`Unknown link type: ${type}`);
} }
}
function SpellDescription({ spell }: { spell: Spell }) {
return ( return (
<> <>
{spell.description && ( {spell.description && (
<> <>
{spell.description.entries.map((e) => ( {spell.description.entries.map((e) => (
// typeof e === 'string' ? (
// <p>{parseText(e)}</p>
// ) : (
// <>
// {e.list ? (
// <ul>
// {e.list.map((text) => (
// <li>{parseText(text)}</li>
// ))}
// </ul>
// ) : (
// <></>
// )}
// </>
// )
<> <>
{e.text && <p>{parseText(e.text)}</p>} {e.text && <p>{parseText(e.text)}</p>}
{e.list && ( {e.list && (