semantic-ui-react#Image TypeScript Examples

The following examples show how to use semantic-ui-react#Image. 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: bigbook.tsx    From website with MIT License 6 votes vote down vote up
render() {
		const { crew, markdownRemark } = this.props;

		return (
			<React.Fragment>
				<Divider horizontal>
					<Header>
						<Link to={`/crew${markdownRemark.fields.slug}`}>
							{crew.name} <Rating defaultRating={crew.max_rarity} maxRating={5} icon='star' size='large' disabled />
						</Link>
					</Header>
				</Divider>
				<Grid columns={2}>
					<Grid.Row>
						<Grid.Column width={4}>
							{crew.series && <Image src={`/media/series/${crew.series}.png`} size='small' />}
							<Link to={`/crew${markdownRemark.fields.slug}`}>
								<Image src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlFullBody}`} size='small' />
							</Link>
						</Grid.Column>
						<Grid.Column width={12}>
							<CommonCrewData crew={crew} markdownRemark={markdownRemark} />

							<div dangerouslySetInnerHTML={{ __html: markdownRemark.html }} />
						</Grid.Column>
					</Grid.Row>
				</Grid>
			</React.Fragment>
		);
	}
Example #2
Source File: lazyimage.tsx    From website with MIT License 6 votes vote down vote up
render() {
        const { size } = this.props
        if (!this.state.show) {
            return (
                <Visibility as="span" fireOnMount onTopVisible={this.showImage}>
                    <Loader active inline="centered" size={size} />
                </Visibility>
            )
        }
        return <Image {...this.props} />
    }
Example #3
Source File: MemberList.tsx    From Riakuto-StartingReact-ja3.1 with Apache License 2.0 6 votes vote down vote up
MemberList: VFC<{ users: User[] }> = ({ users = [] }) => (
  <>
    <Card.Group>
      {users.map((user) => (
        <Card
          key={user.id}
          href={`https://github.com/${user.login}`}
          target="_blank"
        >
          <Card.Content>
            <Image floated="right" size="mini" src={user.avatarUrl} />
            <Card.Header>{user.login}</Card.Header>
            <Card.Meta>GitHub ID: {user.id}</Card.Meta>
          </Card.Content>
        </Card>
      ))}
    </Card.Group>
  </>
)
Example #4
Source File: MemberList.tsx    From Riakuto-StartingReact-ja3.1 with Apache License 2.0 6 votes vote down vote up
MemberList: VFC<{ users: User[] }> = ({ users = [] }) => (
  <>
    <Card.Group>
      {users.map((user) => (
        <Card
          key={user.id}
          href={`https://github.com/${user.login}`}
          target="_blank"
        >
          <Card.Content>
            <Image floated="right" size="mini" src={user.avatarUrl} />
            <Card.Header>{user.login}</Card.Header>
            <Card.Meta>GitHub ID: {user.id}</Card.Meta>
          </Card.Content>
        </Card>
      ))}
    </Card.Group>
  </>
)
Example #5
Source File: MemberList.tsx    From Riakuto-StartingReact-ja3.1 with Apache License 2.0 6 votes vote down vote up
MemberList: VFC<{ users: User[] }> = ({ users = [] }) => (
  <>
    <Card.Group>
      {users.map((user) => (
        <Card
          key={user.id}
          href={`https://github.com/${user.login}`}
          target="_blank"
          rel="noopener noreferrer"
        >
          <Card.Content>
            <Image floated="right" size="mini" src={user.avatarUrl} />
            <Card.Header>{user.login}</Card.Header>
            <Card.Meta>GitHub ID: {user.id}</Card.Meta>
          </Card.Content>
        </Card>
      ))}
    </Card.Group>
  </>
)
Example #6
Source File: crewpopup.tsx    From website with MIT License 6 votes vote down vote up
render() {
		const { crew, useBase } = this.props;
		//console.log(crew);
		if (!crew || !crew.symbol) {
			return <span>ERROR!</span>;
		}

		return (
			<Popup trigger={<span style={{ cursor: 'help', fontWeight: 'bolder' }}>{crew.name}</span>}>
				<Popup.Header>{crew.name}</Popup.Header>
				<Popup.Content>
					<Image size='small' src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlPortrait}`} />
					<Rating icon='star' defaultRating={crew.rarity} maxRating={crew.max_rarity} />
					<p>{formatCrewStats(crew, useBase ?? true)}</p>
				</Popup.Content>
			</Popup>
		);
	}
Example #7
Source File: crew_card.tsx    From website with MIT License 6 votes vote down vote up
function CrewCard({crew}) {
    return (
        <Card>
            <Card.Content>
                <Image
                    floated="left"
                    size="tiny"
                    src={crew.image}
                    bordered
                    style={{
                        borderColor: `${getRarityColor(crew.rarity)}`
                    }}
                />
                <Card.Header>{crew.name}</Card.Header>
                <Card.Meta>
                    <p>{getRarityStars(crew.rarity)}</p>
                    <p>
                        {crew.skills.map(skill => (
                            <Image key={skill.key} width={30} height={30} inline spaced src={skill.imageUrl} />
                        ))}
                    </p>
                </Card.Meta>
                <Card.Description>
                    {crew.traits.join(', ')}
                </Card.Description>
            </Card.Content>
        </Card>
    );
}
Example #8
Source File: threshold_rewards.tsx    From website with MIT License 6 votes vote down vote up
function ThresholdRewardsTab({eventData}) {
	const {threshold_rewards} = eventData;

	return (
		<Table celled striped compact='very'>
			<Table.Body>
				{threshold_rewards.map(row => (
					<Table.Row key={row.points}>
						<Table.Cell>{row.points}</Table.Cell>
						<Table.Cell>
							{row.rewards.map(reward => (
								<Label key={`reward_${reward.id}`} color="black">
									<Image
										src={getIconPath(reward.icon)}
										size="small"
										inline
										spaced="right"
										bordered
										style={{
											borderColor: getRarityColor(reward.rarity),
											maxWidth: '27px',
											maxHeight: '27px'
										}}
										alt={reward.full_name}
									/>
									{reward.full_name}
									{reward.quantity > 1 ? ` x ${reward.quantity}` : ''}
								</Label>
							))}
						</Table.Cell>
					</Table.Row>
				))}
			</Table.Body>
		</Table>
	);
}
Example #9
Source File: ranked_rewards.tsx    From website with MIT License 6 votes vote down vote up
function RankedRewardsTab({eventData}) {
	const {ranked_brackets} = eventData;

	return (
		<Table celled striped compact='very'>
			<Table.Body>
				{ranked_brackets.map(row => (
					<Table.Row key={`bracket_${row.first}_${row.last}`}>
						<Table.Cell width={2}>{getBracketLabel(row)}</Table.Cell>
						<Table.Cell width={14}>
							{row.rewards.map(reward => (
								<Label key={`reward_${reward.id}`} color="black">
									<Image
										src={getIconPath(reward.icon)}
										size="small"
										inline
										spaced="right"
										bordered
										style={{
											borderColor: getRarityColor(reward.rarity ?? 0),
											maxWidth: '27px',
											maxHeight: '27px'
										}}
										alt={reward.full_name}
									/>
									{reward.full_name}
									{reward.quantity > 1 ? ` x ${reward.quantity}` : ''}
								</Label>
							))}
						</Table.Cell>
					</Table.Row>
				))}
			</Table.Body>
		</Table>
	);}
Example #10
Source File: event_info_modal.tsx    From website with MIT License 5 votes vote down vote up
function EventInfoModal({instanceId, image, hasDetails, leaderboard}: EventInfoModalProps) {
	const [eventData, setEventData] = React.useState(null);

	React.useEffect(() => {
		async function fetchEventData() {
			if (hasDetails) {
				const fetchResp = await fetch(`/structured/events/${instanceId}.json`);
				const data = await fetchResp.json();
				setEventData(data);
			}
		}

		fetchEventData();
	}, []);

	const eventInfoPanes = [
		{
			menuItem: 'Event Information',
			render: () => (
				<Tab.Pane attached={false}>
					<EventInformationTab eventData={eventData} />
				</Tab.Pane>
			),
		},
		{
			menuItem: 'Threshold Rewards',
			render: () => (
				<Tab.Pane attached={false}>
					<ThresholdRewardsTab eventData={eventData} />
				</Tab.Pane>
			),
		},
		{
			menuItem: 'Ranked Rewards',
			render: () => (
				<Tab.Pane attached={false}>
					<RankedRewardsTab eventData={eventData} />
				</Tab.Pane>
			),
		},
	];

	const leaderboardPane = [
		{
			menuItem: 'Leaderboard',
			render: () => (
				<Tab.Pane attached={false}>
					<LeaderboardTab leaderboard={leaderboard} />
				</Tab.Pane>
			),
		},
	];

	let panes;
	if (hasDetails && eventData) {
		panes = eventInfoPanes.concat(leaderboardPane);
	} else {
		panes = leaderboardPane;
	}

	return (
		<Container style={{ padding: '1em' }}>
			<Image
				src={`${process.env.GATSBY_ASSETS_URL}${image}`}
				fluid
			/>
			<Tab
				style={{marginTop: '1em'}}
				menu={{secondary: true, pointing: true}}
				panes={panes}
				renderActiveOnly
			/>
		</Container>
	);
}
Example #11
Source File: voyagecalculator.tsx    From website with MIT License 5 votes vote down vote up
VoyageResultPane = (props: VoyageResultPaneProps) => {
	const { result, requests, requestId, calcState, abortCalculation } = props;

	const request = requests.find(r => r.id == requestId);
	if (!request) return (<></>);

	if (!result) {
		return (
			<Tab.Pane>
				<div style={{ textAlign: 'center' }}>
					<Image centered src='/media/voyage-wait-icon.gif' />
					<Button onClick={() => abortCalculation(request.id)}>Abort</Button>
				</div>
			</Tab.Pane>
		);
	}

	// resultToVoyageData
	let data = {...request.voyageConfig};
	if (result.entries) {
		result.entries.forEach((entry, idx) => {
			let acrew = request.consideredCrew.find(c => c.symbol === entry.choice.symbol);
			data.crew_slots[entry.slotId].crew = acrew;
		});
	}
	data.skill_aggregates = result.aggregates;
	data.max_hp = result.startAM;
	data.state = 'pending';

	const renderCalculatorMessage = () => {
		if (calcState != CalculatorState.Done) {
			return (
				<>
					<Image inline size='mini' src='/media/voyage-wait-icon.gif' />
					Calculation in progress. Please wait...{` `}
					<Button size='mini' onClick={() => abortCalculation(request.id)}>Abort</Button>
				</>
			);
		}
		let inputs = Object.entries(request.calcOptions).map(entry => entry[0]+': '+entry[1]);
		inputs.unshift('considered crew: '+request.consideredCrew.length);
		return (
			<>
				Calculated by <b>{request.calcName}</b> calculator ({inputs.join(', ')}){` `}
				in {((request.perf.end-request.perf.start)/1000).toFixed(2)} seconds!
				{result.postscript && (<div>{result.postscript}</div>)}
			</>
		);
	};

	return (
		<React.Fragment>
			{calcState == CalculatorState.Done && (
				<Message attached>
					Estimate: <b>{formatTime(result.estimate.refills[0].result)}</b>{` `}
					(expected range: {formatTime(result.estimate.refills[0].saferResult)} to{` `}
						{formatTime(result.estimate.refills[0].moonshotResult)})
				</Message>
			)}
			<Tab.Pane>
				<VoyageStats
					voyageData={data}
					estimate={result.estimate}
					ships={[request.bestShip]}
					showPanels={['crew']}
				/>
				<div style={{ marginTop: '1em' }}>
					{renderCalculatorMessage()}
				</div>
			</Tab.Pane>
		</React.Fragment>
	);
}
Example #12
Source File: bigbook2.tsx    From website with MIT License 5 votes vote down vote up
renderCrew(entry): JSX.Element {
		let markdownRemark = {
			frontmatter: {
				bigbook_tier: entry.bcrew.bigbook_tier,
				events: entry.bcrew.events,
				in_portal: entry.bcrew.in_portal
			}
		};

		return (
			<Grid.Column key={entry.crew.symbol}>
				<div style={{ textAlign: 'center', fontSize: '0.75em' }}>
					<Popup
						trigger={
							<Image
								src={`${process.env.GATSBY_ASSETS_URL}${entry.crew.imageUrlPortrait}`}
								size='small'
								style={{
									borderColor: CONFIG.RARITIES[entry.crew.max_rarity].color,
									borderWidth: '1px',
									borderRadius: '4px',
									borderStyle: 'solid'
								}}
							/>
						}
						wide='very'
						on='click'>
						<Header>
							<Link to={`/crew/${entry.crew.symbol}/`}>
								{entry.crew.name}{' '}
								<Rating rating={entry.crew.max_rarity} maxRating={entry.crew.max_rarity} icon='star' size='large' disabled />
							</Link>
						</Header>
						<CommonCrewData crew={entry.crew} markdownRemark={markdownRemark} />

						<div dangerouslySetInnerHTML={{ __html: marked(entry.bcrew.markdownContent) }} />
					</Popup>
					<Link to={`/crew/${entry.crew.symbol}/`}>{entry.crew.name}</Link>
				</div>
			</Grid.Column>
		);
	}
Example #13
Source File: voyagecalculator.tsx    From website with MIT License 5 votes vote down vote up
VoyageMain = (props: VoyageMainProps) => {
	const { myCrew, allShips } = props;

	const [voyageData, setVoyageData] = useStateWithStorage('tools/voyageData', undefined);
	const [voyageConfig, setVoyageConfig] = React.useState(undefined);
	const [voyageState, setVoyageState] = React.useState('input');	// input or from voyageData: started, recalled

	if (!voyageConfig) {
		if (voyageData) {
			// Voyage started, config will be full voyage data
			if (voyageData.voyage && voyageData.voyage.length > 0) {
				setVoyageConfig(voyageData.voyage[0]);
				setVoyageState(voyageData.voyage[0].state);
			}
			// Voyage awaiting input, config will be input parameters only
			else {
				setVoyageConfig(voyageData.voyage_descriptions[0]);
			}
		}
		else {
			// voyageData not found in cache, config will be blank voyage
			setVoyageConfig({ skills: {} });
		}
		return (<></>);
	}

	return (
		<React.Fragment>
			{voyageState == 'input' &&
				<Grid columns={2} stackable>
					<Grid.Column width={14}>
						<Card.Group>
							<Card>
								<Card.Content>
									<Image floated='right' src={`${process.env.GATSBY_ASSETS_URL}atlas/icon_${voyageConfig.skills.primary_skill}.png`} style={{ height: '2em' }} />
									<Card.Header>{CONFIG.SKILLS[voyageConfig.skills.primary_skill]}</Card.Header>
									<p>primary</p>
								</Card.Content>
							</Card>
							<Card>
								<Card.Content>
									<Image floated='right' src={`${process.env.GATSBY_ASSETS_URL}atlas/icon_${voyageConfig.skills.secondary_skill}.png`} style={{ height: '2em' }} />
									<Card.Header>{CONFIG.SKILLS[voyageConfig.skills.secondary_skill]}</Card.Header>
									<p>secondary</p>
								</Card.Content>
							</Card>
							<Card>
								<Card.Content>
									<Card.Header>{allTraits.ship_trait_names[voyageConfig.ship_trait]}</Card.Header>
									<p>ship trait</p>
								</Card.Content>
							</Card>
						</Card.Group>
					</Grid.Column>
					<Grid.Column width={2} textAlign='right'>
						<VoyageEditConfigModal voyageConfig={voyageConfig} updateConfig={updateConfig} />
					</Grid.Column>
				</Grid>
			}
			{voyageState != 'input' && (<VoyageExisting voyageConfig={voyageConfig} allShips={allShips} useCalc={() => setVoyageState('input')} />)}
			{voyageState == 'input' && (<VoyageInput voyageConfig={voyageConfig} myCrew={myCrew} allShips={allShips} useInVoyage={() => setVoyageState(voyageConfig.state)} />)}
		</React.Fragment>
	);

	function updateConfig(voyageConfig: any): void {
		setVoyageConfig({...voyageConfig});
		// Update stored voyageData with new voyageConfig
		setVoyageData({
			voyage_descriptions: [{...voyageConfig}],
			voyage: []
		});
		setVoyageState('input');
	}
}
Example #14
Source File: factions.tsx    From website with MIT License 5 votes vote down vote up
render() {
    const { factionInfo, shuttleBays } = this.props;
    const { successOdds } = this.state;
    const updateSuccessOdds = odds => this.setState({successOdds: odds});

    return (
      <>
        <p><span>Running shuttles at average odds of </span>
          <Dropdown text={`${successOdds}%`}>
            <Dropdown.Menu>
              {oddsValues.map(val => (<Dropdown.Item onClick={(e, { value }) => updateSuccessOdds(value)} text={`${val}%`} value={val} />))}
            </Dropdown.Menu>
          </Dropdown>
          <p>(Note: Shuttles cannot be run with a probability of success less than 14%. Shuttles need a probability of less than 60% to be tanked.)</p>
        </p>
        <Table>
          <Table.Header>
          <Table.Row>
            <Table.HeaderCell>Faction</Table.HeaderCell>
            <Table.HeaderCell>Reputation</Table.HeaderCell>
            <Table.HeaderCell>Shuttles needed</Table.HeaderCell>
            <Table.HeaderCell>Time needed</Table.HeaderCell>
          </Table.Row>
          </Table.Header>
          <Table.Body>
          {factionInfo.map((faction, index) => {
            let shuttlesNeededToMaxRep = this._shuttlesToHonouredStatus(faction.reputation);
            let hoursNeededToMaxRep = Math.ceil(shuttlesNeededToMaxRep/shuttleBays)*3;
            let shuttlesNeededToTank = Math.ceil(faction.completed_shuttle_adventures/this._expectedCSA(successOdds/100));
            let hoursNeededToTank = Math.ceil(shuttlesNeededToTank/shuttleBays)*3;

            return (
              <Table.Row key={index}>
                <Table.Cell><span><Image floated='left' size='mini' src={`${process.env.GATSBY_ASSETS_URL}icons_icon_faction_${factionImageLocations[index]}.png`} />{faction.name}</span></Table.Cell>
                <Table.Cell>{this._reputations(faction.reputation)}</Table.Cell>
                <Table.Cell>
                  {faction.reputation < 980 && <p>You need {shuttlesNeededToMaxRep} successful shuttle missions to achieve honored status.</p>}
                  {shuttlesNeededToTank > 0 && <p>To tank your shuttles you need to run {shuttlesNeededToTank} shuttles.</p>}
                  {shuttlesNeededToTank == 0 && <p>Already tanked</p>}
                </Table.Cell>
                <Table.Cell>
                  {faction.reputation < 980 && <p>{this._formatTime(hoursNeededToMaxRep)}</p>}
                  <p>{this._formatTime(hoursNeededToTank)}</p>
                </Table.Cell>
              </Table.Row>
            );
          })}
          </Table.Body>
        </Table>
        <p>Note: <a href="https://www.reddit.com/r/StarTrekTimelines/comments/aq5qzg/guide_tanked_shuttles_why_and_how/">Tanking</a> shuttles is the process of deliberately failing shuttles so that the difficulty and duration of shuttle missions go down.</p>
      </>
    );
  }
Example #15
Source File: crewchallenge.tsx    From website with MIT License 5 votes vote down vote up
GuessRow = (props: GuessRowProps) => {
	const { guess, solveState, guessCount } = props;

	const isSolution = guess.evaluation.crew === EvaluationState.Exact;
	const traits = guess.evaluation.traits ?? guess.traits;

	return (
		<Table.Row {...styleRow()}>
			<Table.Cell {...styleCell(guess.evaluation.variant)}>
				{isSolution && (
					<div>
						{solveState === SolveState.Winner && (<span style={{ whiteSpace: 'nowrap' }}>You got it in {guessCount} tr{guessCount !== 1 ? 'ies' : 'y'}!</span>)}
						{solveState === SolveState.Loser && (<span style={{ whiteSpace: 'nowrap' }}>You lose! The correct answer is:</span>)}
					</div>
				)}
				<div style={{ margin: '.5em 0', whiteSpace: 'nowrap' }}>
					<img width={48} height={48} src={`${process.env.GATSBY_ASSETS_URL}${guess.imageUrlPortrait}`} style={{ verticalAlign: 'middle' }} />
					<span style={{ padding: '0 .5em', fontSize: '1.25em' }}>{guess.name}</span>
				</div>
				{isSolution && guess.flavor && (
					<div>{guess.flavor}</div>
				)}
			</Table.Cell>
			<Table.Cell textAlign='center' {...styleCell(guess.evaluation.series)}>
				{guess.series && <Image src={`/media/series/${guess.series}.png`} size='small' style={{ margin: '0 auto' }} />}
			</Table.Cell>
			<Table.Cell {...styleCell(guess.evaluation.rarity)}>
				<Rating defaultRating={guess.rarity} maxRating={guess.rarity} icon='star' size='large' disabled />
			</Table.Cell>
			{guess.skills.map((skill, idx) => (
				<Table.Cell key={idx} textAlign='center' {...styleCell(guess.evaluation.skills ? guess.evaluation.skills[idx] : 0)}>
					{skill.skill !== '' && <img alt={idx} src={`${process.env.GATSBY_ASSETS_URL}atlas/icon_${skill.skill}.png`} style={{ height: '2em' }} />}
					{skill.skill === '' && <Icon name='minus' />}
				</Table.Cell>
			))}
			<Table.Cell textAlign='center'>
				{traits.map((trait, idx) => (
					<span key={idx} style={{ whiteSpace: 'nowrap' }}>
						{formatTrait(trait)}{idx < traits.length-1 ? ',' : ''}
					</span>
				)).reduce((prev, curr) => [prev, ' ', curr], [])}
			</Table.Cell>
		</Table.Row>
	);

	function styleRow(): any {
		if (!isSolution) return {};
		const attributes = {};
		attributes.style = solveState === SolveState.Winner ? STYLE_SOLVED : STYLE_LOSER;
		return attributes;
	}

	function styleCell(evaluationState: number): any {
		const attributes = {};
		if (evaluationState === EvaluationState.Exact)
			attributes.style = STYLE_SOLVED;
		else if (evaluationState === EvaluationState.Adjacent)
			attributes.style = STYLE_ADJACENT;
		return attributes;
	}

	function formatTrait(trait: string): string {
		const simpleName = (trait: string) => {
			return trait.replace(/[^A-Z]/gi, '').toLowerCase();
		};
		const properName = (trait: string) => {
			return trait.replace(/_/g, ' ').split(' ').map(word => word.substr(0, 1).toUpperCase()+word.substr(1)).join(' ');
		};
		// Display short_name instead of variant trait when appropriate
		if (guess.variants.includes(trait)) {
			if (simpleName(trait).indexOf(simpleName(guess.short_name)) >= 0
					|| simpleName(guess.short_name).indexOf(simpleName(trait)) >= 0)
				return guess.short_name;
		}
		return properName(trait);
	}
}
Example #16
Source File: Place.tsx    From communitymap-ui with Apache License 2.0 5 votes vote down vote up
Place: React.FC<ObjectItemComponentProps> = ({
  item,
  user,
  expanded,
  onClick,
  onVote,
  onComment,
}) => {
  const {
    title,
    description,
    logoURL,
    short_description,
    url,
    userVoted,
    votesCount: votes,
    comments,
  } = item;

  const commentsCount = comments?.length || 0;

  const sortedComments = useMemo(() => {
    if (!comments) return comments;
    return comments.sort((l, r) => (l.created < r.created ? -1 : 1));
  }, [comments]);

  const icon = 'building outline';

  return (
    <div
      className={cx({ item: true, 'place-item': true, expanded })}
      onClick={onClick}
    >
      <div className="title">
        {logoURL ? <Image src={logoURL} /> : <Icon name={icon} />}
        {title}
      </div>

      {!!short_description && (
        <section className="short-description">{short_description}</section>
      )}
      {expanded && !!url && (
        <p className="external-url">
          <a href={normalizeUrl(url)} title={url}>
            <Icon name="external" /> {url}
          </a>
        </p>
      )}
      {expanded && description !== title && (
        <section className="description">{description}</section>
      )}
      {!!commentsCount && (
        <div className="replies-count">{commentsCount} comments</div>
      )}
      {expanded && (
        <section>
          <LikeWidget votes={votes} userVoted={userVoted} onVote={onVote} />
        </section>
      )}
      {expanded && !!commentsCount && (
        <section>
          <h4 className="pale-heading">Replies</h4>
          <CommentsList comments={sortedComments!} />
        </section>
      )}
      {expanded &&
        (!!user ? (
          <PostCommentWidget onComment={onComment} />
        ) : (
          <div style={{ textAlign: 'center' }}>
            You need to register or sign in to be able to post
          </div>
        ))}
    </div>
  );
}
Example #17
Source File: TopBar.tsx    From watchparty with MIT License 5 votes vote down vote up
render() {
    if (this.props.user) {
      return (
        <div
          style={{
            margin: '4px',
            width: '100px',
            alignItems: 'center',
            cursor: 'pointer',
          }}
        >
          <Image
            avatar
            src={this.state.userImage}
            onClick={() => this.setState({ isProfileOpen: true })}
          />
          {this.state.isProfileOpen && this.props.user && (
            <ProfileModal
              user={this.props.user}
              userImage={this.state.userImage}
              close={() => this.setState({ isProfileOpen: false })}
            />
          )}
        </div>
      );
    }
    return (
      <React.Fragment>
        {this.state.isLoginOpen && (
          <LoginModal
            closeLogin={() => this.setState({ isLoginOpen: false })}
          />
        )}
        <Popup
          basic
          content="Sign in to set your name and picture, subscribe, or launch VBrowsers"
          trigger={
            <Dropdown
              style={{ height: '36px' }}
              icon="sign in"
              labeled
              className="icon"
              button
              text="Sign in"
              fluid={this.props.fluid}
            >
              <Dropdown.Menu>
                <Dropdown.Item onClick={this.facebookSignIn}>
                  <Icon name="facebook" />
                  Facebook
                </Dropdown.Item>
                <Dropdown.Item onClick={this.googleSignIn}>
                  <Icon name="google" />
                  Google
                </Dropdown.Item>
                <Dropdown.Item
                  onClick={() => this.setState({ isLoginOpen: true })}
                >
                  <Icon name="mail" />
                  Email
                </Dropdown.Item>
              </Dropdown.Menu>
            </Dropdown>
          }
        />
      </React.Fragment>
    );
  }
Example #18
Source File: index.tsx    From frontegg-react with MIT License 5 votes vote down vote up
Select = (props: SelectProps) => {
  const [open, setOpen] = useState(false);
  const p = mapper(props);
  const { t } = useT();
  const { multiple, options, label, loading, getOptionLabel, renderOption } = p;
  const {
    noOptionsText,
    loadingText,
    onOpen,
    open: openProps,
    onClose,
    fullWidth,
    onBlur,
    value,
    onChange,
    options: propsOptions,
  } = props;

  const handleOnChange = useCallback(
    (e, data) => {
      onChange && onChange(e, data);
    },
    [onChange]
  );

  const optionsMessage = useMemo(
    () => (loading ? loadingText ?? `${t('common.loading')}...` : noOptionsText ?? t('common.empty-items')),
    [loading, loadingText, noOptionsText]
  );

  const renderLabel = useCallback((option, state) => {
    const { flag, image, text } = option;
    const content = renderOption ? (
      <>{renderOption({ label: option.text, value: option.value }, state)}</>
    ) : (
      <>
        {(Flag as any).create(flag)}
        {(Image as any).create(image)}
        {text}
      </>
    );
    return { content };
  }, []);

  const preparedValue = useMemo(() => {
    return Array.isArray(value) ? value?.map((v) => v.value) : value?.value;
  }, [value]);

  const onHandleChange = useCallback(
    (e, newValue) => {
      const data = propsOptions?.filter((o) => newValue.includes(o.value)) || [];
      onChange?.(e, data);
    },
    [propsOptions]
  );

  return (
    <Dropdown
      {...p}
      search
      selection
      value={preparedValue}
      fluid={fullWidth ?? true}
      open={openProps ?? open}
      onBlur={(e, data) => onBlur?.({ ...e, target: { ...e.target, name: data.name } } as any)}
      options={options}
      loading={loading}
      onOpen={() => (onOpen ? onOpen() : setOpen(true))}
      onClose={() => (onClose ? onClose() : setOpen(false))}
      multiple={multiple ?? false}
      placeholder={value ? '' : label}
      onChange={(e, data) => onHandleChange(e, data.value)}
      renderLabel={(option, _index, state) => renderLabel(option, state)}
      noResultsMessage={optionsMessage}
      getoptionlabel={getOptionLabel}
    />
  );
}
Example #19
Source File: event_info.tsx    From website with MIT License 4 votes vote down vote up
render() {
		const { event_instace, errorMessage, event_data } = this.state;

		if (event_instace === undefined || event_data === undefined || errorMessage !== undefined) {
			return (
				<Layout title='Event information'>
					<Header as='h4'>Event information</Header>
					{errorMessage && (
						<Message negative>
							<Message.Header>Unable to load event information</Message.Header>
							<pre>{errorMessage.toString()}</pre>
						</Message>
					)}
					{!errorMessage && (
						<div>
							<Icon loading name='spinner' /> Loading...
						</div>
					)}
				</Layout>
			);
		}

		return (
			<Layout title={event_data.ev_inst.event_name}>
				<Header as='h3'>{event_data.ev_inst.event_name}</Header>
				<Image size='large' src={`${process.env.GATSBY_ASSETS_URL}${event_data.ev_inst.image}`} />

				{this.renderEventDetails()}

				{this.renderEventLog()}

				<Header as='h4'>Leaderboard</Header>
				<Table celled selectable striped collapsing unstackable compact='very'>
					<Table.Header>
						<Table.Row>
							<Table.HeaderCell width={3}>Name</Table.HeaderCell>
							<Table.HeaderCell width={1}>Rank</Table.HeaderCell>
							<Table.HeaderCell width={1}>Score</Table.HeaderCell>
							<Table.HeaderCell width={2}>Fleet</Table.HeaderCell>
						</Table.Row>
					</Table.Header>
					<Table.Body>
						{event_data.ev_lead.leaderboard.map((member, idx) => (
							<Table.Row key={idx}>
								<Table.Cell>
									<div
										style={{
											display: 'grid',
											gridTemplateColumns: '60px auto',
											gridTemplateAreas: `'icon stats' 'icon description'`,
											gridGap: '1px'
										}}>
										<div style={{ gridArea: 'icon' }}>
											<img
												width={48}
												src={`${process.env.GATSBY_ASSETS_URL}${member.avatar ? member.avatar.file.substr(1).replace(/\//g, '_') + '.png' : 'crew_portraits_cm_empty_sm.png'
													}`}
											/>
										</div>
										<div style={{ gridArea: 'stats' }}>
											<span style={{ fontWeight: 'bolder', fontSize: '1.25em' }}>
												{member.last_update ? (
													<Link to={`/profile?dbid=${member.dbid}`}>{member.display_name}</Link>
												) : (
														<span>{member.display_name}</span>
													)}
											</span>
										</div>
										<div style={{ gridArea: 'description' }}>
											Level {member.level}
											{member.last_update && (
												<Label size='tiny'>Last profile upload: {new Date(Date.parse(member.last_update)).toLocaleDateString()}</Label>
											)}
										</div>
									</div>
								</Table.Cell>
								<Table.Cell>{member.rank}</Table.Cell>
								<Table.Cell>{member.score}</Table.Cell>
								<Table.Cell>
									{member.fleetname ? <Link to={`/fleet_info?fleetid=${member.fleetid}`}>
										<b>{member.fleetname}</b>
									</Link> : <span>-</span>}
								</Table.Cell>
							</Table.Row>
						))}
					</Table.Body>
				</Table>

				{event_data.ev_flead &&
					<div>
						<Message>
							<Message.Header>TODO: Fleet Leaderboard is experimental</Message.Header>
							This data may be incomplete or out of date!
						</Message>

						<Header as='h4'>Fleet leaderboard</Header>
						<Table celled selectable striped collapsing unstackable compact='very'>
							<Table.Header>
								<Table.Row>
									<Table.HeaderCell width={3}>Name</Table.HeaderCell>
									<Table.HeaderCell width={1}>Rank</Table.HeaderCell>
								</Table.Row>
							</Table.Header>
							<Table.Body>
								{event_data.ev_flead.fleet_ranks.map((fleet, idx) => (
									<Table.Row key={idx}>
										<Table.Cell>{fleet.fleet_rank}</Table.Cell>
										<Table.Cell>
											<Link to={`/fleet_info?fleetid=${fleet.id}`}>
												<b>{fleet.name}</b>
											</Link>
										</Table.Cell>
									</Table.Row>
								))}
							</Table.Body>
						</Table>
					</div>}
			</Layout>
		);
	}
Example #20
Source File: crewpage.tsx    From website with MIT License 4 votes vote down vote up
render() {
		const { location } = this.props;
		const { markdownRemark, crewJson, site: { siteMetadata } } = this.props.data;
		if (crewJson.edges.length === 0) {
			return <span>Crew not found!</span>;
		}

		const { comments } = this.state;

		let hasBigBookEntry = markdownRemark && markdownRemark.frontmatter && markdownRemark.frontmatter.published;

		const userName = this._getCurrentUsername();

		const crew = crewJson.edges[0].node;
		return (
			<Layout narrowLayout={true}>
				<Helmet titleTemplate={siteMetadata.titleTemplate} defaultTitle={siteMetadata.defaultTitle}>
					<title>{crew.name}</title>
					<meta property='og:type' content='website' />
					<meta property='og:title' content={`${crew.name} - ${siteMetadata.defaultTitle}`} />
					<meta property='og:site_name' content='DataCore' />
					<meta property='og:image' content={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlPortrait}`} />
					<meta property='og:description' content={markdownRemark.rawMarkdownBody.trim() || siteMetadata.defaultDescription} />
					<meta property='og:url' content={`${siteMetadata.baseUrl}${location.pathname}`} />
				</Helmet>
				<CrewFullEquipTree
					visible={this.state.modalVisible}
					items={this.state.items}
					crew={crew}
					onClosed={() => this.setState({ modalVisible: false })}
				/>
				<Grid columns={2}>
					<Grid.Row stretched>
						<Grid.Column width={16}>
							<Header>
								{crew.name} <Rating defaultRating={crew.max_rarity} maxRating={crew.max_rarity} icon='star' size='large' disabled />
							</Header>
						</Grid.Column>
					</Grid.Row>
					<Grid.Row>
						<Grid.Column width={4}>
							{crew.series && <Image src={`/media/series/${crew.series}.png`} size='small' />}
							<Image src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlFullBody}`} size='small' />
						</Grid.Column>
						<Grid.Column width={12}>
							<CommonCrewData crew={crew} markdownRemark={markdownRemark} />

							<div style={{ margin: '1em 0', textAlign: 'right' }}>
								<Button icon='add user' color='green' content='Preview in your roster' onClick={() => { this._addProspect(crew); }} />
							</div>

							{this.state.items.length > 0 ? (
								<React.Fragment>
									{this.renderEquipment(crew)}
									{this.renderEquipmentDetails(crew)}
									<Button
										onClick={() => this.setState({ modalVisible: true })}
										style={{ marginTop: '1em' }}
										content='Full equipment tree'
										icon='right arrow'
										labelPosition='right'
									/>
								</React.Fragment>
							) : (
									<div className='ui medium centered text active inline loader'>Loading items...</div>
								)}

							<Segment>
								<Header as='h4'>{crew.action.name}</Header>
								<p>
									Boosts {CONFIG.CREW_SHIP_BATTLE_BONUS_TYPE[crew.action.bonus_type]} by {crew.action.bonus_amount}
								</p>
								<p>
									Initialize: {crew.action.initial_cooldown}s, Cooldown: {crew.action.cooldown}s, Duration: {crew.action.duration}s
									</p>
								{crew.action.limit && <p>Uses Per Battle: {crew.action.limit}</p>}

								{crew.action.ability && (
									<p>
										Bonus ability:
										{CONFIG.CREW_SHIP_BATTLE_ABILITY_TYPE[crew.action.ability.type].replace('%VAL%', crew.action.ability.amount)}{' '}
										{crew.action.ability.condition > 0 && (
											<span>Trigger: {CONFIG.CREW_SHIP_BATTLE_TRIGGER[crew.action.ability.condition]}</span>
										)}
									</p>
								)}

								<p>
									<b>Accuracy:</b> +{crew.ship_battle.accuracy} <b>Crit Bonus:</b> +{crew.ship_battle.crit_bonus}{' '}
									{crew.ship_battle.crit_chance && (
										<span>
											<b>Crit Rating:</b> +{crew.ship_battle.crit_chance}{' '}
										</span>
									)}
									<b>Evasion:</b> +{crew.ship_battle.evasion}
								</p>
								{crew.action.penalty && (
									<p>
										Decrease {CONFIG.CREW_SHIP_BATTLE_BONUS_TYPE[crew.action.penalty.type]} by {crew.action.penalty.amount}
									</p>
								)}

								{this.renderChargePhases(crew.action, crew.action.charge_phases)}
							</Segment>
						</Grid.Column>
					</Grid.Row>
				</Grid>
				<Divider horizontal hidden />
				{hasBigBookEntry && (
					<React.Fragment>
						<div dangerouslySetInnerHTML={{ __html: markdownRemark.html }} />
						<div style={{ marginTop: '1em', textAlign: 'right' }}>
							-- <a href={`https://www.bigbook.app/crew/${crew.symbol}`}>The Big Book of Behold Advice</a>
						</div>
					</React.Fragment>
				)}
				{/*userName && (
						<div>
							<br />
							<p>Hello, {userName}. You can edit your comment below:</p>
							<SimpleMDE
								value={this.state.commentMarkdown}
								onChange={value => this._handleMarkDownChange(value)}
								options={{ hideIcons: ['fullscreen', 'guide', 'image', 'side-by-side'] }}
							/>
							<Button onClick={() => this._saveComment(crew.symbol, window.localStorage.getItem('token'))} content='Save comment' />
						</div>
					)}
					{comments && (
						<Comment.Group>
							<Header as='h3' dividing>
								Comments
							</Header>

							{comments.map(comment => (
								<Comment key={comment.id}>
									<Comment.Avatar src={comment.user.avatar || `${process.env.GATSBY_ASSETS_URL}crew_portraits_cm_empty_sm.png`} />
									<Comment.Content>
										<Comment.Author>{comment.user.loginUserName}</Comment.Author>
										<Comment.Metadata>
											<div>{comment.lastUpdate}</div>
										</Comment.Metadata>
										<Comment.Text>
											<div dangerouslySetInnerHTML={{ __html: marked(comment.markdown) }} />
										</Comment.Text>
									</Comment.Content>
								</Comment>
							))}
						</Comment.Group>
							)*/}
				<Divider horizontal hidden style={{ marginTop: '4em' }} />
				<ExtraCrewDetails
					crew_archetype_id={crew.archetype_id}
					max_rarity={crew.max_rarity}
					base_skills={crew.base_skills}
					traits={crew.traits} traits_hidden={crew.traits_hidden}
					unique_polestar_combos={crew.unique_polestar_combos}
				/>
			</Layout>
		);
	}
