semantic-ui-react#Label TypeScript Examples

The following examples show how to use semantic-ui-react#Label. 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: LobbyMeetingRoom.tsx    From FLECT_Amazon_Chime_Meeting with Apache License 2.0 6 votes vote down vote up
labelExampleCircular = () => (
        <span>
          {colors.map((color) => (
              //@ts-ignore
            <Label circular empty as="a" color={color} key={color} active={color===this.state.drawingStroke}
                link onClick={()=>{
                    this.mainOverlayVideoRef.current!.setDrawingStroke(color);
                    this.mainOverlayVideoRef.current!.setErasing(false);
                    this.mainOverlayVideoRef.current!.setDrawingMode(true)
                    this.setState({
                        drawingStroke:color,
                        enableDrawing:true,
                        erasing:false,
                    })

                }
            } />
          ))}
        </span>
    )
Example #2
Source File: index.tsx    From chartsy with GNU General Public License v3.0 6 votes vote down vote up
Slider: React.FC<SliderProps> = ({ title, value, min, max, dispatch }) => {
  return (
    <div className="slider">
      <div className="slider-info">
        <p>{title}</p>
        <Label horizontal>{value}</Label>
      </div>
      <input type="range" min={min} max={max} value={value} onChange={dispatch} />
    </div>
  );
}
Example #3
Source File: index.tsx    From frontegg-react with MIT License 6 votes vote down vote up
InputChip = forwardRef<HTMLInputElement, IInputChip>(
  ({ chips, fullWidth, onDelete, className, ...inputProps }, ref) => {
    const inputRef = useRef<HTMLInputElement>(null);

    return (
      <div
        className={classNames('input-chip', className, { fluid: fullWidth })}
        onClick={() => inputRef.current && inputRef.current.focus()}
      >
        {chips.map((chip, idx) => (
          <Label as='div' key={idx} className='chip'>
            {chip}
            {!!onDelete && <Icon name='delete' onClick={() => onDelete(idx)} />}
          </Label>
        ))}
        <input {...inputProps} ref={ref} />
      </div>
    );
  }
)
Example #4
Source File: index.tsx    From frontegg-react with MIT License 6 votes vote down vote up
Tag: FC<TagProps> = (props) => {
  const { children, onDelete, ...rest } = props;
  return (
    <Label {...mapper(rest)}>
      {children}
      {onDelete && <Icon name='delete' onClick={onDelete} />}
    </Label>
  );
}
Example #5
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 #6
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 #7
Source File: commoncrewdata.tsx    From website with MIT License 6 votes vote down vote up
render() {
		const { title, value } = this.props;

		return (
			<Label size="large" style={{ marginBottom: '0.5em' }}>
				{title}
				<Label.Detail>{value}</Label.Detail>
			</Label>
		);
	}
Example #8
Source File: OrgInfo.tsx    From Riakuto-StartingReact-ja3.1 with Apache License 2.0 6 votes vote down vote up
OrgInfo: VFC<{ org: Organization | null }> = ({ org = null }) =>
  org ? (
    <>
      <Item.Group>
        <Item>
          <Item.Image src={org.avatarUrl} size="small" />
          <Item.Content>
            <Item.Header as="a">{org.name}</Item.Header>
            <Item.Meta>{org.description}</Item.Meta>
            <Item.Extra>
              {org.location && (
                <span>
                  <Icon name="map marker alternate" />
                  {org.location}
                </span>
              )}
              {org.blog && (
                <span>
                  <Icon name="globe" />
                  <a href={org.blog} target="_blank" rel="noopener noreferrer">
                    {org.blog}
                  </a>
                </span>
              )}
              {org.isVerified && (
                <Label basic color="teal">
                  verified
                </Label>
              )}
            </Item.Extra>
          </Item.Content>
        </Item>
      </Item.Group>
    </>
  ) : (
    <div />
  )
Example #9
Source File: crewpage.tsx    From website with MIT License 5 votes vote down vote up
renderEquipmentDetails(crew) {
		if (!this.state.selectedEquipment) {
			return <span />;
		}

		let es = crew.equipment_slots.find(es => es.symbol === this.state.selectedEquipment);
		let equipment = this.state.items.find(item => item.symbol === es.symbol);
		if (!equipment) {
			console.error('Could not find equipment for slot', es);
			return <span />;
		}

		if (!equipment.recipe) {
			return (
				<div>
					<br />
					<p>This item is not craftable, you can find it in these sources:</p>
					<ItemSources item_sources={equipment.item_sources} />
				</div>
			);
		}

		return (
			<div>
				<Grid columns={4} centered padded>
					{equipment.recipe.list.map(entry => {
						let recipeEntry = this.state.items.find(item => item.symbol === entry.symbol);
						return (
							<Grid.Column key={recipeEntry.name + recipeEntry.rarity} textAlign='center'>
								<Popup
									trigger={
										<Label as='a' style={{ background: CONFIG.RARITIES[recipeEntry.rarity].color }} image size='big'>
											<img src={`${process.env.GATSBY_ASSETS_URL}${recipeEntry.imageUrl}`} />x{entry.count}
										</Label>
									}
									header={CONFIG.RARITIES[recipeEntry.rarity].name + ' ' + recipeEntry.name}
									content={<ItemSources item_sources={recipeEntry.item_sources} />}
									wide
								/>
							</Grid.Column>
						);
					})}
				</Grid>
			</div>
		);
	}
Example #10
Source File: ColorfulBeads.tsx    From Riakuto-StartingReact-ja3.1 with Apache License 2.0 5 votes vote down vote up
ColorfulBeads: VFC<{ count?: number }> = ({ count = 0 }) => (
  <Container className="beads-box">
    {range(count).map((n: number) => (
      <Label circular color={colors[n % colors.length]} key={n} />
    ))}
  </Container>
)
Example #11
Source File: SettingsTab.tsx    From watchparty with MIT License 5 votes vote down vote up
SettingRow = ({
  icon,
  name,
  description,
  checked,
  disabled,
  onChange,
  content,
  subOnly,
  helpIcon,
}: {
  icon: string;
  name: string;
  description?: React.ReactNode;
  checked?: boolean;
  disabled: boolean;
  updateTS?: number;
  onChange?: (e: React.FormEvent, data: CheckboxProps) => void;
  content?: React.ReactNode;
  subOnly?: boolean;
  helpIcon?: React.ReactNode;
}) => {
  return (
    <React.Fragment>
      <Divider inverted horizontal />
      <div>
        <div style={{ display: 'flex' }}>
          <Icon size="large" name={icon as any} />
          <div>
            {name} {helpIcon}
            {subOnly ? (
              <Label size="mini" color="orange">
                Subscriber only
              </Label>
            ) : null}
          </div>
          {!content && (
            <Radio
              style={{ marginLeft: 'auto' }}
              toggle
              checked={checked}
              disabled={disabled}
              onChange={onChange}
            />
          )}
        </div>
        <div className="smallText" style={{ marginBottom: '8px' }}>
          {description}
        </div>
        {content}
      </div>
    </React.Fragment>
  );
}
Example #12
Source File: SearchResult.tsx    From watchparty with MIT License 5 votes vote down vote up
render() {
    const result = this.props;
    const setMedia = this.props.setMedia;
    return (
      <React.Fragment>
        <Menu.Item
          onClick={async (e) => {
            this.props.launchMultiSelect([]);
            let response = await window.fetch(
              this.props.streamPath +
                '/data?torrent=' +
                encodeURIComponent(result.magnet!)
            );
            let metadata = await response.json();
            // console.log(metadata);
            if (
              metadata.files.filter(
                (file: any) => file.length > 10 * 1024 * 1024
              ).length > 1
            ) {
              // Multiple large files, present user selection
              const multiStreamSelection = metadata.files.map(
                (file: any, i: number) => ({
                  ...file,
                  url:
                    this.props.streamPath +
                    '/stream?torrent=' +
                    encodeURIComponent(result.magnet!) +
                    '&fileIndex=' +
                    i,
                })
              );
              multiStreamSelection.sort((a: any, b: any) =>
                a.name.localeCompare(b.name)
              );
              this.props.launchMultiSelect(multiStreamSelection);
            } else {
              this.props.launchMultiSelect(undefined);
              setMedia(e, {
                value:
                  this.props.streamPath +
                  '/stream?torrent=' +
                  encodeURIComponent(result.magnet!),
              });
            }
          }}
        >
          <Label
            circular
            empty
            color={Number(result.seeders) ? 'green' : 'red'}
          />
          <Icon name="film" />
          {result.name +
            ' - ' +
            result.size +
            ' - ' +
            result.seeders +
            ' peers'}
        </Menu.Item>
      </React.Fragment>
    );
  }
