react-bootstrap#ButtonGroup TypeScript Examples
The following examples show how to use
react-bootstrap#ButtonGroup.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Settings.tsx From apps with MIT License | 6 votes |
Settings = ({ visibleOnly, updateVisibleOnly, localTime, updateLocalTime }: IProps) => (
<div>
<ButtonGroup>
<Button disabled variant="outline-dark">
Showing{" "}
</Button>
<Button variant={visibleOnly ? "warning" : "success"} onClick={() => updateVisibleOnly(!visibleOnly)}>
{visibleOnly ? "only entries with visible changes" : "all entries"}
</Button>
<Button variant={localTime ? "warning" : "success"} onClick={() => updateLocalTime(!localTime)}>
{localTime ? "with local timestamps" : "with UTC timestamps"}
</Button>
</ButtonGroup>
<br />
</div>
)
Example #2
Source File: BattleActorAttackDisplay.tsx From apps with MIT License | 6 votes |
render() {
return (
<div>
<ButtonGroup className="battle-actor-action-display">
<Button className="action" variant="danger" onClick={(e) => this.queueAction(Card.BUSTER)}>
B
</Button>
<Button className="action" variant="success" onClick={(e) => this.queueAction(Card.QUICK)}>
Q
</Button>
<Button className="action" variant="primary" onClick={(e) => this.queueAction(Card.ARTS)}>
A
</Button>
<Button className="action" variant="secondary">
NP
</Button>
</ButtonGroup>
</div>
);
}
Example #3
Source File: BgmDescriptor.tsx From apps with MIT License | 5 votes |
export default function BgmDescriptor(props: {
region: Region;
bgm: Bgm.Bgm;
showName?: string;
showLink?: boolean;
style?: React.CSSProperties;
}) {
const bgm = props.bgm;
if (bgm.id === 0) {
return null;
} else if (bgm.audioAsset !== undefined) {
const showName = getBgmName(bgm);
const toLink = props.showLink ? (
<>
<Button variant="primary" as={Link} to={`/${props.region}/bgm/${bgm.id}`}>
<FontAwesomeIcon icon={faShare} title={`Go to ${props.region} BGM ${showName}`} />
</Button>
</>
) : null;
const downloadButton = bgm.notReleased ? (
<Button disabled variant="secondary" target="_blank" title={showName}>
{showName}
</Button>
) : (
<Button variant={"info"} href={bgm.audioAsset} target="_blank" title={`Download ${showName}`}>
{props.showName ?? showName}
<FontAwesomeIcon icon={faFileAudio} />
</Button>
);
return (
<>
<ButtonGroup size="sm" style={props.style}>
<VoiceLinePlayer audioAssetUrls={[bgm.audioAsset]} delay={[0]} title={bgm.name} />
{downloadButton}
{toLink}
</ButtonGroup>
</>
);
} else {
return (
<Button variant={"info"} disabled style={props.style}>
{bgm.name}
</Button>
);
}
}
Example #4
Source File: SettingForm.tsx From apps with MIT License | 5 votes |
render() {
return (
<div>
<Form>
<Form.Group>
<Form.Label>Language</Form.Label>
<Form.Control
as={"select"}
value={this.props.language}
onChange={(ev: Event) => this.updateLanguage(ev.target.value)}
>
{Object.values(Language).map((v) => (
<option key={v} value={v}>
{v}
</option>
))}
</Form.Control>
</Form.Group>
<Form.Group>
<Form.Label>Theme</Form.Label>
<Form.Control
as={"select"}
value={this.props.theme}
onChange={(ev: Event) => this.updateTheme(ev.target.value)}
>
{Object.values(Theme).map((v) => (
<option key={v} value={v}>
{v}
</option>
))}
</Form.Control>
</Form.Group>
</Form>
<ButtonGroup style={{ width: "100%", marginBottom: "1em" }}>
<Button
variant={Manager.shopPlannerEnabled() ? "success" : "secondary"}
onClick={() => this.updateShopPlannerEnabled(!Manager.shopPlannerEnabled())}
>
Shop planner: {Manager.shopPlannerEnabled() ? "Enabled" : "Disabled"}
</Button>
</ButtonGroup>
<ButtonGroup style={{ width: "100%", marginBottom: "1em" }}>
<Button
variant={Manager.scriptSceneEnabled() ? "success" : "secondary"}
onClick={() => this.updateScriptSceneEnabled(!Manager.scriptSceneEnabled())}
>
Script Scene: {Manager.scriptSceneEnabled() ? "Enabled" : "Disabled"}
</Button>
</ButtonGroup>
<ButtonGroup style={{ width: "100%", marginBottom: "1em" }}>
<Button
variant={Manager.showScriptLine() ? "success" : "secondary"}
onClick={() => Manager.setShowScriptLine(!Manager.showScriptLine())}
>
Original line number in scripts: {Manager.showScriptLine() ? "Shown" : "Hidden"}
</Button>
</ButtonGroup>
<ButtonGroup style={{ width: "100%" }}>
<Button
variant={Manager.hideEnemyFunctions() ? "success" : "secondary"}
onClick={() => this.updateHideEnemyFunction(!Manager.hideEnemyFunctions())}
>
Enemy functions {Manager.hideEnemyFunctions() ? "hidden" : "shown"}
</Button>
</ButtonGroup>
</div>
);
}
Example #5
Source File: Header.tsx From peterportal-client with MIT License | 5 votes |
Header: FC<HeaderProps> = ({ courseCount, unitCount, saveRoadmap }) => {
const dispatch = useAppDispatch();
const [target, setTarget] = useState<any>(null!);
const [showMenu, setShowMenu] = useState(false);
const buttons = <>
<Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={() => dispatch(setShowTransfer(true))}>
Transfer Credits
<ArrowLeftRight className="header-icon" />
</Button>
<Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={saveRoadmap}>
Save
<Save className="header-icon" />
</Button>
<Button variant={isMobile ? "primary" : 'light'} className={isMobile ? 'my-1' : "header-btn"} onClick={() => dispatch(clearPlanner())}>
Clear
<Trash className="header-icon" />
</Button>
</>
const onMenuClick = (event: React.MouseEvent) => {
setShowMenu(!showMenu);
setTarget(event.target);
};
return (
<div className="header">
<Transfer />
<div>
<div id="title">
Peter's Roadmap
</div>
<span id="planner-stats">
Total: <span id="course-count">{courseCount}</span>{" "}
{courseCount === 1 ? "course" : "courses"},{" "}
<span id="unit-count">{unitCount}</span>{" "}
{unitCount === 1 ? "unit" : "units"}
</span>
</div>
<div>
{
isMobile && <>
<Button variant="light" className="header-btn add-course" onClick={() => { dispatch(setShowSearch(true)) }}>
<Plus className="header-icon mr-1" />
Add Course
</Button>
<List className='mx-3' onClick={onMenuClick} />
<Overlay show={showMenu} target={target} placement="left">
<Popover id='roadmap-header-buttons'>
<Popover.Content>
<div className='d-flex flex-column'>
{buttons}
</div>
</Popover.Content>
</Popover>
</Overlay>
</>
}
{
isBrowser && <ButtonGroup>
{buttons}
</ButtonGroup>
}
</div>
</div >
)
}
Example #6
Source File: IpfsConsoleView.tsx From 3Speak-app with GNU General Public License v3.0 | 4 votes |
//JSON editor specific
export function IpfsConsoleView() {
const [ipfsConfig, setIpfsConfig] = useState({} as any)
const [ipfsInfo, setIpfsInfo] = useState({} as any)
const [configError, setConfigError] = useState(false)
const editor = useRef<any>()
const loopPid = useRef<any>()
const getIpfsConfig = async () => {
const info = await IpfsHandler.getIpfs()
setIpfsInfo(info)
let jsonContent
const { ipfs } = info
if (editor.current) {
editor.current?.createEditor({
value: await ipfs.config.getAll(),
ace: ace,
mode: 'code',
theme: 'ace/theme/solarized_dark',
ref: editor,
htmlElementProps: {
style: {
height: '500px',
},
},
onChange: (json) => {
jsonContent = json
},
})
} else {
throw new Error(`editor ref is not defined! Cannot create editor.`)
}
}
const update = async () => {
console.log(`UPDATING`)
const annotations = editor.current.jsonEditor.aceEditor.getSession().getAnnotations()
setConfigError(annotations.length === 0 ? false : true)
}
useEffect(() => {
void getIpfsConfig()
loopPid.current = setInterval(update, 150)
return () => {
clearInterval(loopPid.current)
}
}, [])
return (
<div style={{ padding: '5px', overflow: 'hidden' }}>
<h3>
This is the IPFS Debug Console. This is for advanced users only, if you don't know what you
are doing stay out of this area.
</h3>
<div style={{ overflow: 'show' }}>
<Row>
<Col style={{ background: '#f8f9fa', margin: '5px' }}>
<Editor
value={ipfsConfig}
ace={ace}
mode="code"
theme="ace/theme/solarized_dark"
ref={editor}
htmlElementProps={{
style: {
height: '560px',
},
}}
onChange={(json) => {
console.log(json)
}}
/>
<ButtonGroup>
<Button
variant="success"
onClick={async () => {
try {
const jsonContent = editor.current.jsonEditor.get()
NotificationManager.success('IPFS config saved')
await ipfsInfo.ipfs.config.replace(jsonContent)
} catch (ex) {
console.error(ex)
}
}}
disabled={configError}
>
Save
</Button>
</ButtonGroup>
</Col>
<Col style={{ background: '#f8f9fa', margin: '5px' }}>
<IpfsStatsView />
</Col>
</Row>
<Row>
<Col style={{ background: '#f8f9fa', margin: '5px' }}></Col>
<Col style={{ background: '#f8f9fa', margin: '5px' }}></Col>
</Row>
</div>
</div>
)
}
Example #7
Source File: BgmsPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
const bgms = this.bgms(),
results = bgms.slice(this.state.perPage * this.state.page, this.state.perPage * (this.state.page + 1));
const pageNavigator = this.paginator(bgms.length);
return (
<div id="bgms" className="listing-page">
<Row>
<Col md={12} lg={6} id="item-type">
<ButtonGroup>
<Button
variant={this.state.releaseOnlyFilter === true ? "success" : "outline-dark"}
onClick={(_) => this.toggleReleaseOnlyFilter(true)}
>
Buyable in my room
</Button>
<Button
variant={this.state.releaseOnlyFilter === false ? "success" : "outline-dark"}
onClick={(_) => this.toggleReleaseOnlyFilter(false)}
>
Not buyable in my room
</Button>
</ButtonGroup>
</Col>
<Col md={12} lg={3} id="item-search">
<Form inline>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({
search: ev.target.value,
page: 0,
});
}}
/>
</Form>
</Col>
</Row>
<Row>
<Col>{pageNavigator}</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center">#</th>
<th className="col-center">Logo</th>
<th>Name</th>
<th>Unlock Cost</th>
<th>Player</th>
</tr>
</thead>
<tbody>
{results.map((bgm) => {
const route = `/${this.props.region}/bgm/${bgm.id}`;
const showName = getBgmName(bgm);
const shopDetail = bgm.shop ? (
<>
<ItemDescriptor region={this.props.region} item={bgm.shop.cost.item} /> ×
{bgm.shop.cost.amount}
</>
) : null;
return (
<tr key={bgm.id}>
<td className="col-center">
<Link to={route}>{bgm.id}</Link>
</td>
<td className="col-center">
<Link to={route}>
<img src={bgm.logo} style={{ height: "1.5em" }} alt="BGM Logo" />
</Link>
</td>
<td
style={{
whiteSpace: Manager.showingJapaneseText() ? "pre-wrap" : "normal",
}}
>
<Link to={route}>{showName}</Link>
</td>
<td>{shopDetail}</td>
<td>
<BgmDescriptor region={this.props.region} bgm={bgm} showName="Download" />
</td>
</tr>
);
})}
</tbody>
</Table>
{pageNavigator}
</div>
);
}
Example #8
Source File: CommandCodesPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
return (
<div id="command-codes" className="listing-page">
<Row>
<Col sm={6} md={5} id="item-rarity">
<ButtonGroup>
{[...new Set(this.state.commandCodes.map((s) => s.rarity))]
// deduplicate star counts
.sort((a, b) => a - b)
// sort
.map((rarity) => (
<Button
variant={
this.state.activeRarityFilters.includes(rarity) ? "success" : "outline-dark"
}
key={rarity}
onClick={(_) => this.toggleRarityFilter(rarity)}
>
{rarity} ★
</Button>
))}
</ButtonGroup>
</Col>
<Col sm={6} md={3} id="item-search">
<Form inline>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({ search: ev.target.value });
}}
/>
</Form>
</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center">#</th>
<th className="col-center">Thumbnail</th>
<th>Name</th>
<th className="rarity-col">Rarity</th>
</tr>
</thead>
<tbody>
{this.commandCodes().map((commandCode) => {
const route = `/${this.props.region}/command-code/${commandCode.collectionNo}`;
return (
<tr key={commandCode.id}>
<td className="col-center">
<Link to={route}>{commandCode.collectionNo}</Link>
</td>
<td className="col-center">
<Link to={route}>
<FaceIcon
rarity={commandCode.rarity}
location={commandCode.face}
height={50}
/>
</Link>
</td>
<td>
<Link to={route}>{commandCode.name}</Link>
</td>
<td className="rarity-col">
<RarityDescriptor rarity={commandCode.rarity} />
</td>
</tr>
);
})}
</tbody>
</Table>
</div>
);
}
Example #9
Source File: CraftEssencesPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
const craftEssences = this.craftEssences(),
results = craftEssences.slice(
this.state.perPage * this.state.page,
this.state.perPage * (this.state.page + 1)
);
const pageNavigator = this.paginator(craftEssences.length);
return (
<div id="craft-essences" className="listing-page">
<Row>
<Col md={12} lg={6} xl={5} id="item-type">
<ButtonGroup>
{[
[CEType.OTHER, "Regular CE"],
[CEType.VALENTINE, "Valentine CE"],
[CEType.BOND, "Bond CE"],
[CEType.COMMEMORATIVE, "EXP CE"],
].map(([ceType, buttonText]) => {
return (
<Button
variant={
this.state.activeCETypeFilters.includes(ceType as CEType)
? "success"
: "outline-dark"
}
key={ceType}
onClick={(_) => this.toggleCETypeFilter(ceType as CEType)}
>
{buttonText}
</Button>
);
})}
</ButtonGroup>
</Col>
<Col md={12} lg={3} id="item-search">
<Form inline>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({ search: ev.target.value, page: 0 });
}}
/>
</Form>
</Col>
</Row>
<Row>
<Col sm={12} md={5} id="item-rarity">
<ButtonGroup>
{[...new Set(this.state.craftEssences.map((s) => s.rarity))]
// deduplicate star counts
.sort((a, b) => a - b)
// sort
.map((rarity) => (
<Button
variant={
this.state.activeRarityFilters.includes(rarity) ? "success" : "outline-dark"
}
key={rarity}
onClick={(_) => this.toggleRarityFilter(rarity)}
>
{rarity} ★
</Button>
))}
</ButtonGroup>
</Col>
<Col sm={12} md={7}>
{pageNavigator}
</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center">#</th>
<th className="col-center">Thumbnail</th>
<th>Name</th>
<th className="rarity-col">Rarity</th>
</tr>
</thead>
<tbody>
{results.map((craftEssence) => {
const route = `/${this.props.region}/craft-essence/${craftEssence.collectionNo}`;
return (
<tr key={craftEssence.id}>
<td className="col-center">
<Link to={route}>
{craftEssence.collectionNo} (
<span className="listing-svtId" lang="en-US">
{craftEssence.id}
</span>
)
</Link>
</td>
<td className="col-center">
<Link to={route}>
<FaceIcon
type={Entity.EntityType.SERVANT_EQUIP}
rarity={craftEssence.rarity}
location={craftEssence.face}
height={50}
/>
</Link>
</td>
<td style={{ whiteSpace: Manager.showingJapaneseText() ? "pre-wrap" : "normal" }}>
<Link to={route}>{craftEssence.name}</Link>
</td>
<td className="rarity-col">
<RarityDescriptor rarity={craftEssence.rarity} />
</td>
</tr>
);
})}
</tbody>
</Table>
{pageNavigator}
</div>
);
}
Example #10
Source File: Shop.tsx From apps with MIT License | 4 votes |
ShopTab = ({ region, shops, filters, onChange, itemCache, questCache }: IProps) => {
let [forceEnablePlanner, setForceEnablePlanner] = useState<boolean | undefined>(undefined);
let [itemFilters, setItemFilters] = useState(new Set<number>());
const allItems = new Map(shops.map((shop) => [shop.cost.item.id, shop.cost.item]));
let shopEnabled = forceEnablePlanner === undefined ? Manager.shopPlannerEnabled() : forceEnablePlanner;
let counted = shops
.filter((shop) => (shopEnabled ? filters.has(shop.id) : true))
.map(
(shop) =>
[shop.cost.item, (shopEnabled ? filters.get(shop.id)! : shop.limitNum) * shop.cost.amount] as const
);
let items = new Map(counted.map((tuple) => [tuple[0].id, tuple[0]]));
let amounts = new Map<number, number>();
for (let [item, amount] of counted)
if (amounts.has(item.id)) amounts.set(item.id, (amounts.get(item.id) ?? 0) + amount);
else amounts.set(item.id, amount);
// reset filter if nothing is chosen
if (!amounts.size && itemFilters.size) setItemFilters(new Set());
const excludeItemIds = (itemIds: number[]) => {
return new Map(
shops
.filter((shop) => shop.payType !== Shop.PayType.FREE)
.filter((shop) => shop.limitNum !== 0)
.filter((shop) => !itemIds.includes(shop.targetIds[0]) || shop.purchaseType !== Shop.PurchaseType.ITEM)
.map((shop) => [shop.id, shop.limitNum])
);
};
return (
<>
<Alert variant="success" style={{ margin: "1em 0", display: "flex" }}>
<div style={{ flexGrow: 1 }}>
{shopEnabled
? amounts.size > 0
? "Total amount for chosen items: "
: "No item was chosen. Choose at least one to get calculations."
: "Total currency amount needed to clear the shop: "}
{[...amounts]
.filter(([_, amount]) => amount > 0)
.map(([itemId, amount]) => (
<span style={{ whiteSpace: "nowrap", paddingRight: "1ch" }} key={itemId}>
<IconLink region={region} item={items.get(itemId)!} />
<b>×{amount.toLocaleString()}</b>
</span>
))}
</div>
<div style={{ flexBasis: "auto", paddingLeft: "10px" }}>
<Button
variant={shopEnabled ? "dark" : "success"}
onClick={() => setForceEnablePlanner(!forceEnablePlanner)}
>
<FontAwesomeIcon icon={faEdit} title={shopEnabled ? "Disable planner" : "Enable planner"} />
</Button>
</div>
</Alert>
{shopEnabled && (
<>
<ButtonGroup>
<Button disabled variant="outline-dark">
Quick toggle
</Button>
<Button variant="outline-success" onClick={() => onChange?.(excludeItemIds([]))}>
All
</Button>
<Button variant="outline-success" onClick={() => onChange?.(new Map())}>
None
</Button>
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle variant="outline-success">Exclude</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item
as={Button}
onClick={() =>
onChange?.(excludeItemIds([...gemIds, ...magicGemIds, ...secretGemIds]))
}
>
Gems
</Dropdown.Item>
<Dropdown.Item
as={Button}
onClick={() => onChange?.(excludeItemIds([...monumentIds, ...pieceIds]))}
>
Monuments & Pieces
</Dropdown.Item>
<Dropdown.Item as={Button} onClick={() => onChange?.(excludeItemIds(monumentIds))}>
Monuments
</Dropdown.Item>
<Dropdown.Item as={Button} onClick={() => onChange?.(excludeItemIds(pieceIds))}>
Pieces
</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
</ButtonGroup>
<div> </div>
</>
)}
<Table hover responsive className="shopTable">
<thead>
<tr>
<th style={{ textAlign: "left" }}>Detail</th>
<th style={{ whiteSpace: "nowrap" }}>
Currency
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle size="sm">
<FontAwesomeIcon style={{ display: "inline" }} icon={faFilter} />
</Dropdown.Toggle>
<Dropdown.Menu>
{/* Actually a checkbox is the best here */}
<Dropdown.Item
as={Button}
onClick={() => {
setItemFilters(new Set());
}}
>
Reset
</Dropdown.Item>
{[...allItems].map(([itemId, item]) => (
<Dropdown.Item
key={item.id}
as={Button}
onClick={() => {
setItemFilters(new Set([itemId]));
}}
>
<ItemIcon region={region} item={item} height={40} />
{item.name}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</th>
<th>Cost</th>
<th>Item</th>
<th>Set</th>
<th>Limit</th>
{shopEnabled && <th>Target</th>}
</tr>
</thead>
<tbody>
{shops
.filter((shop) =>
itemFilters.size && amounts.size ? itemFilters.has(shop.cost.item.id) : true
)
.sort((a, b) => a.priority - b.priority)
.map((shop) => {
let limitNumIndicator = shopEnabled ? (
<Button
variant="light"
onClick={() => {
filters.set(shop.id, shop.limitNum);
onChange?.(filters);
}}
>
{shop.limitNum.toLocaleString()}
</Button>
) : (
<>{shop.limitNum.toLocaleString()}</>
);
return (
<tr key={shop.id}>
<td style={{ minWidth: "10em" }}>
<b>{shop.name}</b>
<div style={{ fontSize: "0.75rem" }} className="newline">
{colorString(shop.detail)}
<ScriptLink region={region} shop={shop} />
<br />
<div>
{shop.releaseConditions.length ? (
<ul className="condition-list">
{shop.releaseConditions.map((cond, index) => (
<li key={index} style={{ fontSize: "0.75rem" }}>
{cond.closedMessage && `${cond.closedMessage} — `}
<CondTargetNumDescriptor
region={region}
cond={cond.condType}
targets={cond.condValues}
num={cond.condNum}
quests={questCache}
items={itemCache}
/>
</li>
))}
</ul>
) : (
""
)}
</div>
</div>
</td>
<td style={{ textAlign: "center" }}>
{shop.payType !== Shop.PayType.FREE ? (
<IconLink region={region} item={shop.cost.item} />
) : null}
</td>
<td style={{ textAlign: "center" }}>
{shop.payType !== Shop.PayType.FREE ? shop.cost.amount.toLocaleString() : null}
</td>
<td>
<ShopPurchaseDescriptor region={region} shop={shop} itemMap={itemCache} />
</td>
<td style={{ textAlign: "center" }}>{shop.setNum.toLocaleString()}</td>
<td style={{ textAlign: "center" }}>
{shop.limitNum === 0 ? <>Unlimited</> : limitNumIndicator}
</td>
{shopEnabled && (
<>
<td style={{ textAlign: "center", maxWidth: "5em" }}>
<InputGroup size="sm">
<Form.Control
type="number"
value={filters.get(shop.id) ?? 0}
min={0}
max={shop.limitNum || undefined}
onChange={(event) => {
let value = +event.target.value;
if (value) filters.set(shop.id, value);
else filters.delete(shop.id);
onChange?.(filters);
}}
/>
</InputGroup>
</td>
</>
)}
</tr>
);
})}
</tbody>
</Table>
</>
);
}
Example #11
Source File: EventsPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
const events = this.events(),
results = events.slice(this.state.perPage * this.state.page, this.state.perPage * (this.state.page + 1));
const pageNavigator = this.paginator(events.length);
const currentTimestamp = getCurrentTimestamp();
return (
<div id="events" className="listing-page">
<Row>
<Col md={12} lg={6} id="item-type">
<ButtonGroup>
{[
[Event.EventType.EVENT_QUEST, "Event"],
[Event.EventType.COMBINE_CAMPAIGN, "Servant Lvl Up"],
[Event.EventType.SVTEQUIP_COMBINE_CAMPAIGN, "CE Lvl Up"],
[Event.EventType.QUEST_CAMPAIGN, "AP Cost"],
[Event.EventType.WAR_BOARD, "Grail Front"],
].map(([eventType, buttonText]) => {
return (
<Button
variant={
this.state.activeEventTypeFilters.includes(eventType as Event.EventType)
? "success"
: "outline-dark"
}
key={eventType}
onClick={(_) => this.toggleEventTypeFilter(eventType as Event.EventType)}
>
{buttonText}
</Button>
);
})}
</ButtonGroup>
</Col>
<Col md={12} lg={3} id="item-search">
<Form inline>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({
search: ev.target.value,
page: 0,
});
}}
/>
</Form>
</Col>
</Row>
<Row>
<Col sm={12}>{pageNavigator}</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center">#</th>
<th className="col-center">Ongoing</th>
<th>Name</th>
</tr>
</thead>
<tbody>
{results.map((event) => {
const route = `/${this.props.region}/event/${event.id}`;
const isOngoing = currentTimestamp >= event.startedAt && currentTimestamp <= event.endedAt;
return (
<tr key={event.id}>
<td className="col-center">
<Link to={route}>{event.id}</Link>
</td>
<td className="col-center">
{isOngoing ? (
<FontAwesomeIcon
icon={faCheckCircle}
title="Master mission is ongoing right now"
/>
) : null}
</td>
<td>
<Link to={route}>{event.name}</Link>
</td>
</tr>
);
})}
</tbody>
</Table>
{pageNavigator}
</div>
);
}
Example #12
Source File: ScriptPage.tsx From apps with MIT License | 4 votes |
ScriptPage = (props: { region: Region; scriptId: string }) => {
const { region, scriptId } = props;
const showScriptLine = Manager.showScriptLine();
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<AxiosError | undefined>(undefined);
const [script, setScript] = useState<string>("");
const [scriptData, setScriptData] = useState<Script.Script | undefined>(undefined);
const [enableScene, setEnableScene] = useState<boolean>(Manager.scriptSceneEnabled());
useEffect(() => {
Manager.setRegion(region);
setError(undefined);
setLoading(true);
Promise.all([axios.get<string>(getScriptAssetURL(region, scriptId), { timeout: 10000 }), Api.script(scriptId)])
.then(([rawScript, scriptData]) => {
setScript(rawScript.data);
setScriptData(scriptData);
setLoading(false);
})
.catch((e) => setError(e));
}, [region, scriptId]);
if (error !== undefined) return <ErrorStatus error={error} />;
if (loading) return <Loading />;
if (script === "" || scriptData === undefined) return null;
document.title = `[${region}] Script ${scriptId} - Atlas Academy DB`;
const parsedScript = parseScript(region, script);
const audioUrls = [] as string[];
let hasDialogueLines = false;
const addAudioUrls = (component: ScriptComponent) => {
switch (component.type) {
case ScriptComponentType.DIALOGUE:
if (component.voice !== undefined) audioUrls.push(component.voice.audioAsset);
hasDialogueLines = true;
break;
case ScriptComponentType.SOUND_EFFECT:
audioUrls.push(component.soundEffect.audioAsset);
break;
}
};
for (const { content: component } of parsedScript.components) {
switch (component.type) {
case ScriptComponentType.CHOICES:
for (const choice of component.choices) {
for (const choiceComponent of choice.results) {
addAudioUrls(choiceComponent);
}
}
break;
default:
addAudioUrls(component);
}
}
const scrollRefs = new Map(audioUrls.map((url) => [url, createRef<HTMLTableRowElement>()]));
for (const { content: component } of parsedScript.components) {
if (component.type === ScriptComponentType.LABEL) {
scrollRefs.set(component.name, createRef<HTMLTableRowElement>());
}
}
const scrollToRow = (assetUrl: string) => {
let rowRef = scrollRefs.get(assetUrl);
if (rowRef !== undefined && rowRef.current !== null) {
rowRef.current.scrollIntoView({ behavior: "smooth" });
}
};
const showRawData = new Map<string, ScriptComponentWrapper[]>();
for (const component of parsedScript.components) {
const typeName = ScriptComponentType[component.content.type],
mapEntry = showRawData.get(typeName);
if (mapEntry !== undefined) {
mapEntry.push(component);
} else {
showRawData.set(typeName, [component]);
}
}
showRawData.set("ALL_COMPONENTS", parsedScript.components);
return (
<>
<h1>Script {scriptId}</h1>
<br />
<ScriptMainData
region={region}
scriptData={scriptData}
wordCount={countWord(
region,
parsedScript.components.map((c) => c.content)
)}
>
<ButtonGroup style={{ margin: "1em 0" }}>
{hasDialogueLines ? (
<VoiceLinePlayer
audioAssetUrls={audioUrls}
delay={new Array(audioUrls.length).fill(0).fill(1, 1)}
title="voice lines"
showTitle
handleNavigateAssetUrl={scrollToRow}
/>
) : null}
<Button
variant={enableScene ? "success" : "secondary"}
onClick={() => setEnableScene(!enableScene)}
>
Scene {enableScene ? "Enabled" : "Disabled"}
</Button>
<Button
variant={showScriptLine ? "success" : "secondary"}
onClick={() => Manager.setShowScriptLine(!showScriptLine)}
>
Line number {showScriptLine ? "shown" : "hidden"}
</Button>
<RawDataViewer text="Parsed Script" data={fromEntries(showRawData)} block={false} />
</ButtonGroup>
<ShowScriptLineContext.Provider value={showScriptLine}>
<ScriptTable region={region} script={parsedScript} showScene={enableScene} refs={scrollRefs} />
</ShowScriptLineContext.Provider>
</ScriptMainData>
</>
);
}
Example #13
Source File: ServantVoiceLines.tsx From apps with MIT License | 4 votes |
VoiceLinesTable = ({
region,
voice,
mergedDownloadNamePrefix,
servants,
costumes,
}: {
region: Region;
voice: Profile.VoiceGroup;
mergedDownloadNamePrefix: string;
servants: Map<number, Servant.ServantBasic>;
costumes?: {
[key: string]: Profile.CostumeDetail;
};
}) => {
const voiceLines = voice.voiceLines.sort((a, b) => (b.priority || 0) - (a.priority || 0));
const voiceLineNames: string[] = [];
const voiceNameCount: Record<string, number> = {};
for (const line of voiceLines) {
line.conds = line.conds.filter(
(cond) => !(cond.condType === Profile.VoiceCondType.EVENT_END && cond.value === 0)
);
let lineName = line.overwriteName || line.name || "";
if (lineName in voiceNameCount) {
voiceNameCount[lineName]++;
} else {
voiceNameCount[lineName] = 1;
}
voiceLineNames.push(lineName.replace("{0}", voiceNameCount[lineName].toString()));
}
return (
<Table bordered className="mb-0">
<tbody>
{voiceLines.map((line, index) => (
<tr key={`line_${index}`}>
<td style={{ verticalAlign: "middle" }}>
<b className="newline">{voiceLineNames[index]}</b>
<br />
<div className="newline">
{voiceTextField(region, voice.type) ? (
line.text.map((line, i) => (
<VoiceSubtitleFormat key={i} region={region} inputString={line} />
))
) : (
<VoiceSubtitleFormat region={region} inputString={line.subtitle} />
)}
</div>
{line.conds.length || line.playConds.length || line.summonScript ? (
<>
<Alert variant="info" style={{ marginBottom: 0, marginTop: "1em" }}>
{line.summonScript === undefined ? null : (
<>
Summoning Script:{" "}
<ScriptDescriptor
region={region}
scriptId={line.summonScript.scriptId}
scriptType=""
/>
</>
)}
{line.conds.length > 1 && (
<>
<b>Unlock Requirements (all of the following):</b>
<br />
<ul style={{ marginBottom: 0 }}>
{line.conds.map((cond, index) => (
<li key={index}>
<VoiceCondTypeDescriptor
region={region}
servants={servants}
costumes={costumes}
cond={cond}
/>
</li>
))}
</ul>
</>
)}
{line.conds.length === 1 && (
<>
<b>Unlock Requirement:</b>
<br />
<VoiceCondTypeDescriptor
region={region}
servants={servants}
costumes={costumes}
cond={line.conds[0]}
/>
<br />
</>
)}
<VoicePlayCondDescriptor
region={region}
playConds={line.playConds}
servants={servants}
/>
</Alert>
</>
) : (
""
)}
</td>
<td style={{ verticalAlign: "middle", width: "1px" }}>
<ButtonGroup>
<VoiceLinePlayer
audioAssetUrls={line.audioAssets}
delay={line.delay}
title={voiceLineNames[index]}
/>
<Dropdown as={ButtonGroup}>
<Dropdown.Toggle variant={"info"} title={`Download ${voiceLineNames[index]}`}>
<FontAwesomeIcon icon={faFileAudio} />
</Dropdown.Toggle>
<Dropdown.Menu title={`Download ${voiceLineNames[index]}`}>
<Dropdown.Item
title={`Download ${voiceLineNames[index]} merged file`}
onClick={() => {
const fileName = `${mergedDownloadNamePrefix} - ${voiceLineNames[index]}`;
mergeVoiceLine(line.audioAssets, line.delay, fileName);
}}
>
Merged
</Dropdown.Item>
{line.audioAssets.map((asset, i) => (
<Dropdown.Item
key={i}
href={asset}
target="_blank"
title={`Download ${voiceLineNames[index]} part ${i + 1}`}
>
Part {i + 1}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</ButtonGroup>
</td>
</tr>
))}
</tbody>
</Table>
);
}
Example #14
Source File: ServantsPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
const servants = this.servants(),
hasPaginator = servants.length > this.state.perPage,
results = servants.slice(this.state.perPage * this.state.page, this.state.perPage * (this.state.page + 1));
return (
<div id="servants" className="listing-page">
<Row>
<Col md={12} lg="auto" id="class-name">
{normalClasses.map((className) => {
const active = this.isClassFilterActive(className);
return (
<span
key={className}
className={"filter"}
style={{ opacity: active ? 1 : 0.5 }}
onClick={(ev: MouseEvent) => {
this.toggleClassFilter(className);
}}
>
<ClassIcon height={37} rarity={active ? 5 : 3} className={className} />
</span>
);
})}
<div className={"d-block d-lg-none"} style={{ flexBasis: "100%", height: 0 }}></div>
{extraClasses.map((className) => {
const active = this.isClassFilterActive(className);
return (
<span
key={className}
className={"filter"}
style={{ opacity: active ? 1 : 0.5 }}
onClick={(ev: MouseEvent) => {
this.toggleClassFilter(className);
}}
>
<ClassIcon height={37} rarity={active ? 5 : 3} className={className} />
</span>
);
})}
</Col>
<Col sm={12} lg={3} id="servant-search">
<Form>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({ search: ev.target.value });
}}
/>
</Form>
</Col>
</Row>
<Row>
<Col sm={12} md={6} lg={5} id="servant-rarity">
<ButtonGroup>
{[...new Set(this.state.servants.map((s) => s.rarity))]
// deduplicate star counts
.sort((a, b) => a - b)
// sort
.map((rarity) => (
<Button
variant={
this.state.activeRarityFilters.includes(rarity) ? "success" : "outline-dark"
}
key={rarity}
onClick={(ev: MouseEvent) => this.toggleRarityFilter(rarity)}
>
{rarity} ★
</Button>
))}
</ButtonGroup>
</Col>
<Col sm={12} md={6} lg={7}>
{this.paginator(servants.length)}
</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center text-nowrap">
<Button
variant=""
className="py-0 px-2 border-0 align-bottom"
onClick={() => {
this.setState({
sortKey: this.state.sortKey === "collectionNo" ? "id" : "collectionNo",
});
}}
>
{this.state.sortKey === "collectionNo" ? (
<FontAwesomeIcon icon={faHashtag} title="Collection No" />
) : (
<FontAwesomeIcon icon={faKey} title="Servant ID" />
)}
</Button>
<Button
variant=""
className="py-0 px-2 border-0 align-bottom"
onClick={() => {
this.setState({
sortDirection:
this.state.sortDirection === "ascending" ? "descending" : "ascending",
});
}}
>
{this.state.sortDirection === "ascending" ? (
<FontAwesomeIcon icon={faArrowDown19} title="Ascending" />
) : (
<FontAwesomeIcon icon={faArrowDown91} title="Descending" />
)}
</Button>
</th>
<th className="col-center">Class</th>
<th className="col-center">Thumbnail</th>
<th>Name</th>
<th className="rarity-col">Rarity</th>
</tr>
</thead>
<tbody>
{results.map((servant) => {
const route = `/${this.props.region}/servant/${servant.collectionNo}`;
return (
<tr key={servant.id}>
<td className="col-center">
<Link to={route}>
{servant.collectionNo} (
<span className="listing-svtId" lang="en-US">
{servant.id}
</span>
)
</Link>
</td>
<td className="col-center">
<ClassIcon className={servant.className} rarity={servant.rarity} height={50} />
</td>
<td className="col-center">
<Link to={route}>
<img
src={servant.face}
alt={`${servant.name} face icon`}
width={50}
height={50}
/>
</Link>
</td>
<td style={{ whiteSpace: Manager.showingJapaneseText() ? "nowrap" : "normal" }}>
<Link to={route}>{servant.name}</Link>
</td>
<td className="rarity-col">
<RarityDescriptor rarity={servant.rarity} />
</td>
</tr>
);
})}
</tbody>
</Table>
{hasPaginator ? this.paginator(servants.length) : undefined}
</div>
);
}
Example #15
Source File: WarsPage.tsx From apps with MIT License | 4 votes |
render() {
if (this.state.error) return <ErrorStatus error={this.state.error} />;
if (this.state.loading) return <Loading />;
const currentSortingOrder = this.state.sort;
const wars = this.wars().sort((w1, w2) => (currentSortingOrder ? -1 : 1) * (w1.id - w2.id)),
results = wars.slice(this.state.perPage * this.state.page, this.state.perPage * (this.state.page + 1));
const pageNavigator = this.paginator(wars.length);
return (
<div id="wars" className="listing-page">
<Row>
<Col md={12} lg={4} id="item-type">
<ButtonGroup>
{[WarType.MAIN, WarType.CHALDEA_GATE, WarType.OTHER].map((warType) => {
return (
<Button
variant={
this.state.activeWarTypeFilters.includes(warType)
? "success"
: "outline-dark"
}
key={warType}
onClick={(_) => {
this.toggleWarTypeFilter(warType);
this.setState({ page: 0 });
}}
>
{warType.toString()}
</Button>
);
})}
</ButtonGroup>
</Col>
<Col md={12} lg={3} id="item-search">
<Form inline>
<Form.Control
placeholder={"Search"}
value={this.state.search ?? ""}
onChange={(ev: ChangeEvent) => {
this.setState({
search: ev.target.value,
page: 0,
});
}}
/>
</Form>
</Col>
</Row>
<Row>
<Col sm={12}>{pageNavigator}</Col>
</Row>
<hr />
<Table striped bordered hover responsive>
<thead>
<tr>
<th className="col-center">
<Button
variant=""
style={{ outline: "none" }}
onClick={() =>
this.setState({
sort: currentSortingOrder ? SortingOrder.ASC : SortingOrder.DESC,
})
}
>
{currentSortingOrder ? (
<FontAwesomeIcon icon={faSortNumericDownAlt} />
) : (
<FontAwesomeIcon icon={faSortNumericDown} />
)}
</Button>
</th>
<th>War Name</th>
<th>Event</th>
</tr>
</thead>
<tbody>
{results.map((war) => {
const route = `/${this.props.region}/war/${war.id}`;
return (
<tr key={war.id}>
<td className="col-center">
<Link to={route}>{war.id}</Link>
</td>
<td>
<Link to={route}>{war.longName}</Link>
</td>
<td>
{war.eventId !== 0 ? (
<Link to={`/${this.props.region}/event/${war.eventId}`}>
{war.eventName !== "" ? war.eventName : `Event ${war.eventId}`}
</Link>
) : (
""
)}
</td>
</tr>
);
})}
</tbody>
</Table>
{pageNavigator}
</div>
);
}