Example #21
Source File: fleet_info.tsx    From website with MIT License 4 votes vote down vote up
render() {
		const { fleet_id, errorMessage, fleet_data, factions, events } = this.state;

		if (fleet_id === undefined || fleet_data === undefined || errorMessage !== undefined) {
			return (
				<Layout title='Fleet information'>
					<Header as="h4">Fleet information</Header>
					{errorMessage && (
						<Message negative>
							<Message.Header>Unable to load fleet profile</Message.Header>
							<pre>{errorMessage.toString()}</pre>
						</Message>
					)}
					{!errorMessage && (
						<div>
							<Icon loading name="spinner" /> Loading...
						</div>
					)}
					<p>
						Are you looking to share your player profile? Go to the <Link to={`/playertools`}>Player Tools page</Link> to
							upload your player.json and access other useful player tools.
						</p>
				</Layout>
			);
		}

		let imageUrl = 'icons_icon_faction_starfleet.png';
		if (factions && factions[fleet_data.nicon_index]) {
			imageUrl = factions[fleet_data.nicon_index].icon;
		}

		let event1;
		let event2;
		let event3;

		if (events[0].event_name === fleet_data.leaderboard[0].event_name) {
			event1 = events[0];
			event2 = events[1];
			event3 = events[2];
		} else {
			event1 = events.find(ev => ev.event_name === fleet_data.leaderboard[0].event_name);
			event2 = events.find(ev => ev.event_name === fleet_data.leaderboard[1].event_name);
			event3 = events.find(ev => ev.event_name === fleet_data.leaderboard[2].event_name);
		}

		return (
			<Layout title={fleet_data.name}>
				<Item.Group>
					<Item>
						<Item.Image size="tiny" src={`${process.env.GATSBY_ASSETS_URL}${imageUrl}`} />

						<Item.Content>
							<Item.Header>{fleet_data.name}</Item.Header>
							<Item.Meta>
								<Label>Starbase level: {fleet_data.nstarbase_level}</Label>
								<Label>
									Size: {fleet_data.cursize} / {fleet_data.maxsize}
								</Label>
								<Label>Created: {new Date(fleet_data.created).toLocaleDateString()}</Label>
								<Label>
									Enrollment {fleet_data.enrollment} (min level: {fleet_data.nmin_level})
									</Label>
							</Item.Meta>
						</Item.Content>
					</Item>
				</Item.Group>

				{event1 && <table>
					<tbody>
						<tr>
							<th>
								{' '}
								<Link to={`/event_info?instance_id=${event1.instance_id}`}>
									{fleet_data.leaderboard[0].event_name}
								</Link>
							</th>
							<th>
								{' '}
								<Link to={`/event_info?instance_id=${event2.instance_id}`}>
									{fleet_data.leaderboard[1].event_name}
								</Link>
							</th>
							<th>
								{' '}
								<Link to={`/event_info?instance_id=${event3.instance_id}`}>
									{fleet_data.leaderboard[2].event_name}
								</Link>
							</th>
						</tr>
						<tr>
							<td><Image size="medium" src={`${process.env.GATSBY_ASSETS_URL}${event1.image}`} /></td>
							<td><Image size="medium" src={`${process.env.GATSBY_ASSETS_URL}${event2.image}`} /></td>
							<td><Image size="medium" src={`${process.env.GATSBY_ASSETS_URL}${event3.image}`} /></td>
						</tr>
						<tr>
							<td align="center">Fleet rank: {fleet_data.leaderboard[0].fleet_rank}</td>
							<td align="center">Fleet rank: {fleet_data.leaderboard[1].fleet_rank}</td>
							<td align="center">Fleet rank: {fleet_data.leaderboard[2].fleet_rank}</td>
						</tr>
					</tbody>
				</table>}

				<Header as="h4">Members</Header>

				<Table celled selectable striped collapsing unstackable compact="very">
					<Table.Header>
						<Table.Row>
							<Table.HeaderCell width={3}>Name</Table.HeaderCell>
							<Table.HeaderCell width={1}>Rank</Table.HeaderCell>
							<Table.HeaderCell width={1}>Profile</Table.HeaderCell>
						</Table.Row>
					</Table.Header>
					<Table.Body>
						{fleet_data.members.map((member, idx) => (
							<Table.Row key={idx}>
								<Table.Cell>
									<div
										style={{
											display: 'grid',
											gridTemplateColumns: '60px auto',
											gridTemplateAreas: `'icon stats' 'icon description'`,
											gridGap: '1px'
										}}
									>
										<div style={{ gridArea: 'icon' }}>
											<img
												width={48}
												src={`${process.env.GATSBY_ASSETS_URL}${member.crew_avatar || 'crew_portraits_cm_empty_sm.png'}`}
											/>
										</div>
										<div style={{ gridArea: 'stats' }}>
											<span style={{ fontWeight: 'bolder', fontSize: '1.25em' }}>
												{member.last_update ? (
													<Link to={`/profile?dbid=${member.dbid}`}>{member.display_name}</Link>
												) : (
														<span>{member.display_name}</span>
													)}
											</span>
										</div>
										<div style={{ gridArea: 'description' }}>
											{member.last_update && (
												<Label size="tiny">
													Last profile upload: {new Date(Date.parse(member.last_update)).toLocaleDateString()}
												</Label>
											)}
										</div>
									</div>
								</Table.Cell>
								<Table.Cell>{member.rank}</Table.Cell>
								<Table.Cell>
									{member.last_update
										? `Last profile upload: ${new Date(Date.parse(member.last_update)).toLocaleDateString()}`
										: 'Never'}
								</Table.Cell>
							</Table.Row>
						))}
					</Table.Body>
				</Table>
			</Layout>
		);
	}