Example #13
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 #14
Source File: LobbyMeetingRoom.tsx    From FLECT_Amazon_Chime_Meeting with Apache License 2.0 4 votes vote down vote up
render(){
        const props = this.props as any
        const appState = props.appState as AppState
        const gs = this.props as GlobalState
        
        const thisAttendeeId = props.thisAttendeeId as string
        const thisMeetingId  = props.thisMeetingId as string
        const attendeeInfo = appState.joinedMeetings[thisMeetingId].roster[thisAttendeeId]
        let attendeeName = "no focused"
        //let meetingShortId = thisMeetingId.substr(0,5)
        const meetingName = gs.meetings.filter((x)=>{return x.meetingId === thisMeetingId})[0].meetingName
        

        let muted = <div/>
        if(attendeeInfo === undefined){
        }else{
            attendeeName = (attendeeInfo.name !== undefined && attendeeInfo.name !== null)? attendeeInfo.name!.substring(0,20) : "unknown"
            muted = attendeeInfo.muted ? (<Icon name="mute"  color="red" />) : (<Icon name="unmute"/>)
        }

        const focusedTileId = getTileId(thisAttendeeId, appState.joinedMeetings[thisMeetingId].videoTileStates)
        if(focusedTileId > 0 && this.mainOverlayVideoRef.current !== null){
            if(appState.joinedMeetings[thisMeetingId].videoTileStates[focusedTileId].localTile){
                const videoElement = this.mainOverlayVideoRef.current.getVideoRef().current!
                appState.joinedMeetings[thisMeetingId].meetingSession?.audioVideo.bindVideoElement(focusedTileId, videoElement)
                videoElement.style.setProperty('-webkit-transform', 'scaleX(1)');
                videoElement.style.setProperty('transform', 'scaleX(1)');
            }else{
                appState.joinedMeetings[thisMeetingId].meetingSession?.audioVideo.bindVideoElement(focusedTileId, this.mainOverlayVideoRef.current.getVideoRef().current!)
            }
        }else{
            console.log("not focusedid", focusedTileId, this.mainOverlayVideoRef.current)
        }

        return(
            <Grid>
                <Grid.Row>
                    <Grid.Column>
                        
                        <div>
                            <MainOverlayVideoElement {...props} ref={this.mainOverlayVideoRef}/>
                        </div>
                        <span>
                            {muted}
                            {attendeeName} @ {meetingName}
                        </span>

                        <span style={{paddingLeft:"10px"}}>
                            <Icon name="pencil" color={this.state.enableDrawing? "red":"grey"}
                                link onClick ={
                                    ()=>{
                                        this.mainOverlayVideoRef.current!.setDrawingMode(!this.state.enableDrawing)
                                        this.mainOverlayVideoRef.current!.setErasing(false)
                                        this.setState({
                                            enableDrawing:!this.state.enableDrawing,
                                            erasing:false,
                                        })
                                    }
                                }
                            />
                            {this.labelExampleCircular()}
                            <Icon name="eraser" color={this.state.erasing? "red":"grey"}
                                link onClick={
                                    ()=>{
                                        this.mainOverlayVideoRef.current!.setErasing(true)
                                        this.setState({
                                            erasing:true,
                                            enableDrawing:false
                                        })
                                    }
                                } 
                            />
                            <Icon name="file outline" link onClick={()=>{this.mainOverlayVideoRef.current!.clearDrawingCanvas()}} />
                        </span>


                        <span style={{paddingLeft:"10px"}}>
                            <Icon basic link name="long arrow alternate left"  size="large"
                                onClick={() => {
                                    props.setForegroundPosition(ForegroundPosition.BottomLeft)
                                }}
                            />
                            <Icon basic link name="long arrow alternate right"  size="large"
                                onClick={() => {
                                    props.setForegroundPosition(ForegroundPosition.BottomRight)
                                }}
                            />
                            <Icon basic link name="square outline"  size="large"
                                onClick={() => {
                                    props.setForegroundSize(ForegroundSize.Full)
                                }}
                            />
                            <Icon basic link name="expand"  size="large"
                                onClick={() => {
                                    props.setForegroundSize(ForegroundSize.Large)
                                }}
                            />
                            <Icon basic link name="compress"  size="large"
                                onClick={() => {
                                    props.setForegroundSize(ForegroundSize.Small)
                                }}
                            />
                        </span>
                        
                        <span style={{paddingLeft:"10px"}}>
                            <Label as="a" onClick={() => { props.setVirtualForeground(VirtualForegroundType.None) }} >
                                <Icon name="square outline" size="large"/>
                                None
                            </Label> 
                            <Label as="a" onClick={() => { props.setVirtualForeground(VirtualForegroundType.Canny) }} >
                                <Icon name="chess board" size="large"/>
                                canny
                            </Label> 
                            <Label as="a" onClick={() => { props.setVirtualForeground(VirtualForegroundType.Ascii) }} >
                                <Icon name="font" size="large"/>
                                ascii
                            </Label> 
                        </span>

                    </Grid.Column>
                </Grid.Row>
            </Grid>
        )
    }
Example #15
Source File: profile.tsx    From website with MIT License 4 votes vote down vote up
renderDesktop() {
		const { playerData } = this.state;

		const panes = [
			{
				menuItem: 'Crew',
				render: () => <ProfileCrew playerData={this.state.playerData} />
			},
			{
				menuItem: 'Crew (mobile)',
				render: () => <ProfileCrewMobile playerData={this.state.playerData} isMobile={false} />
			},
			{
				menuItem: 'Ships',
				render: () => <ProfileShips playerData={this.state.playerData} />
			},
			{
				menuItem: 'Items',
				render: () => <ProfileItems playerData={this.state.playerData} />
			},
			{
				menuItem: 'Other',
				render: () => <ProfileOther playerData={this.state.playerData} />
			},
			{
				menuItem: 'Charts & Stats',
				render: () => <ProfileCharts playerData={this.state.playerData} />
			}
		];

		return (
			<Layout title={playerData.player.character.display_name}>
				<Item.Group>
					<Item>
						<Item.Image
							size='tiny'
							src={`${process.env.GATSBY_ASSETS_URL}${playerData.player.character.crew_avatar
									? playerData.player.character.crew_avatar.portrait
									: 'crew_portraits_cm_empty_sm.png'
								}`}
						/>

						<Item.Content>
							<Item.Header>{playerData.player.character.display_name}</Item.Header>
							<Item.Meta>
								<Label>VIP {playerData.player.vip_level}</Label>
								<Label>Level {playerData.player.character.level}</Label>
								<Label>{playerData.calc.numImmortals} crew</Label>
								<Label>{playerData.player.character.shuttle_bays} shuttles</Label>
							</Item.Meta>
							<Item.Description>
								{playerData.player.fleet && (
									<p>
										Fleet{' '}
										<Link to={`/fleet_info?fleetid=${playerData.player.fleet.id}`}>
											<b>{playerData.player.fleet.slabel}</b>
										</Link>{' '}
											({playerData.player.fleet.rank}) Starbase level {playerData.player.fleet.nstarbase_level}{' '}
									</p>
								)}
							</Item.Description>
						</Item.Content>
					</Item>
				</Item.Group>

				<Menu compact>
					<Menu.Item>
						{playerData.calc.lastModified ? <span>Last updated: {playerData.calc.lastModified.toLocaleString()}</span> : <span />}
					</Menu.Item>
					<Dropdown item text='Download'>
						<Dropdown.Menu>
							<Dropdown.Item onClick={() => this._exportExcel()}>Complete spreadsheet (XLSX)</Dropdown.Item>
							<Dropdown.Item onClick={() => this._exportCrew()}>Crew table (CSV)</Dropdown.Item>
							<Dropdown.Item onClick={() => this._exportShips()}>Ship table (CSV)</Dropdown.Item>
							<Dropdown.Item onClick={() => this._exportItems()}>Item table (CSV)</Dropdown.Item>
						</Dropdown.Menu>
					</Dropdown>
				</Menu>
				<Tab menu={{ secondary: true, pointing: true }} panes={panes} />
			</Layout>
		);
	}
Example #16
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 #17
Source File: events.tsx    From website with MIT License 4 votes vote down vote up
function EventsPage() {
	const [eventsData, setEventsData] = React.useState<EventInstance[]>([]);
	const [leaderboardData, setLeaderboardData] = React.useState(null);
	const [loadingError, setLoadingError] = React.useState(null);
	const [modalEventInstance, setModalEventInstance] = React.useState(null);

	// load the events and leaderboard data once on component mount
	React.useEffect(() => {
		async function loadData() {
			try {
				const fetchEventResp = await fetch('/structured/event_instances.json')
				const eventDataList = await fetchEventResp.json();
				setEventsData(eventDataList.reverse());

				const fetchLeaderboardResp = await fetch('/structured/event_leaderboards.json');
				const leaderboardDataList = await fetchLeaderboardResp.json();
				const keyedLeaderboard = {};
				leaderboardDataList.forEach(entry => keyedLeaderboard[entry.instance_id] = entry);
				setLeaderboardData(keyedLeaderboard);
			}
			catch (e) {
				setLoadingError(e);
			}
		}

		loadData();
	}, []);

	return (
		<Layout>
			<Container style={{ paddingTop: '4em', paddingBottom: '2em' }}>
				<Header as='h2'>Events</Header>
				{loadingError && (
					<Message negative>
						<Message.Header>Unable to load event information</Message.Header>
						<pre>{loadingError.toString()}</pre>
					</Message>
				)}
				<Grid stackable columns={3}>
					{eventsData.map(eventInfo => (
						<Grid.Column key={eventInfo.instance_id}>
							<div
								style={{ cursor: 'pointer' }}
								onClick={() => setModalEventInstance(eventInfo)}
							>
								<Segment padded>
									<Label attached="bottom">
										{eventInfo.event_name}
									</Label>
									<LazyImage
										src={`${process.env.GATSBY_ASSETS_URL}${eventInfo.image}`}
										size="large"
										onError={e => e.target.style.visibility = 'hidden'}
									/>
								</Segment>
							</div>
						</Grid.Column>
					))}
				</Grid>
				{modalEventInstance !== null && (
					<Modal
						open
						size="large"
						onClose={() => setModalEventInstance(null)}
						closeIcon
					>
						<Modal.Header>{modalEventInstance.event_name}</Modal.Header>
						<Modal.Content scrolling>
							<EventInfoModal
								instanceId={modalEventInstance.instance_id}
								image={modalEventInstance.image}
								hasDetails={modalEventInstance.event_details}
								leaderboard={leaderboardData[modalEventInstance.instance_id].leaderboard}
							/>
						</Modal.Content>
					</Modal>
				)}
			</Container>
		</Layout>
	);
}
Example #18
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 #19
Source File: event_info.tsx    From website with MIT License 4 votes vote down vote up
renderEventDetails() {
		const { event_data } = this.state;

		if (event_data === undefined || event_data.event_details === undefined) {
			return <span />;
		}

		let event = event_data.event_details;

		return (
			<div>
				<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>
				<p>{event.description}</p>
				<p>{event.rules}</p>

				<Label>{event.bonus_text}</Label>

				{event.content.map((cnt, idx) => {
					let crew_bonuses = undefined;
					if (cnt.shuttles) {
						crew_bonuses = cnt.shuttles[0].crew_bonuses;
					} else if (cnt.crew_bonuses) {
						crew_bonuses = cnt.crew_bonuses;
					} else if (cnt.bonus_crew && cnt.bonus_traits) {
						// Skirmishes
						crew_bonuses = {};
						cnt.bonus_crew.forEach(element => {
							crew_bonuses[element] = 10;
						});

						// TODO: crew from traits
					} else if (cnt.special_crew) {
						// Expeditions
						crew_bonuses = {};
						cnt.special_crew.forEach(element => {
							crew_bonuses[element] = 50;
						});
					}
					return (
						<div key={idx}>
							<Header as='h5'>Phase {idx + 1}</Header>
							<Label>Type: {cnt.content_type}</Label>
							<Header as='h6'>Bonus crew</Header>
							{crew_bonuses && (
								<p>
									{Object.entries(crew_bonuses).map(([bonus, val], idx) => (
										<span key={idx}>
											{bonus} ({val}),
										</span>
									))}
								</p>
							)}
						</div>
					);
				})}

				<Header as='h4'>Threshold rewards</Header>
				<Table celled selectable striped collapsing unstackable compact='very'>
					<Table.Header>
						<Table.Row>
							<Table.HeaderCell width={2}>Points</Table.HeaderCell>
							<Table.HeaderCell width={4}>Reward</Table.HeaderCell>
						</Table.Row>
					</Table.Header>
					<Table.Body>
						{event.threshold_rewards.filter(reward => reward.rewards && reward.rewards.length > 0).map((reward, idx) => (
							<Table.Row key={idx}>
								<Table.Cell>{reward.points}</Table.Cell>
								<Table.Cell>
									{reward.rewards[0].quantity} {reward.rewards[0].full_name}
								</Table.Cell>
							</Table.Row>
						))}
					</Table.Body>
				</Table>

				<Header as='h4'>Ranked rewards</Header>
				<Table celled selectable striped collapsing unstackable compact='very'>
					<Table.Header>
						<Table.Row>
							<Table.HeaderCell width={2}>Ranks</Table.HeaderCell>
							<Table.HeaderCell width={4}>Rewards</Table.HeaderCell>
						</Table.Row>
					</Table.Header>
					<Table.Body>
						{event.ranked_brackets.map((bracket, idx) => (
							<Table.Row key={idx}>
								<Table.Cell>
									{bracket.first} - {bracket.last}
								</Table.Cell>
								<Table.Cell>
									{bracket.rewards.map((reward, idx) => (
										<span key={idx}>
											{reward.quantity} {reward.full_name},
										</span>
									))}
								</Table.Cell>
							</Table.Row>
						))}
					</Table.Body>
				</Table>

				<Header as='h4'>Quest</Header>

				{event.quest ? event.quest.map((quest, idx) => (
					<div key={idx}>
						{quest && quest.screens && quest.screens.map((screen, idx) => (
							<p key={idx}>
								<b>{screen.speaker_name}: </b>
								{screen.text}
							</p>
						))}
					</div>
				)) : <span>Mini-events don't include quest information.</span>}

				<Message>
					<Message.Header>TODO: Leaderboard out of date</Message.Header>
					If this event is currently active, the leaderboard below is out of date (updated only a couple of times a week).
				</Message>
			</div>
		);
	}
Example #20
Source File: App.tsx    From watchparty with MIT License 4 votes vote down vote up
render() {
    const sharer = this.state.participants.find((p) => p.isScreenShare);
    const controls = (
      <Controls
        key={this.state.controlsTimestamp}
        togglePlay={this.togglePlay}
        onSeek={this.onSeek}
        fullScreen={this.fullScreen}
        toggleMute={this.toggleMute}
        toggleSubtitle={this.toggleSubtitle}
        setVolume={this.setVolume}
        jumpToLeader={this.jumpToLeader}
        paused={this.state.currentMediaPaused}
        muted={this.isMuted()}
        subtitled={this.isSubtitled()}
        currentTime={this.getCurrentTime()}
        duration={this.getDuration()}
        disabled={!this.haveLock()}
        leaderTime={this.isHttp() ? this.getLeaderTime() : undefined}
        isPauseDisabled={this.isPauseDisabled()}
      />
    );
    const subscribeButton = (
      <SubscribeButton
        user={this.props.user}
        isSubscriber={this.props.isSubscriber}
        isCustomer={this.props.isCustomer}
      />
    );
    const displayRightContent =
      this.state.showRightBar || this.state.fullScreen;
    const rightBar = (
      <Grid.Column
        width={displayRightContent ? 4 : 1}
        style={{ display: 'flex', flexDirection: 'column' }}
        className={`${
          this.state.fullScreen
            ? 'fullHeightColumnFullscreen'
            : 'fullHeightColumn'
        }`}
      >
        <Input
          inverted
          fluid
          label={'My name is:'}
          value={this.state.myName}
          onChange={this.updateName}
          style={{ visibility: displayRightContent ? '' : 'hidden' }}
          icon={
            <Icon
              onClick={() => this.updateName(null, { value: generateName() })}
              name="refresh"
              inverted
              circular
              link
            />
          }
        />
        {
          <Menu
            inverted
            widths={3}
            style={{
              marginTop: '4px',
              marginBottom: '4px',
              visibility: displayRightContent ? '' : 'hidden',
            }}
          >
            <Menu.Item
              name="chat"
              active={this.state.currentTab === 'chat'}
              onClick={() => {
                this.setState({ currentTab: 'chat', unreadCount: 0 });
              }}
              as="a"
            >
              Chat
              {this.state.unreadCount > 0 && (
                <Label circular color="red">
                  {this.state.unreadCount}
                </Label>
              )}
            </Menu.Item>
            <Menu.Item
              name="people"
              active={this.state.currentTab === 'people'}
              onClick={() => this.setState({ currentTab: 'people' })}
              as="a"
            >
              People
              <Label
                circular
                color={
                  getColorForString(
                    this.state.participants.length.toString()
                  ) as SemanticCOLORS
                }
              >
                {this.state.participants.length}
              </Label>
            </Menu.Item>
            <Menu.Item
              name="settings"
              active={this.state.currentTab === 'settings'}
              onClick={() => this.setState({ currentTab: 'settings' })}
              as="a"
            >
              {/* <Icon name="setting" /> */}
              Settings
            </Menu.Item>
          </Menu>
        }
        <Chat
          chat={this.state.chat}
          nameMap={this.state.nameMap}
          pictureMap={this.state.pictureMap}
          socket={this.socket}
          scrollTimestamp={this.state.scrollTimestamp}
          getMediaDisplayName={this.getMediaDisplayName}
          hide={this.state.currentTab !== 'chat' || !displayRightContent}
          isChatDisabled={this.state.isChatDisabled}
          owner={this.state.owner}
          user={this.props.user}
          ref={this.chatRef}
        />
        {this.state.state === 'connected' && (
          <VideoChat
            socket={this.socket}
            participants={this.state.participants}
            nameMap={this.state.nameMap}
            pictureMap={this.state.pictureMap}
            tsMap={this.state.tsMap}
            rosterUpdateTS={this.state.rosterUpdateTS}
            hide={this.state.currentTab !== 'people' || !displayRightContent}
            owner={this.state.owner}
            user={this.props.user}
          />
        )}
        <SettingsTab
          hide={this.state.currentTab !== 'settings' || !displayRightContent}
          user={this.props.user}
          roomLock={this.state.roomLock}
          setRoomLock={this.setRoomLock}
          socket={this.socket}
          isSubscriber={this.props.isSubscriber}
          roomId={this.state.roomId}
          isChatDisabled={this.state.isChatDisabled}
          setIsChatDisabled={this.setIsChatDisabled}
          owner={this.state.owner}
          setOwner={this.setOwner}
          vanity={this.state.vanity}
          setVanity={this.setVanity}
          roomLink={this.state.roomLink}
          password={this.state.password}
          setPassword={this.setPassword}
          clearChat={this.clearChat}
          roomTitle={this.state.roomTitle}
          setRoomTitle={this.setRoomTitle}
          roomDescription={this.state.roomDescription}
          setRoomDescription={this.setRoomDescription}
          roomTitleColor={this.state.roomTitleColor}
          setRoomTitleColor={this.setRoomTitleColor}
          mediaPath={this.state.mediaPath}
          setMediaPath={this.setMediaPath}
        />
      </Grid.Column>
    );
    return (
      <React.Fragment>
        {!this.state.isAutoPlayable && (
          <Modal inverted basic open>
            <div style={{ display: 'flex', justifyContent: 'center' }}>
              <Button
                primary
                size="large"
                onClick={() => {
                  this.setState({ isAutoPlayable: true });
                  this.setMute(false);
                  this.setVolume(1);
                }}
                icon
                labelPosition="left"
              >
                <Icon name="volume up" />
                Click to unmute
              </Button>
            </div>
          </Modal>
        )}
        {this.state.multiStreamSelection && (
          <MultiStreamModal
            streams={this.state.multiStreamSelection}
            setMedia={this.setMedia}
            resetMultiSelect={this.resetMultiSelect}
          />
        )}
        {this.state.isVBrowserModalOpen && (
          <VBrowserModal
            isSubscriber={this.props.isSubscriber}
            subscribeButton={subscribeButton}
            closeModal={() => this.setState({ isVBrowserModalOpen: false })}
            startVBrowser={this.startVBrowser}
            user={this.props.user}
            beta={this.props.beta}
          />
        )}
        {this.state.isScreenShareModalOpen && (
          <ScreenShareModal
            closeModal={() => this.setState({ isScreenShareModalOpen: false })}
            startScreenShare={this.setupScreenShare}
          />
        )}
        {this.state.isFileShareModalOpen && (
          <FileShareModal
            closeModal={() => this.setState({ isFileShareModalOpen: false })}
            startFileShare={this.setupFileShare}
          />
        )}
        {this.state.isSubtitleModalOpen && (
          <SubtitleModal
            closeModal={() => this.setState({ isSubtitleModalOpen: false })}
            socket={this.socket}
            currentSubtitle={this.state.currentSubtitle}
            src={this.state.currentMedia}
            haveLock={this.haveLock}
            getMediaDisplayName={this.getMediaDisplayName}
            beta={this.props.beta}
          />
        )}
        {this.state.error && <ErrorModal error={this.state.error} />}
        {this.state.isErrorAuth && (
          <PasswordModal
            savedPasswords={this.state.savedPasswords}
            roomId={this.state.roomId}
          />
        )}
        {this.state.errorMessage && (
          <Message
            negative
            header="Error"
            content={this.state.errorMessage}
            style={{
              position: 'fixed',
              bottom: '10px',
              right: '10px',
              zIndex: 1000,
            }}
          ></Message>
        )}
        {this.state.successMessage && (
          <Message
            positive
            header="Success"
            content={this.state.successMessage}
            style={{
              position: 'fixed',
              bottom: '10px',
              right: '10px',
              zIndex: 1000,
            }}
          ></Message>
        )}
        <TopBar
          user={this.props.user}
          isCustomer={this.props.isCustomer}
          isSubscriber={this.props.isSubscriber}
          roomTitle={this.state.roomTitle}
          roomDescription={this.state.roomDescription}
          roomTitleColor={this.state.roomTitleColor}
        />
        {
          <Grid stackable celled="internally">
            <Grid.Row id="theaterContainer">
              <Grid.Column
                width={this.state.showRightBar ? 12 : 15}
                className={
                  this.state.fullScreen
                    ? 'fullHeightColumnFullscreen'
                    : 'fullHeightColumn'
                }
              >
                <div
                  style={{
                    display: 'flex',
                    flexDirection: 'column',
                    height: '100%',
                  }}
                >
                  {!this.state.fullScreen && (
                    <React.Fragment>
                      <ComboBox
                        setMedia={this.setMedia}
                        playlistAdd={this.playlistAdd}
                        playlistDelete={this.playlistDelete}
                        playlistMove={this.playlistMove}
                        currentMedia={this.state.currentMedia}
                        getMediaDisplayName={this.getMediaDisplayName}
                        launchMultiSelect={this.launchMultiSelect}
                        streamPath={this.props.streamPath}
                        mediaPath={this.state.mediaPath}
                        disabled={!this.haveLock()}
                        playlist={this.state.playlist}
                      />
                      <Separator />
                      <div
                        className="mobileStack"
                        style={{ display: 'flex', gap: '4px' }}
                      >
                        {this.screenShareStream && (
                          <Button
                            fluid
                            className="toolButton"
                            icon
                            labelPosition="left"
                            color="red"
                            onClick={this.stopScreenShare}
                            disabled={sharer?.id !== this.socket?.id}
                          >
                            <Icon name="cancel" />
                            Stop Share
                          </Button>
                        )}
                        {!this.screenShareStream &&
                          !sharer &&
                          !this.isVBrowser() && (
                            <Popup
                              content={`Share a tab or an application. Make sure to check "Share audio" for best results.`}
                              trigger={
                                <Button
                                  fluid
                                  className="toolButton"
                                  disabled={!this.haveLock()}
                                  icon
                                  labelPosition="left"
                                  color={'instagram'}
                                  onClick={() => {
                                    this.setState({
                                      isScreenShareModalOpen: true,
                                    });
                                  }}
                                >
                                  <Icon name={'slideshare'} />
                                  Screenshare
                                </Button>
                              }
                            />
                          )}
                        {!this.screenShareStream &&
                          !sharer &&
                          !this.isVBrowser() && (
                            <Popup
                              content="Launch a shared virtual browser"
                              trigger={
                                <Button
                                  fluid
                                  className="toolButton"
                                  disabled={!this.haveLock()}
                                  icon
                                  labelPosition="left"
                                  color="green"
                                  onClick={() => {
                                    this.setState({
                                      isVBrowserModalOpen: true,
                                    });
                                  }}
                                >
                                  <Icon name="desktop" />
                                  VBrowser
                                </Button>
                              }
                            />
                          )}
                        {this.isVBrowser() && (
                          <Popup
                            content="Choose the person controlling the VBrowser"
                            trigger={
                              <Dropdown
                                icon="keyboard"
                                labeled
                                className="icon"
                                style={{ height: '36px' }}
                                button
                                value={this.state.controller}
                                placeholder="No controller"
                                clearable
                                onChange={this.changeController}
                                selection
                                disabled={!this.haveLock()}
                                options={this.state.participants.map((p) => ({
                                  text: this.state.nameMap[p.id] || p.id,
                                  value: p.id,
                                }))}
                              ></Dropdown>
                            }
                          />
                        )}
                        {this.isVBrowser() && (
                          <Dropdown
                            icon="desktop"
                            labeled
                            className="icon"
                            style={{ height: '36px' }}
                            button
                            disabled={!this.haveLock()}
                            value={this.state.vBrowserResolution}
                            onChange={(_e, data) =>
                              this.setState({
                                vBrowserResolution: data.value as string,
                              })
                            }
                            selection
                            options={[
                              {
                                text: '1080p (Plus only)',
                                value: '1920x1080@30',
                                disabled: !this.state.isVBrowserLarge,
                              },
                              {
                                text: '720p',
                                value: '1280x720@30',
                              },
                              {
                                text: '576p',
                                value: '1024x576@60',
                              },
                              {
                                text: '486p',
                                value: '864x486@60',
                              },
                              {
                                text: '360p',
                                value: '640x360@60',
                              },
                            ]}
                          ></Dropdown>
                        )}
                        {this.isVBrowser() && (
                          <Button
                            fluid
                            className="toolButton"
                            icon
                            labelPosition="left"
                            color="red"
                            disabled={!this.haveLock()}
                            onClick={this.stopVBrowser}
                          >
                            <Icon name="cancel" />
                            Stop VBrowser
                          </Button>
                        )}
                        {!this.screenShareStream &&
                          !sharer &&
                          !this.isVBrowser() && (
                            <Popup
                              content="Stream your own video file"
                              trigger={
                                <Button
                                  fluid
                                  className="toolButton"
                                  disabled={!this.haveLock()}
                                  icon
                                  labelPosition="left"
                                  onClick={() => {
                                    this.setState({
                                      isFileShareModalOpen: true,
                                    });
                                  }}
                                >
                                  <Icon name="file" />
                                  File
                                </Button>
                              }
                            />
                          )}
                        {false && (
                          <SearchComponent
                            setMedia={this.setMedia}
                            playlistAdd={this.playlistAdd}
                            type={'youtube'}
                            streamPath={this.props.streamPath}
                            disabled={!this.haveLock()}
                          />
                        )}
                        {Boolean(this.props.streamPath) && (
                          <SearchComponent
                            setMedia={this.setMedia}
                            playlistAdd={this.playlistAdd}
                            type={'stream'}
                            streamPath={this.props.streamPath}
                            launchMultiSelect={this.launchMultiSelect}
                            disabled={!this.haveLock()}
                          />
                        )}
                      </div>
                      <Separator />
                    </React.Fragment>
                  )}
                  <div style={{ flexGrow: 1 }}>
                    <div id="playerContainer">
                      {(this.state.loading ||
                        !this.state.currentMedia ||
                        this.state.nonPlayableMedia) && (
                        <div
                          id="loader"
                          className="videoContent"
                          style={{
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'center',
                          }}
                        >
                          {this.state.loading && (
                            <Dimmer active>
                              <Loader>
                                {this.isVBrowser()
                                  ? 'Launching virtual browser. This can take up to a minute.'
                                  : ''}
                              </Loader>
                            </Dimmer>
                          )}
                          {!this.state.loading && !this.state.currentMedia && (
                            <Message
                              color="yellow"
                              icon="hand point up"
                              header="You're not watching anything!"
                              content="Pick something to watch above."
                            />
                          )}
                          {!this.state.loading &&
                            this.state.nonPlayableMedia && (
                              <Message
                                color="red"
                                icon="frown"
                                header="It doesn't look like this is a media file!"
                                content="Maybe you meant to launch a VBrowser if you're trying to visit a web page?"
                              />
                            )}
                        </div>
                      )}
                      <iframe
                        style={{
                          display:
                            this.isYouTube() && !this.state.loading
                              ? 'block'
                              : 'none',
                        }}
                        title="YouTube"
                        id="leftYt"
                        className="videoContent"
                        allowFullScreen
                        frameBorder="0"
                        allow="autoplay"
                        src="https://www.youtube.com/embed/?enablejsapi=1&controls=0&rel=0"
                      />
                      {this.isVBrowser() &&
                      this.getVBrowserPass() &&
                      this.getVBrowserHost() ? (
                        <VBrowser
                          username={this.socket.id}
                          password={this.getVBrowserPass()}
                          hostname={this.getVBrowserHost()}
                          controlling={this.state.controller === this.socket.id}
                          setLoadingFalse={this.setLoadingFalse}
                          resolution={this.state.vBrowserResolution}
                          doPlay={this.doPlay}
                          setResolution={(data: string) =>
                            this.setState({ vBrowserResolution: data })
                          }
                        />
                      ) : (
                        <video
                          style={{
                            display:
                              (this.isVideo() && !this.state.loading) ||
                              this.state.fullScreen
                                ? 'block'
                                : 'none',
                            width: '100%',
                            maxHeight:
                              'calc(100vh - 62px - 36px - 36px - 8px - 41px - 16px)',
                          }}
                          id="leftVideo"
                          onEnded={this.onVideoEnded}
                          playsInline
                        ></video>
                      )}
                    </div>
                  </div>
                  {this.state.currentMedia && controls}
                  {Boolean(this.state.total) && (
                    <div>
                      <Progress
                        size="tiny"
                        color="green"
                        inverted
                        value={this.state.downloaded}
                        total={this.state.total}
                        // indicating
                        label={
                          Math.min(
                            (this.state.downloaded / this.state.total) * 100,
                            100
                          ).toFixed(2) +
                          '% - ' +
                          formatSpeed(this.state.speed) +
                          ' - ' +
                          this.state.connections +
                          ' connections'
                        }
                      ></Progress>
                    </div>
                  )}
                </div>
                <Button
                  style={{
                    position: 'absolute',
                    top: '50%',
                    right: 'calc(0% - 18px)',
                    zIndex: 900,
                  }}
                  circular
                  size="mini"
                  icon={this.state.showRightBar ? 'angle right' : 'angle left'}
                  onClick={() =>
                    this.setState({ showRightBar: !this.state.showRightBar })
                  }
                />
              </Grid.Column>
              {rightBar}
            </Grid.Row>
          </Grid>
        }
      </React.Fragment>
    );
  }
Example #21
Source File: Controls.tsx    From watchparty with MIT License 4 votes vote down vote up
render() {
    const {
      togglePlay,
      onSeek,
      fullScreen,
      toggleMute,
      toggleSubtitle,
      jumpToLeader,
      currentTime,
      duration,
      leaderTime,
      isPauseDisabled,
      disabled,
      subtitled,
      paused,
    } = this.props;
    const { muted, volume } = this.state;
    const isBehind = leaderTime && leaderTime - currentTime > 5;
    return (
      <div className="controls">
        <Icon
          size="large"
          onClick={() => {
            togglePlay();
          }}
          className="control action"
          disabled={disabled || isPauseDisabled}
          name={paused ? 'play' : 'pause'}
        />
        <Popup
          content={
            (isBehind ? "We've detected that your stream is behind. " : '') +
            'Click to sync to leader.'
          }
          trigger={
            <Icon
              size="large"
              onClick={jumpToLeader}
              className={`control action ${isBehind ? 'glowing' : ''}`}
              name={'angle double right'}
            />
          }
        />
        <div className="control">{formatTimestamp(currentTime)}</div>
        <Progress
          size="tiny"
          color="blue"
          onClick={
            duration < Infinity && !this.props.disabled ? onSeek : undefined
          }
          onMouseOver={this.onMouseOver}
          onMouseOut={this.onMouseOut}
          onMouseMove={this.onMouseMove}
          className="control action"
          inverted
          style={{
            flexGrow: 1,
            marginTop: 0,
            marginBottom: 0,
            position: 'relative',
            minWidth: '50px',
          }}
          value={currentTime}
          total={duration}
        >
          {duration < Infinity && this.state.showTimestamp && (
            <div
              style={{
                position: 'absolute',
                bottom: '0px',
                left: `calc(${this.state.posTimestamp * 100 + '% - 27px'})`,
                pointerEvents: 'none',
              }}
            >
              <Label basic color="blue" pointing="below">
                <div style={{ width: '34px' }}>
                  {formatTimestamp(this.state.currTimestamp)}
                </div>
              </Label>
            </div>
          )}
        </Progress>
        <div className="control">{formatTimestamp(duration)}</div>
        <Icon
          size="large"
          onClick={() => {
            toggleSubtitle();
          }}
          className="control action"
          name={subtitled ? 'closed captioning' : 'closed captioning outline'}
          title="Captions"
        />
        <Icon
          size="large"
          onClick={() => fullScreen(false)}
          className="control action"
          style={{ transform: 'rotate(90deg)' }}
          name="window maximize outline"
          title="Theater Mode"
        />
        <Icon
          size="large"
          onClick={() => fullScreen(true)}
          className="control action"
          name="expand"
          title="Fullscreen"
        />
        <Icon
          size="large"
          onClick={() => {
            toggleMute();
            this.setState({ muted: !this.state.muted });
          }}
          className="control action"
          name={muted ? 'volume off' : 'volume up'}
          title="Mute"
        />
        <div style={{ width: '100px', marginRight: '10px' }}>
          <Slider
            value={volume}
            color="blue"
            settings={{
              min: 0,
              max: 1,
              step: 0.01,
              onChange: (value: number) => {
                this.setState({ volume: value });
                this.props.setVolume(value);
              },
            }}
          />
        </div>
      </div>
    );
  }
Example #22
Source File: AppHeader.tsx    From peterportal-client with MIT License 4 votes vote down vote up
AppHeader: FC<{}> = props => {
  const dispatch = useAppDispatch();
  const sidebarOpen = useAppSelector(state => state.ui.sidebarOpen);
  const location = useLocation();
  const [week, setWeek] = useState('');

  let splitLocation = location.pathname.split('/');
  let coursesActive = splitLocation.length > 0 && splitLocation[splitLocation.length - 1] == 'courses' || splitLocation.length > 1 && splitLocation[1] == 'course';
  let professorsActive = splitLocation.length > 0 && splitLocation[splitLocation.length - 1] == 'professors' || splitLocation.length > 1 && splitLocation[1] == 'professor';

  useEffect(() => {
    // Get the current week data
    axios.get<WeekData>('/schedule/api/currentWeek')
      .then(res => {
        // case for break and finals week
        if (res.data.week == -1) {
          setWeek(res.data.display);
        }
        // case when school is in session 
        else {
          setWeek('Week ' + res.data.week + ' • ' + res.data.quarter);
        }
      });
  }, [])

  let toggleMenu = () => {
    dispatch(setSidebarStatus(!sidebarOpen));
  }

  return (
    <header className='navbar'>
      <div className='navbar-nav'>
        <div className='navbar-left'>
          {/* Hamburger Menu */}
          <div className='navbar-menu'>
            <List className='navbar-menu-icon' onClick={toggleMenu} />
          </div>

          {/* Toggle Course and Professor */}
          {(coursesActive || professorsActive) && <div className='navbar-toggle'>
            <div className='desktop-toggle'>
              <div className={`navbar-toggle-item ${coursesActive ? 'active' : ''}`}>
                <a href='/search/courses'>
                  Courses
                </a>
              </div>
              <div className={`navbar-toggle-item ${professorsActive ? 'active' : ''}`}>
                <a href='/search/professors'>
                  Professors
                </a>
              </div>
            </div>
            <div className='mobile-toggle'>
              {coursesActive === true && (
                <div className={`navbar-toggle-item active`}>
                  <a href='/search/professors'>
                    Professors
                  </a>
                </div>
              )}
              {professorsActive === true && (
                <div className={`navbar-toggle-item active`}>
                  <a href='/search/courses'>
                    Courses
                  </a>
                </div>
              )}
            </div>
          </div>
          }
        </div>

        {/* Logo */}
        <div className='navbar-logo'>
          <a href='/'>
            <img alt='PeterPortal' id='peterportal-logo' src={Logo}></img>
          </a>
        </div>

        {/* Week */}
        <div style={{ display: 'flex', alignItems: 'center' }}>
          <div className='beta' style={{ margin: "auto 12px" }}>
            <Popup style={{ padding: "36px", width: "400px" }} position='bottom right' trigger={<Label as='a' color='yellow' image>beta<Label.Detail>v1.1</Label.Detail></Label>} flowing hoverable >
              <Grid centered columns={1}>
                <Grid.Column textAlign='left'>
                  <h4>Beta Disclaimer</h4>
                  <p>
                    Please note that this is a beta version of PeterPortal, which is still undergoing development.
                    Some content on this web application may not be accurate. Users are encouraged to double check details.
                    <br />
                    <br />
                    Should you encounter any bugs, glitches, lack of functionality or other problems on the application,
                    please let us know immediately so we can rectify these accordingly. Your help in this regard is greatly appreciated.
                  </p>
                  <div className='feedback'>
                    <a className="ui button" href="https://github.com/icssc-projects/peterportal-client/issues/new" target="_blank" rel="noopener noreferrer">
                      <Icon name='github' />Report an issue
                    </a>
                    <a className="ui button" href="https://forms.gle/JjwBmELq26daroTh9" target="_blank" rel="noopener noreferrer">
                      <Icon name='clipboard list' />Feedback
                    </a>
                  </div>
                </Grid.Column>
              </Grid>
            </Popup>
          </div>
          <p className='school-term' style={{ height: '1rem', lineHeight: '1rem' }}>
            {week}
          </p>
        </div>
      </div>
    </header>
  );
}
Example #23
Source File: commoncrewdata.tsx    From website with MIT License 4 votes vote down vote up
renderOtherRanks(crew, roster = false) {
		let v = [];
		let g = [];
		let b = [];

		const skillName = short => CONFIG.SKILLS[CONFIG.SKILLS_SHORT.find(c => c.short === short).name];
		const rankHandler = rank => roster
			? roster.filter(c => c.ranks[rank] && crew.ranks[rank] > c.ranks[rank]).length + 1
			: crew.ranks[rank];
		const tripletHandler = rank => roster
			? roster.filter(c => c.ranks[rank] &&
													 c.ranks[rank].name == crew.ranks[rank].name &&
													 crew.ranks[rank].rank > c.ranks[rank].rank).length + 1
			: crew.ranks[rank].rank;

		// Need to filter by skills first before sorting by voyage triplet
		const tripletFilter = crew.ranks.voyTriplet
								? crew.ranks.voyTriplet.name.split('/')
									.map(s => 'skill:'+s.trim())
									.reduce((prev, curr) => prev+' '+curr)
								: '';

		for (let rank in crew.ranks) {
			if (rank.startsWith('V_')) {
				v.push(
					<Statistic key={rank}>
						<Statistic.Label>{rank.substr(2).replace('_', ' / ')}</Statistic.Label>
						<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, 'ranks.'+rank)}</Statistic.Value>
					</Statistic>
				);
			} else if (rank.startsWith('G_')) {
				g.push(
					<Statistic key={rank}>
						<Statistic.Label>{rank.substr(2).replace('_', ' / ')}</Statistic.Label>
						<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, 'ranks.'+rank)}</Statistic.Value>
					</Statistic>
				);
			} else if (rank.startsWith('B_') && crew.ranks[rank]) {
				b.push(
					<Statistic key={rank}>
						<Statistic.Label>{skillName(rank.substr(2))}</Statistic.Label>
						<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, CONFIG.SKILLS_SHORT.find(c => c.short === rank.substr(2)).name, 'descending')}</Statistic.Value>
					</Statistic>
				);
			}
		}

		return (
			<React.Fragment>
				<Segment>
					<Header as="h5">Base ranks</Header>
					<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
						{b}
					</Statistic.Group>
				</Segment>
				<Segment>
					<Header as="h5">Voyage skill ranks</Header>
					{crew.ranks.voyTriplet && (
						<React.Fragment>
							<Statistic.Group widths="one" size={'mini'}>
								<Statistic>
									<Statistic.Label>{crew.ranks.voyTriplet.name}</Statistic.Label>
									<Statistic.Value>{rankLinker(roster, tripletHandler('voyTriplet'), crew.symbol, 'ranks.voyRank', 'ascending', tripletFilter)}</Statistic.Value>
								</Statistic>
							</Statistic.Group>
							<Divider />
						</React.Fragment>
				)}
					<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
						{v}
					</Statistic.Group>
				</Segment>
				<Segment>
					<Header as="h5">Gauntlet pair ranks</Header>
					<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
						{g}
					</Statistic.Group>
				</Segment>
			</React.Fragment>
		);
	}