Example #22
Source File: gauntlets.tsx    From website with MIT License 4 votes vote down vote up
render() {
		return (
			<StaticQuery
				query={graphql`
					query {
						allGauntletsJson {
							edges {
								node {
									gauntlet_id
									date
									jackpot_crew
									contest_data {
										featured_skill
										traits
									}
								}
							}
						}
						allCrewJson {
							edges {
								node {
									symbol
									name
									traits_named
									imageUrlPortrait
									max_rarity
									ranks {
										gauntletRank
									}
									base_skills {
										security_skill {
											core
											range_min
											range_max
										}
										command_skill {
											core
											range_min
											range_max
										}
										diplomacy_skill {
											core
											range_min
											range_max
										}
										science_skill {
											core
											range_min
											range_max
										}
										medicine_skill {
											core
											range_min
											range_max
										}
										engineering_skill {
											core
											range_min
											range_max
										}
									}
								}
							}
						}
					}
				`}
				render={data => (
					<Layout title='Gauntlets'>
						<Item.Group divided>
							{data.allGauntletsJson.edges.sort((a, b) => Date.parse(b.node.date) - Date.parse(a.node.date)).map(({ node }, index) => {
								const prettyDate = new Date(node.date).toDateString();
								const prettyTraits = node.contest_data.traits.map(t => trait_names[t]);
								const matchedCrew = data.allCrewJson.edges.filter(e => e.node.max_rarity > 3 && prettyTraits.filter(t => e.node.traits_named.includes(t)).length > 1).sort((a, b) => (prettyTraits.filter(t => b.node.traits_named.includes(t)).length - prettyTraits.filter(t => a.node.traits_named.includes(t)).length));
								return (
								<Item key={index}>
									<Item.Content>
										<Item.Header>
											{node.contest_data.traits.map(t => trait_names[t]).join("/")}/{SKILLS[node.contest_data.featured_skill]}
										</Item.Header>
										<Item.Meta style={{color: 'white'}}>{prettyDate}</Item.Meta>
										<Item.Description>
											<Grid stackable>
											{matchedCrew.map(({ node: crew }) => (
													<Grid.Column width={1} style={{textAlign: 'center'}}>
														<a href={`/crew/${crew.symbol}`}>
													<Image
													src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlPortrait}`}
													size='tiny'
													alt={crew.name}
													style={{
														borderColor: CONFIG.RARITIES[crew.max_rarity].color,
														borderWidth: '1px',
														borderRadius: '4px',
														borderStyle: 'solid',
														marginLeft: 'auto',
														marginRight: 'auto'
													}}
												/>
												</a>
												{prettyTraits.filter(t => crew.traits_named.includes(t)).length == 3 ? '65%' : '45%'}
												<br />
												{crew.base_skills[node.contest_data.featured_skill] ? <img style={{width: '1em'}} src={`${process.env.GATSBY_ASSETS_URL}atlas/icon_${node.contest_data.featured_skill}.png`} /> : ''}
												</Grid.Column>
											))}
											</Grid>
										</Item.Description>
									</Item.Content>
								</Item>
							)
								})}
						</Item.Group>
					</Layout>
				)}
			/>
		);
	}
Example #23
Source File: item_info.tsx    From website with MIT License 4 votes vote down vote up
render() {
		const { errorMessage, item_data, items } = this.state;

		if (item_data === undefined || errorMessage !== undefined) {
			return (
				<Layout title='Item information'>
					<Header as="h4">Item information</Header>
					{errorMessage && (
						<Message negative>
							<Message.Header>Unable to load item information</Message.Header>
							<pre>{errorMessage.toString()}</pre>
						</Message>
					)}
					{!errorMessage && (
						<div>
							<Icon loading name="spinner" /> Loading...
						</div>
					)}
				</Layout>
			);
		}

		console.log(item_data);

		let bonusText = [];
		if (item_data.item.bonuses) {
			for (let [key, value] of Object.entries(item_data.item.bonuses)) {
				let bonus = CONFIG.STATS_CONFIG[Number.parseInt(key)];
				if (bonus) {
					bonusText.push(`+${value} ${bonus.symbol}`);
				} else {
					// TODO: what kind of bonus is this?
				}
			}
		}

		// TODO: share this code with equipment.ts
		let demands = [];
		if (item_data.item.recipe) {
			for (let iter of item_data.item.recipe.list) {
				let recipeEquipment = items.find(item => item.symbol === iter.symbol);
				demands.push({
					count: iter.count,
					symbol: iter.symbol,
					equipment: recipeEquipment,
					factionOnly: iter.factionOnly
				});
			}
		}

		return (
			<Layout title={item_data.item.name}>
				<Message icon warning>
					<Icon name="exclamation triangle" />
					<Message.Content>
						<Message.Header>Work in progress!</Message.Header>
							This section is under development and not fully functional yet.
						</Message.Content>
				</Message>
				<Header as="h3">
					{item_data.item.name}{' '}
					<Rating icon='star' rating={item_data.item.rarity} maxRating={item_data.item.rarity} size="large" disabled />
				</Header>
				<Image size="small" src={`${process.env.GATSBY_ASSETS_URL}${item_data.item.imageUrl}`} />

				<br />

				{bonusText.length > 0 && (
					<div>
						<p>Bonuses: {bonusText.join(', ')}</p>
						<br />
					</div>
				)}

				{item_data.item.recipe && item_data.item.recipe.list && (
					<div>
						<Header as="h4">Craft it for {item_data.item.recipe.craftCost} chrons using this recipe:</Header>
						<Grid columns={3} padded>
							{demands.map((entry, idx) => (
								<Grid.Column key={idx}>
									<Popup
										trigger={
											<Header
												style={{ display: 'flex', cursor: 'zoom-in' }}
												icon={
													<ItemDisplay
														src={`${process.env.GATSBY_ASSETS_URL}${entry.equipment.imageUrl}`}
														size={48}
														maxRarity={entry.equipment.rarity}
														rarity={entry.equipment.rarity}
													/>
												}
												content={entry.equipment.name}
												subheader={`Need ${entry.count} ${entry.factionOnly ? ' (FACTION)' : ''}`}
											/>
										}
										header={
											<Link to={`/item_info?symbol=${entry.symbol}`}>
												{CONFIG.RARITIES[entry.equipment.rarity].name + ' ' + entry.equipment.name}
											</Link>
										}
										content={<ItemSources item_sources={entry.equipment.item_sources} />}
										on="click"
										wide
									/>
								</Grid.Column>
							))}
						</Grid>
					</div>
				)}

				{item_data.item.item_sources.length > 0 && (
					<div>
						<Header as="h4">Item sources</Header>
						<ItemSources item_sources={item_data.item.item_sources} />
						<br />
					</div>
				)}

				{item_data.crew_levels.length > 0 && (
					<div>
						<Header as="h4">Equippable by this crew:</Header>
						<Grid columns={3} padded>
							{item_data.crew_levels.map((entry, idx) => (
								<Grid.Column key={idx}>
									<Header
										style={{ display: 'flex' }}
										icon={
											<ItemDisplay
												src={`${process.env.GATSBY_ASSETS_URL}${entry.crew.imageUrlPortrait}`}
												size={60}
												maxRarity={entry.crew.max_rarity}
												rarity={entry.crew.max_rarity}
											/>
										}
										content={<Link to={`/crew/${entry.crew.symbol}/`}>{entry.crew.name}</Link>}
										subheader={`Level ${entry.level}`}
									/>
								</Grid.Column>
							))}
						</Grid>
					</div>
				)}

				{item_data.builds.length > 0 && (
					<div>
						<Header as="h4">Is used to build these</Header>
						<Grid columns={3} padded>
							{item_data.builds.map((entry, idx) => (
								<Grid.Column key={idx}>
									<Header
										style={{ display: 'flex', cursor: 'zoom-in' }}
										icon={
											<ItemDisplay
												src={`${process.env.GATSBY_ASSETS_URL}${entry.imageUrl}`}
												size={48}
												maxRarity={entry.rarity}
												rarity={entry.rarity}
											/>
										}
										content={
											<Link to={`/item_info?symbol=${entry.symbol}`}>
												{CONFIG.RARITIES[entry.rarity].name + ' ' + entry.name}
											</Link>
										}
									/>
								</Grid.Column>
							))}
						</Grid>
					</div>
				)}
			</Layout>
		);
	}
Example #24
Source File: voyagecalculator.tsx    From website with MIT License 4 votes vote down vote up
VoyageInput = (props: VoyageInputProps) => {
	const { voyageConfig, myCrew, allShips, useInVoyage } = props;

	const [bestShip, setBestShip] = React.useState(undefined);
	const [consideredCrew, setConsideredCrew] = React.useState([]);
	const [calculator, setCalculator] = React.useState(isMobile ? 'ussjohnjay' : 'iampicard');
	const [calcOptions, setCalcOptions] = React.useState({});
	const [telemetryOptOut, setTelemetryOptOut] = useStateWithStorage('telemetryOptOut', false, { rememberForever: true });
	const [requests, setRequests] = React.useState([]);
	const [results, setResults] = React.useState([]);

	React.useEffect(() => {
		// Note that allShips is missing the default ship for some reason (1* Constellation Class)
		//	This WILL break voyagecalculator if that's the only ship a player owns
		const consideredShips = [];
		allShips.filter(ship => ship.owned).forEach(ship => {
			const traited = ship.traits.find(trait => trait === voyageConfig.ship_trait);
			let entry = {
				ship: ship,
				score: ship.antimatter + (traited ? 150 : 0),
				traited: traited,
				bestIndex: Math.min(ship.index.left, ship.index.right)
			};
			consideredShips.push(entry);
		});
		consideredShips.sort((a, b) => {
			if (a.score === b.score) return a.bestIndex - b.bestIndex;
			return b.score - a.score;
		});
		setBestShip(consideredShips[0]);
		setRequests([]);
		setResults([]);
	}, [voyageConfig]);

	React.useEffect(() => {
		return function cleanup() {
			// Cancel active calculations when leaving page
			requests.forEach(request => {
				if (request.calcState == CalculatorState.InProgress)
					request.abort();
			});
		}
	}, []);

	// Scroll here when calculator started, finished
	const topAnchor = React.useRef(null);

	const calculators = CALCULATORS.helpers.map(helper => {
		return { key: helper.id, value: helper.id, text: helper.name };
	});
	calculators.push({ key: 'all', value: 'all', text: 'All calculators (slower)' });

	return (
		<React.Fragment>
			<div ref={topAnchor} />
			{renderBestShip()}
			{renderResults()}
			{requests.length > 0 && <Header as='h3'>Options</Header>}
			<Form>
				<InputCrewOptions myCrew={myCrew} updateConsideredCrew={setConsideredCrew} />
				<Form.Group inline>
					<Form.Field
						control={Select}
						label='Calculator'
						options={calculators}
						value={calculator}
						onChange={(e, { value }) => setCalculator(value)}
						placeholder='Select calculator'
					/>
					{CALCULATORS.fields.filter(field => field.calculators.includes(calculator) || calculator == 'all').map(field => (
						<Form.Field
							key={field.id}
							control={Select}	/* Only control allowed at the moment */
							label={field.name}
							options={field.options}
							value={calcOptions[field.id] ?? field.default}
							placeholder={field.description}
							onChange={(e, { value }) => setCalcOptions(prevOptions =>
								{
									const newValue = { [field.id]: value };
									return {...prevOptions, ...newValue};
								}
							)}
						/>
					))}
				</Form.Group>

				<Form.Group>
					<Form.Button primary onClick={() => startCalculation()}>
						Calculate best crew selection
					</Form.Button>
					{voyageConfig.state &&
						<Form.Button onClick={()=> useInVoyage()}>
							Return to in voyage calculator
						</Form.Button>
					}
				</Form.Group>
			</Form>
			<Message style={{ marginTop: '2em' }}>
				<Message.Content>
					<Message.Header>Privacy Notice</Message.Header>
					<p>We use anonymous statistics aggregated from voyage calculations to improve DataCore and power our <b><Link to='/hall_of_fame'>Voyage Hall of Fame</Link></b>.</p>
					<Form>
						<Form.Field
							control={Checkbox}
							label={<label>Permit DataCore to collect anonymous voyage stats</label>}
							checked={!telemetryOptOut}
							onChange={(e, { checked }) => setTelemetryOptOut(!checked) }
						/>
					</Form>
				</Message.Content>
			</Message>
		</React.Fragment>
	);

	function renderBestShip(): JSX.Element {
		if (!bestShip) return (<></>);

		const direction = bestShip.ship.index.right < bestShip.ship.index.left ? 'right' : 'left';
		const index = bestShip.ship.index[direction] ?? 0;

		return (
			<Card fluid>
				<Card.Content>
					<Image floated='left' src={`${process.env.GATSBY_ASSETS_URL}${bestShip.ship.icon.file.substr(1).replace('/', '_')}.png`} style={{ height: '4em' }} />
					<Card.Header>{bestShip.ship.name}</Card.Header>
					<p>best ship{bestShip.traited && (<span style={{ marginLeft: '1em' }}>{` +`}{allTraits.ship_trait_names[voyageConfig.ship_trait]}</span>)}</p>
					<p style={{ marginTop: '.5em' }}>Tap <Icon name={`arrow ${direction}`} />{index} time{index != 1 ? 's' : ''} on your voyage ship selection screen to select {bestShip.ship.name}.</p>
				</Card.Content>
			</Card>
		);
	}

	function renderResults(): JSX.Element {
		if (results.length == 0)
			return (<></>);

		const showPopup = (result) => <Popup basic content={<p>{result.result.postscript}</p>} trigger={<p>{result.name}</p>} />
		const panes = results.map(result => ({
			menuItem: { key: result.id, content: result.result ? showPopup(result) : result.name },
			render: () => (
				<VoyageResultPane result={result.result}
					requests={requests} requestId={result.requestId}
					calcState={result.calcState} abortCalculation={abortCalculation}
				/>
			)
		}));

		return (
			<React.Fragment>
				<Header as='h3'>Recommended Lineups</Header>
				<Tab menu={{ pointing: true }}
					panes={panes}
				/>
			</React.Fragment>
		);
	}

	function scrollToAnchor(): void {
		if (!topAnchor.current) return;
		topAnchor.current.scrollIntoView({
			behavior: 'smooth'
		}, 500);
	}

	function startCalculation(): void {
		const helperConfig = {
			voyageConfig, bestShip, consideredCrew, calcOptions,
			resultsCallback: handleResults,
			isMobile
		};
		CALCULATORS.helpers.forEach(helper => {
			if (helper.id == calculator || calculator == 'all') {
				const request = helper.helper(helperConfig);
				requests.push(request);
				results.push({
					id: request.id,
					requestId: request.id,
					name: 'Calculating...',
					calcState: CalculatorState.InProgress
				});
				request.start();
			}
		});
		setRequests([...requests]);
		setResults([...results]);
		scrollToAnchor();
	}

	function handleResults(requestId: string, reqResults: any[], calcState: number): void {
		reqResults.forEach((reqResult, idx) => {
			// Update existing pane with results
			if (idx == 0) {
				setResults(prevResults => {
					const result = prevResults.find(r => r.id == requestId);
					if (calcState == CalculatorState.Done) {
						result.name = formatTime(reqResult.estimate.refills[0].result);
						result.calcState = CalculatorState.Done;
						sendTelemetry(requestId, reqResult);
					}
					result.result = reqResult;
					return [...prevResults];
				});
			}
			// Add new panes if multiple results generated by this request
			else {
				setResults(prevResults => [...prevResults, {
					id: requestId+'-'+idx,
					requestId,
					name: formatTime(reqResult.estimate.refills[0].result),
					calcState: CalculatorState.Done,
					result: reqResult
				}]);
			}
		});
		if (calcState == CalculatorState.Done) scrollToAnchor();
	}

	function abortCalculation(requestId: string): void {
		const request = requests.find(r => r.id == requestId);
		if (request) {
			request.abort();
			setResults(prevResults => {
				const result = prevResults.find(prev => prev.id == requestId);
				if (result.result) {
					result.name = formatTime(result.result.estimate.refills[0].result);
					result.calcState = CalculatorState.Done;
				}
				else {
					const index = prevResults.findIndex(prev => prev.id == requestId);
					prevResults.splice(index, 1);
				}
				return [...prevResults];
			});
		}
	}

	function sendTelemetry(requestId: string, result: any): void {
		if (telemetryOptOut) return;
		const request = requests.find(r => r.id == requestId);
		const estimatedDuration = result.estimate.refills[0].result*60*60;
		try {
			fetch(`${process.env.GATSBY_DATACORE_URL}api/telemetry`, {
				method: 'post',
				headers: {
					'Content-Type': 'application/json'
				},
				body: JSON.stringify({
					type: 'voyageCalc',
					data: {
						voyagers: result.entries.map((entry) => entry.choice.symbol),
						estimatedDuration,
						calculator: request ? request.calculator : ''
					}
				})
			});
		}
		catch (err) {
			console.log('An error occurred while sending telemetry', err);
		}
	}
}
Example #25
Source File: eventplanner.tsx    From website with MIT License 4 votes vote down vote up
EventPicker = (props: EventPickerProps) => {
	const { playerData, events, crew, buffConfig, allCrew } = props;

	const [eventIndex, setEventIndex] = useStateWithStorage('eventplanner/eventIndex', 0);
	const [phaseIndex, setPhaseIndex] = useStateWithStorage('eventplanner/phaseIndex', 0);
	const [prospects, setProspects] = useStateWithStorage('eventplanner/prospects', []);

	const eventsList = [];
	events.forEach((activeEvent, eventId) => {
		eventsList.push(
			{
				key: activeEvent.symbol,
				value: eventId,
				text: activeEvent.name
			}
		);
	});

	const eventData = events[eventIndex];

	const EVENT_TYPES = {
		'shuttles': 'Faction',
		'gather': 'Galaxy',
		'skirmish': 'Skirmish'
	};

	const phaseList = [];
	eventData.content_types.forEach((contentType, phaseId) => {
		if (!phaseList.find((phase) => phase.key == contentType)) {
			phaseList.push(
				{
					key: contentType,
					value: phaseId,
					text: EVENT_TYPES[contentType]
				}
			);
		}
	});

	const allBonusCrew = allCrew.filter((c) => eventData.bonus.indexOf(c.symbol) >= 0);
	allBonusCrew.sort((a, b)=>a.name.localeCompare(b.name));

	const myCrew = JSON.parse(JSON.stringify(crew));
	const lockable = [];

	prospects.forEach((p) => {
		let prospect = allCrew.find((c) => c.symbol == p.symbol);
		if (prospect) {
			prospect = JSON.parse(JSON.stringify(prospect));
			prospect.id = myCrew.length+1;
			prospect.prospect = true;
			prospect.have = false;
			prospect.rarity = p.rarity;
			prospect.level = 100;
			prospect.immortal = 0;
			CONFIG.SKILLS_SHORT.forEach(skill => {
				let score = { core: 0, min: 0, max: 0 };
				if (prospect.base_skills[skill.name]) {
					if (prospect.rarity == prospect.max_rarity)
						score = applySkillBuff(buffConfig, skill.name, prospect.base_skills[skill.name]);
					else
						score = applySkillBuff(buffConfig, skill.name, prospect.skill_data[prospect.rarity-1].base_skills[skill.name]);
				}
				prospect[skill.name] = score;
			});
			myCrew.push(prospect);
			lockable.push({
				symbol: prospect.symbol,
				name: prospect.name,
				rarity: prospect.rarity,
				level: prospect.level,
				prospect: prospect.prospect
			});
		}
	});

	return (
		<React.Fragment>
			<Form>
				<Form.Field
					control={Dropdown}
					selection
					options={eventsList}
					value={eventIndex}
					onChange={(e, { value }) => setEventIndex(value) }
				/>
				<Image size='large' src={`${process.env.GATSBY_ASSETS_URL}${eventData.image}`} />
				<div>{eventData.description}</div>
				{phaseList.length > 1 && (<div style={{ margin: '1em 0' }}>Select a phase: <Dropdown selection options={phaseList} value={phaseIndex} onChange={(e, { value }) => setPhaseIndex(value) } /></div>)}
			</Form>
			<EventCrewTable crew={myCrew} eventData={eventData} phaseIndex={phaseIndex} buffConfig={buffConfig} lockable={lockable} />
			<EventProspects pool={allBonusCrew} prospects={prospects} setProspects={setProspects} />
			{eventData.content_types[phaseIndex] == 'shuttles' && (<EventShuttles playerData={playerData} crew={myCrew} eventData={eventData} />)}
		</React.Fragment>
	);
}
Example #26
Source File: event_information.tsx    From website with MIT License 4 votes vote down vote up
function EventInformationTab({ eventData }) {
	const { crewJson } = useStaticQuery(graphql`
		query {
			crewJson: allCrewJson {
				edges {
					node {
						name
						max_rarity
						imageUrlPortrait
						symbol
						traits
						traits_hidden
						traits_named
						base_skills {
							security_skill {
								core
							}
							command_skill {
								core
							}
							diplomacy_skill {
								core
							}
							engineering_skill {
								core
							}
							medicine_skill {
								core
							}
							science_skill {
								core
							}
						}
					}
				}
			}
		}
	`);
	const crewData = crewJson.edges.map(edge => edge.node);
	const crewMap = {};
	crewData.forEach(crew => {
		crewMap[crew.symbol] = crew;
	})

	const {
		name,
		description,
		bonus_text,
		content_types,
	} = eventData;

	const { bonus, featured } = getEventData(eventData, crewData);
	const featuredCrewData = featured.map(symbol => {
		const crew = crewMap[symbol];
		return {
			key: `crew_${crew.symbol}`,
			name: crew.name,
			image: getIconPath({file: crew.imageUrlPortrait}),
			rarity: crew.max_rarity,
			skills: Object.keys(crew.base_skills)
				.filter(skill => !!crew.base_skills[skill])
				.sort((a, b) => crew.base_skills[a].core > crew.base_skills[b].core ? -1 : 1)
				.map(skill => ({
					key: skill,
					imageUrl: `${process.env.GATSBY_ASSETS_URL}atlas/icon_${skill}.png`
				})),
			traits: crew.traits_named,
		};
	});
	const bonusCrew = crewData.filter(crew => bonus.includes(crew.symbol) && !featured.includes(crew.symbol));

	return (
		<>
			<Card fluid raised>
				<Card.Content>
					<Card.Header>{name}</Card.Header>
					<Card.Meta>{getEventType(content_types)}</Card.Meta>
					<Card.Description>{description}</Card.Description>
				</Card.Content>
				<Card.Content extra>
					<p>{bonus_text}</p>
				</Card.Content>
			</Card>
			<Header as="h3">Featured Crew</Header>
			<Card.Group>
				{featuredCrewData.map(crew => (
					<CrewCard key={crew.key} crew={crew} />
				))}
			</Card.Group>
			<Header as="h3">Bonus Crew</Header>
			{bonusCrew.length === 0 && (
				<p>Bonus crew not yet determined for this event.</p>
			)}
			{sortCrew(bonusCrew).map(crew => (
				<Label key={`crew_${crew.symbol}`} color="black" style={{ marginBottom: '5px' }}>
					<Image
						src={getIconPath({ file: crew.imageUrlPortrait })}
						size="massive"
						inline
						spaced="right"
						bordered
						style={{
							borderColor: getRarityColor(crew.max_rarity)
						}}
						alt={crew.name}
					/>
					{crew.name}
				</Label>
			))}
		</>
	);
}
Example #27
Source File: commoncrewdata.tsx    From website with MIT License 4 votes vote down vote up
render() {
		const { markdownRemark, crew, compact, crewDemands, roster } = this.props;

		let panels = [
			{
				index: 0,
				key: 0,
				title: getCoolStats(crew, false),
				content: { content: <div style={{ paddingBottom: '1em' }}>{this.renderOtherRanks(crew)}</div> }
			}
		];

		if (roster && roster.length > 0) {
			panels.push(
				{
					index: 1,
					key: 1,
					title: this.rosterComparisonTitle(crew, roster),
					content: { content: <div style={{ paddingBottom: '1em' }}>{this.renderOtherRanks(crew, roster)}</div> }
				});
		}

		return (
			<React.Fragment>
				{compact ? (
					<Segment>
						<Grid columns={2}>
							<Grid.Column width={4}>
								<Image src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlFullBody}`} size="tiny" />
							</Grid.Column>
							<Grid.Column width={12}>
								<CrewStat
									skill_name="security_skill"
									data={crew.base_skills.security_skill}
									scale={compact ? 0.75 : 1}
								/>
								<CrewStat skill_name="command_skill" data={crew.base_skills.command_skill} scale={compact ? 0.75 : 1} />
								<CrewStat
									skill_name="diplomacy_skill"
									data={crew.base_skills.diplomacy_skill}
									scale={compact ? 0.75 : 1}
								/>
								<CrewStat skill_name="science_skill" data={crew.base_skills.science_skill} scale={compact ? 0.75 : 1} />
								<CrewStat
									skill_name="medicine_skill"
									data={crew.base_skills.medicine_skill}
									scale={compact ? 0.75 : 1}
								/>
								<CrewStat
									skill_name="engineering_skill"
									data={crew.base_skills.engineering_skill}
									scale={compact ? 0.75 : 1}
								/>
							</Grid.Column>
						</Grid>
					</Segment>
				) : (
						<Segment>
							<CrewStat skill_name="security_skill" data={crew.base_skills.security_skill} scale={compact ? 0.75 : 1} />
							<CrewStat skill_name="command_skill" data={crew.base_skills.command_skill} scale={compact ? 0.75 : 1} />
							<CrewStat skill_name="diplomacy_skill" data={crew.base_skills.diplomacy_skill} scale={compact ? 0.75 : 1} />
							<CrewStat skill_name="science_skill" data={crew.base_skills.science_skill} scale={compact ? 0.75 : 1} />
							<CrewStat skill_name="medicine_skill" data={crew.base_skills.medicine_skill} scale={compact ? 0.75 : 1} />
							<CrewStat
								skill_name="engineering_skill"
								data={crew.base_skills.engineering_skill}
								scale={compact ? 0.75 : 1}
							/>
						</Segment>
					)}

				{crew.skill_data && crew.skill_data.length > 0 && (
					<Accordion
						defaultActiveIndex={-1}
						panels={[
							{
								index: 0,
								key: 0,
								title: 'Other fuse levels',
								content: {
									content: (
										<Segment.Group raised>
											{crew.skill_data.map((sk: any, idx: number) => (
												<Segment key={idx}>
													<Rating
														defaultRating={sk.rarity}
														maxRating={crew.max_rarity}
														icon="star"
														size="small"
														disabled
													/>
													<CrewStat skill_name="security_skill" data={sk.base_skills.security_skill} scale={0.75} />
													<CrewStat skill_name="command_skill" data={sk.base_skills.command_skill} scale={0.75} />
													<CrewStat skill_name="diplomacy_skill" data={sk.base_skills.diplomacy_skill} scale={0.75} />
													<CrewStat skill_name="science_skill" data={sk.base_skills.science_skill} scale={0.75} />
													<CrewStat skill_name="medicine_skill" data={sk.base_skills.medicine_skill} scale={0.75} />
													<CrewStat
														skill_name="engineering_skill"
														data={sk.base_skills.engineering_skill}
														scale={0.75}
													/>
												</Segment>
											))}
										</Segment.Group>
									)
								}
							}
						]}
					/>
				)}

				{crew.flavor && !compact && <p>{crew.flavor}</p>}

				{compact && (
					<div style={{ textAlign: 'center' }}>
						<StatLabel title="Voyage rank" value={crew.ranks.voyRank} />
						<StatLabel title="Gauntlet rank" value={crew.ranks.gauntletRank} />
						<StatLabel title="Big book tier" value={formatTierLabel(markdownRemark.frontmatter.bigbook_tier)} />
						{markdownRemark.frontmatter.events !== null && (
							<StatLabel title="Events" value={markdownRemark.frontmatter.events} />
						)}
					</div>
				)}

				{!compact && (
					<>
					<Statistic.Group size="tiny">
						{markdownRemark.frontmatter.events !== null && (
							<Statistic>
								<Statistic.Label>Events</Statistic.Label>
								<Statistic.Value>{markdownRemark.frontmatter.events}</Statistic.Value>
							</Statistic>
						)}
						<Statistic>
							<Statistic.Label>Big Book Tier</Statistic.Label>
							<Statistic.Value>{formatTierLabel(markdownRemark.frontmatter.bigbook_tier)}</Statistic.Value>
						</Statistic>
						<Statistic>
							<Statistic.Label>CAB Rating <CABExplanation /></Statistic.Label>
							<Statistic.Value>{crew.cab_ov ?? 'None'}</Statistic.Value>
						</Statistic>
						{!compact && markdownRemark.frontmatter.in_portal !== null && (
							<Statistic color={markdownRemark.frontmatter.in_portal ? 'green' : 'red'}>
								<Statistic.Label>Portal</Statistic.Label>
								<Statistic.Value>{markdownRemark.frontmatter.in_portal ? 'YES' : 'NO'}</Statistic.Value>
							</Statistic>
						)}
						</Statistic.Group>
						<Statistic.Group style={{ paddingBottom: '2em' }} size="tiny">
						<Statistic>
							<Statistic.Label>CAB Rank <CABExplanation /></Statistic.Label>
							<Statistic.Value>{crew.cab_ov_rank ? rankLinker(false, crew.cab_ov_rank, crew.symbol, 'cab_ov', 'descending', 'rarity:'+crew.max_rarity) : 'None'}</Statistic.Value>
						</Statistic>
						<Statistic>
							<Statistic.Label>Voyage Rank</Statistic.Label>
							<Statistic.Value>{rankLinker(false, crew.ranks.voyRank, crew.symbol, 'ranks.voyRank')}</Statistic.Value>
						</Statistic>
						<Statistic>
							<Statistic.Label>Gauntlet Rank</Statistic.Label>
							<Statistic.Value>{rankLinker(false, crew.ranks.gauntletRank, crew.symbol, 'ranks.gauntletRank')}</Statistic.Value>
						</Statistic>
					</Statistic.Group>
					</>
				)}

				{crewDemands && (
					<p>
						<b>{crewDemands.factionOnlyTotal}</b>
						{' faction items, '}
						<span style={{ display: 'inline-block' }}>
							<img src={`${process.env.GATSBY_ASSETS_URL}atlas/energy_icon.png`} height={14} />
						</span>{' '}
						<b>{crewDemands.totalChronCost}</b>
						{', '}
						<span style={{ display: 'inline-block' }}>
							<img src={`${process.env.GATSBY_ASSETS_URL}currency_sc_currency_0.png`} height={16} />
						</span>{' '}
						<b>{crewDemands.craftCost}</b>
					</p>
				)}

				<Accordion
					exclusive={false}
					panels={panels}
				/>

				<p>
					<b>Traits: </b>
					{crew.traits_named
						.map(trait => (
							<a key={trait} href={`/?search=trait:${trait}`}>
								{trait}
							</a>
						))
						.reduce((prev, curr) => [prev, ', ', curr])}
					{', '}
					{crew.traits_hidden
						.map(trait => (
							<a style={{ color: 'lightgray' }} key={trait} href={`/?search=trait:${trait}`}>
								{trait}
							</a>
						))
						.reduce((prev, curr) => [prev, ', ', curr])}
				</p>

				{crew.cross_fuse_targets && crew.cross_fuse_targets.symbol && (
					<p>
						Can cross-fuse with{' '}
						<Link to={`/crew/${crew.cross_fuse_targets.symbol}/`}>{crew.cross_fuse_targets.name}</Link>.
					</p>
				)}

				{crew.collections.length > 0 && (
					<p>
						<b>Collections: </b>
						{crew.collections
							.map(col => (
								<Link key={col} to={`/collections/#${encodeURIComponent(col)}`}>
									{col}
								</Link>
							))
							.reduce((prev, curr) => [prev, ', ', curr])}
					</p>
				)}

				<p>
					<b>Date added: </b>{new Date(crew.date_added).toLocaleDateString("en-US")} (<b>Obtained: </b>{crew.obtained})
				</p>

				{crew.nicknames && crew.nicknames.length > 0 && (
					<p>
						<b>Also known as: </b>
						{crew.nicknames
							.map((nick, idx) => (
							<span key={idx}>{nick.cleverThing}{nick.creator ? <> (coined by <i>{nick.creator}</i>)</> : ''}</span>
						))
						.reduce((prev, curr) => [prev, ', ', curr])}
					</p>
				)}
			</React.Fragment>
		);
	}
Example #28
Source File: ProfileWidgetPlus.tsx    From communitymap-ui with Apache License 2.0 4 votes vote down vote up
EditUserProfile: React.FC<{ user: firebase.User }> = ({ user }) => {
  const [toggled, setToggle] = useState(false);
  const info = useUserPublicInfo(user.uid, true);
  const [changed, setChanged] = useState<{ name: string } | null>(null);

  const { status, func: saveInfo } = useAsyncStatus(async () => {
    return saveUserPublicInfo({
      ...(info || { id: user.uid }),
      ...(changed || { name: '' }),
    });
  });

  if (info === undefined) return <Loader active />;
  // if (info === null) return <div>User not found :(</div>;
  const UserForm = () => (
    <Form
      onSubmit={() => saveInfo()}
      loading={status.pending}
      error={!!status.error}
      success={status.success}
    >
      <Form.Input
        label="Name/Nickname"
        required
        value={changed?.name || info?.name || ''}
        onChange={(e, { value }) => setChanged({ ...changed, name: value })}
      />
      {/* <Form.Input label="Gender"/> */}

      <Message error>{status.error}</Message>
      <Message success>Successfully saved</Message>

      <Form.Group>
        <Form.Button primary disabled={!changed}>
          Save
        </Form.Button>
        <Form.Button
          type="button"
          disabled={!changed}
          onClick={() => setChanged(null)}
        >
          Clear changes
        </Form.Button>
      </Form.Group>
    </Form>
  );
  const BtnSettings = () => (
    <Button
      circular
      icon="settings"
      onClick={() => setToggle((toggled) => !toggled)}
    />
  );

  return (
    <Card>
      <Image
        src="http://dwinery.com/ocm/wp-content/uploads/elementor/thumbs/avatar-ookvknm0adkt2o1cwyctxzbsfccgeo4fo00qr8xhao.png"
        wrapped
        ui={false}
      />
      <Card.Content>
        <Card.Header>
          <Grid>
            <Grid.Column floated="left" width={8}>
              {info?.name}
            </Grid.Column>
            <Grid.Column floated="right" width={3}>
              {BtnSettings()}
            </Grid.Column>
          </Grid>
        </Card.Header>
        <Card.Meta>
          <span className="date">Joined in: {info?.created}</span>
        </Card.Meta>
        <Card.Description>{toggled && <>{UserForm()}</>}</Card.Description>
      </Card.Content>
      <Card.Content extra>
        <Grid columns={2} divided>
          <Grid.Row>
            <Grid.Column>
              <Icon name="handshake" /> 11 People
            </Grid.Column>
            <Grid.Column>
              <Icon name="globe" /> 12 Places
            </Grid.Column>
          </Grid.Row>
        </Grid>
      </Card.Content>
    </Card>
  );
}
Example #29
Source File: Place.tsx    From communitymap-ui with Apache License 2.0 4 votes vote down vote up
AddNewPlaceObject: React.FC<{
  type: ObjectItemInput['type'];
  onPost: (data: ObjectItemInput) => void;
}> = ({ type, onPost }) => {
  const [state, setState] = useState({} as any);
  const onChange = (e: any) => {
    const { name, value } = e.target;
    console.debug(e.target.name, e.target.value);
    setState({ ...state, [name]: value });
  };
  return (
    <div className="add-new-place">
      <h4>
        <Icon name="building outline" /> New place
      </h4>
      <Form
        onSubmit={(e) => {
          e.preventDefault();
          console.debug('submit', state);
          const {
            placeName,
            description,
            short_description = null,
            url = null,
            logoURL = null,
          } = state;

          onPost({
            type,
            title: placeName,
            description,
            short_description,
            url,
            logoURL,
            valid_until: '2100-01-05T09:00:00.000Z',
          });
        }}
      >
        {REACT_APP_CLOUDINARY_CLOUD_NAME && (
          <Form.Field>
            <label>Logo</label>
            <CloudinaryImageUpload
              cloudName={REACT_APP_CLOUDINARY_CLOUD_NAME}
              uploadPreset={REACT_APP_CLOUDINARY_UPLOAD_PRESET_LOGO}
              onChange={(logoURL) => setState({ ...state, logoURL })}
            >
              {state.logoURL && <Image src={state.logoURL} alt="logo" />}
            </CloudinaryImageUpload>
          </Form.Field>
        )}
        <Form.Input
          autoComplete="off"
          label="Name"
          placeholder="e.g. Annie's Bakery"
          name="placeName"
          required
          onChange={onChange}
        />
        <Form.Input
          autoComplete="off"
          label="Very brief description"
          name="short_description"
          placeholder="e.g. Nice bagels and tasty latte"
          required
          onChange={onChange}
        />
        <Form.Input
          autoComplete="off"
          label="Website URL"
          name="url"
          onChange={onChange}
        />
        <Form.TextArea
          autoFocus
          required
          label="Description"
          name="description"
          onChange={onChange}
        />

        <Form.Button primary>Add</Form.Button>
      </Form>
    </div>
  );
}