Example #24
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 #25
Source File: SettingsTab.tsx    From watchparty with MIT License 4 votes vote down vote up
SettingsTab = ({
  hide,
  user,
  roomLock,
  setRoomLock,
  socket,
  isSubscriber,
  owner,
  vanity,
  setVanity,
  roomLink,
  password,
  setPassword,
  isChatDisabled,
  setIsChatDisabled,
  clearChat,
  roomTitle,
  roomDescription,
  roomTitleColor,
  mediaPath,
  setMediaPath,
}: SettingsTabProps) => {
  const [updateTS, setUpdateTS] = useState(0);
  const [permModalOpen, setPermModalOpen] = useState(false);
  const [validVanity, setValidVanity] = useState(true);
  const [validVanityLoading, setValidVanityLoading] = useState(false);
  const [adminSettingsChanged, setAdminSettingsChanged] = useState(false);
  const [roomTitleInput, setRoomTitleInput] = useState<string | undefined>(undefined);
  const [roomDescriptionInput, setRoomDescriptionInput] = useState<
    string | undefined
  >(undefined);
  const [roomTitleColorInput, setRoomTitleColorInput] = useState<
    string | undefined
  >('');

  const setRoomState = useCallback(
    async (data: any) => {
      const token = await user?.getIdToken();
      socket.emit('CMD:setRoomState', {
        uid: user?.uid,
        token,
        ...data,
      });
    },
    [socket, user]
  );
  const setRoomOwner = useCallback(
    async (data: any) => {
      const token = await user?.getIdToken();
      socket.emit('CMD:setRoomOwner', {
        uid: user?.uid,
        token,
        ...data,
      });
    },
    [socket, user]
  );
  const checkValidVanity = useCallback(
    async (input: string) => {
      if (!input) {
        setValidVanity(true);
        return;
      }
      setValidVanity(false);
      setValidVanityLoading(true);
      const response = await axios.get(serverPath + '/resolveRoom/' + input);
      const data = response.data;
      setValidVanityLoading(false);
      if (
        data &&
        data.vanity &&
        data.vanity !== roomLink.split('/').slice(-1)[0]
      ) {
        // Already exists and doesn't match current room
        setValidVanity(false);
      } else {
        setValidVanity(true);
      }
    },
    [setValidVanity, roomLink]
  );
  const disableLocking =
    !Boolean(user) || Boolean(roomLock && roomLock !== user?.uid);
  const disableOwning = !Boolean(user) || Boolean(owner && owner !== user?.uid);

  return (
    <div
      style={{
        display: hide ? 'none' : 'block',
        color: 'white',
        overflow: 'scroll',
        padding: '8px',
      }}
    >
      {permModalOpen && (
        <PermanentRoomModal
          closeModal={() => setPermModalOpen(false)}
        ></PermanentRoomModal>
      )}
      <div className="sectionHeader">Room Settings</div>
      {!user && (
        <Message color="yellow" size="tiny">
          You need to be signed in to change these settings.
        </Message>
      )}
      <SettingRow
        icon={roomLock ? 'lock' : 'lock open'}
        name={`Lock Room`}
        description="Only the person who locked the room can control the video."
        checked={Boolean(roomLock)}
        disabled={disableLocking && disableOwning}
        onChange={(_e, data) => setRoomLock(data.checked)}
      />
      {
        <SettingRow
          icon={'clock'}
          name={`Make Room Permanent`}
          description={
            'Prevent this room from expiring. This also unlocks additional room features.'
          }
          helpIcon={
            <Icon
              name="help circle"
              onClick={() => setPermModalOpen(true)}
              style={{ cursor: 'pointer' }}
            ></Icon>
          }
          checked={Boolean(owner)}
          disabled={disableOwning}
          onChange={(_e, data) => setRoomOwner({ undo: !data.checked })}
        />
      }
      {owner && owner === user?.uid && (
        <div className="sectionHeader">Admin Settings</div>
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'key'}
          name={`Set Room Password`}
          description="Users must know this password in order to join the room."
          content={
            <Input
              value={password}
              size="mini"
              onChange={(e) => {
                setAdminSettingsChanged(true);
                setPassword(e.target.value);
              }}
              fluid
            />
          }
          disabled={false}
        />
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'folder'}
          name={`Set Room Media Source`}
          description="Set a media source URL with files to replace the default examples. Supports S3 buckets and nginx file servers."
          content={
            <Input
              value={mediaPath}
              size="mini"
              onChange={(e) => {
                setAdminSettingsChanged(true);
                setMediaPath(e.target.value);
              }}
              fluid
            />
          }
          disabled={false}
        />
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'i cursor'}
          name={`Disable Chat`}
          description="Prevent users from sending messages in chat."
          checked={Boolean(isChatDisabled)}
          disabled={false}
          onChange={(_e, data) => {
            setAdminSettingsChanged(true);
            setIsChatDisabled(Boolean(data.checked));
          }}
        />
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'i delete'}
          name={`Clear Chat`}
          description="Delete all existing chat messages"
          disabled={false}
          content={
            <Button
              color="red"
              icon
              labelPosition="left"
              onClick={() => clearChat()}
            >
              <Icon name="delete" />
              Delete Messages
            </Button>
          }
        />
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'linkify'}
          name={`Set Custom Room URL`}
          description="Set a custom URL for this room. Inappropriate names may be revoked."
          checked={Boolean(roomLock)}
          disabled={!isSubscriber}
          subOnly={true}
          content={
            <React.Fragment>
              <Input
                value={vanity}
                disabled={!isSubscriber}
                onChange={(e) => {
                  setAdminSettingsChanged(true);
                  checkValidVanity(e.target.value);
                  setVanity(e.target.value);
                }}
                label={<Label>{`${window.location.origin}/r/`}</Label>}
                loading={validVanityLoading}
                fluid
                size="mini"
                icon
                action={
                  validVanity ? (
                    <Icon name="checkmark" color="green" />
                  ) : (
                    <Icon name="close" color="red" />
                  )
                }
              ></Input>
            </React.Fragment>
          }
        />
      )}
      {owner && owner === user?.uid && (
        <SettingRow
          icon={'pencil'}
          name={`Set Room Title, Description & Color`}
          description="Set the room title, description and title color to be displayed in the top bar."
          disabled={!isSubscriber}
          subOnly={true}
          content={
            <React.Fragment>
              <div style={{ display: 'flex', marginBottom: 2 }}>
                <Input
                  style={{ marginRight: 3, flexGrow: 1 }}
                  value={roomTitleInput ?? roomTitle}
                  disabled={!isSubscriber}
                  maxLength={roomTitleMaxCharLength}
                  onChange={(e) => {
                    setAdminSettingsChanged(true);
                    setRoomTitleInput(e.target.value);
                  }}
                  placeholder={`Title (max. ${roomTitleMaxCharLength} characters)`}
                  fluid
                  size="mini"
                  icon
                ></Input>
                <Popup
                  content={
                    <React.Fragment>
                      <h5>Edit Title Color</h5>
                      <HexColorPicker
                        color={
                          roomTitleColorInput ||
                          roomTitleColor ||
                          defaultRoomTitleColor
                        }
                        onChange={(e) => {
                          setAdminSettingsChanged(true);
                          setRoomTitleColorInput(e);
                        }}
                      />
                      <div
                        style={{
                          marginTop: 8,
                          paddingLeft: 4,
                          borderLeft: `24px solid ${roomTitleColorInput}`,
                        }}
                      >
                        {roomTitleColorInput?.toUpperCase()}
                      </div>
                    </React.Fragment>
                  }
                  on="click"
                  trigger={
                    <Button
                      icon
                      color="teal"
                      size="tiny"
                      style={{ margin: 0 }}
                      disabled={!isSubscriber}
                    >
                      <Icon name="paint brush" />
                    </Button>
                  }
                />
              </div>
              <Input
                style={{ marginBottom: 2 }}
                value={roomDescriptionInput ?? roomDescription}
                disabled={!isSubscriber}
                maxLength={roomDescriptionMaxCharLength}
                onChange={(e) => {
                  setAdminSettingsChanged(true);
                  setRoomDescriptionInput(e.target.value);
                }}
                placeholder={`Description (max. ${roomDescriptionMaxCharLength} characters)`}
                fluid
                size="mini"
                icon
              ></Input>
            </React.Fragment>
          }
        />
      )}
      <div
        style={{
          borderTop: '3px dashed white',
          marginTop: 10,
          marginBottom: 10,
        }}
      />
      {owner && owner === user?.uid && (
        <Button
          primary
          disabled={!validVanity || !adminSettingsChanged}
          labelPosition="left"
          icon
          fluid
          onClick={() => {
            setRoomState({
              vanity: vanity,
              password: password,
              isChatDisabled: isChatDisabled,
              roomTitle: roomTitleInput ?? roomTitle,
              roomDescription: roomDescriptionInput ?? roomDescription,
              roomTitleColor:
                roomTitleColorInput || roomTitleColor || defaultRoomTitleColor,
              mediaPath: mediaPath,
            });
            setAdminSettingsChanged(false);
          }}
        >
          <Icon name="save" />
          Save Admin Settings
        </Button>
      )}
      <div className="sectionHeader">Local Settings</div>
      <SettingRow
        updateTS={updateTS}
        icon="bell"
        name="Disable chat notification sound"
        description="Don't play a sound when a chat message is sent while you're on another tab"
        checked={Boolean(getCurrentSettings().disableChatSound)}
        disabled={false}
        onChange={(_e, data) => {
          updateSettings(
            JSON.stringify({
              ...getCurrentSettings(),
              disableChatSound: data.checked,
            })
          );
          setUpdateTS(Number(new Date()));
        }}
      />
    </div>
  );
}
Example #26
Source File: ProfileWidgetPlus.tsx    From communitymap-ui with Apache License 2.0 4 votes vote down vote up
ProfileWidgetPlus: React.FC = () => {
  const user = useAuth();
  const { dialogs } = useMyDirectMessages();
  const unreadDialogs =
    dialogs?.filter((dlg) => dlg.lastMsgId !== dlg.lastReadBy[user?.uid || ''])
      .length || 0;

  const [login, setLogin] = useState(false);
  useEffect(() => {
    if (user && login) {
      setLogin(false);
    }
  }, [user, login]);

  const [showProfile, setShowProfile] = useState(false);

  const signOut = () => getFirebaseApp().auth().signOut();

  return (
    <div id="profile-widget">
      {login && <Login title="" onClose={() => setLogin(false)} />}
      {showProfile && !!user && (
        <Modal open closeIcon onClose={() => setShowProfile(false)}>
          <Modal.Header>Your profile</Modal.Header>
          <Modal.Content>
            <EditUserProfile user={user} />
          </Modal.Content>
        </Modal>
      )}
      {user ? (
        <Dropdown
          trigger={
            <Button className="profile-button" icon size="large">
              <Icon.Group>
                <Icon name="user outline" />
                {unreadDialogs > 0 && (
                  <Icon
                    corner="top right"
                    className="has-unread-messages"
                    name="mail"
                    color="red"
                  />
                )}
              </Icon.Group>
            </Button>
          }
          pointing="top right"
          icon={null}
        >
          <Dropdown.Menu>
            <Dropdown.Item disabled>{user.email}</Dropdown.Item>
            <Dropdown.Divider />
            <Dropdown.Item onClick={() => setShowProfile(true)}>
              <Icon name="user" />
              Profile
            </Dropdown.Item>
            <Dropdown.Item as={Link} to="/my-messages">
              <Icon name="mail" />
              Messages
              {unreadDialogs > 0 && (
                <Label className="user-menu-label" color="blue">
                  {unreadDialogs}
                </Label>
              )}
            </Dropdown.Item>
            <Dropdown.Divider />
            <Dropdown.Item as={Link} to="/terms">
              Terms of Service
            </Dropdown.Item>
            <Dropdown.Item as={Link} to="/privacy">
              Privacy Policy
            </Dropdown.Item>
            <Dropdown.Divider />
            <Dropdown.Item onClick={signOut}>
              <Icon name="log out" />
              Log out
            </Dropdown.Item>
          </Dropdown.Menu>
        </Dropdown>
      ) : (
        // <Button primary size="large" onClick={() => setLogin(true)}>
        //   Sign in
        // </Button>
        <Dropdown
          trigger={
            <Button className="profile-button" icon size="large">
              <Icon name="bars" />
            </Button>
          }
          pointing="top right"
          icon={null}
        >
          <Dropdown.Menu>
            <Dropdown.Item as={Link} to="/terms">
              Terms of Service
            </Dropdown.Item>
            <Dropdown.Item as={Link} to="/privacy">
              Privacy Policy
            </Dropdown.Item>
            <Dropdown.Divider />
            <Dropdown.Item onClick={() => setLogin(true)}>
              <Icon name="sign in" />
              Sign in
            </Dropdown.Item>
          </Dropdown.Menu>
        </Dropdown>
      )}
    </div>
  );
}
Example #27
Source File: CourseQuarterIndicator.tsx    From peterportal-client with MIT License 4 votes vote down vote up
CourseQuarterIndicator: FC<CourseQuarterIndicatorProps> = (props) => {
  return (
    <div style={{ display: 'flex', marginLeft: 'auto' }}>
      {props.terms.length > 0 && (
        <Popup
          trigger={
            <div style={{ display: 'inline' }}>
              {props.terms.includes('2020 Fall') && (
                <span style={{ float: 'right', marginLeft: '4px' }}>
                  <Label circular color='yellow' empty />
                </span>
              )}

              {props.terms.includes('2020 Summer2') && (
                <span style={{ float: 'right', marginLeft: '4px' }}>
                  <Label circular color='violet' empty />
                </span>
              )}

              {props.terms.includes('2020 Summer10wk') && (
                <span style={{ float: 'right', marginLeft: '4px' }}>
                  <Label circular color='green' empty />
                </span>
              )}

              {props.terms.includes('2020 Summer1') && (
                <span style={{ float: 'right', marginLeft: '4px' }}>
                  <Label circular color='orange' empty />
                </span>
              )}

              {props.terms.includes('2020 Spring') && (
                <span style={{ float: 'right', marginLeft: '4px' }}>
                  <Label circular color='teal' empty />
                </span>
              )}
            </div>
          }
          content={
            <div style={{ display: 'flex', flexDirection: 'column' }}>
              <h5 style={{ marginBottom: '4px' }}>Offered in:</h5>
              {props.terms.includes('2020 Fall') && (
                <div style={{ float: 'right' }}>
                  <Label circular color='yellow' empty />
                  <span style={{ marginLeft: '6px' }}>Fall 2020</span>
                </div>
              )}

              {props.terms.includes('2020 Summer2') && (
                <div style={{ float: 'right' }}>
                  <Label circular color='violet' empty />
                  <span style={{ marginLeft: '6px' }}>SS II 2020</span>
                </div>
              )}

              {props.terms.includes('2020 Summer10wk') && (
                <div style={{ float: 'right' }}>
                  <Label circular color='green' empty />
                  <span style={{ marginLeft: '6px' }}>SS 10wk 2020</span>
                </div>
              )}

              {props.terms.includes('2020 Summer1') && (
                <div style={{ float: 'right' }}>
                  <Label circular color='orange' empty />
                  <span style={{ marginLeft: '6px' }}>SS I 2020</span>
                </div>
              )}

              {props.terms.includes('2020 Spring') && (
                <div style={{ float: 'right' }}>
                  <Label circular color='teal' empty />
                  <span style={{ marginLeft: '6px' }}>Spring 2020</span>
                </div>
              )}
            </div>
          }
          basic
          position='bottom right'
        />
      )}
    </div>
  )
}