github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/web/src/HeaderBar.tsx (about) 1 import React from "react" 2 import { Link } from "react-router-dom" 3 import styled from "styled-components" 4 import { AnalyticsType } from "./analytics" 5 import { ReactComponent as DetailViewSvg } from "./assets/svg/detail-view-icon.svg" 6 import { ReactComponent as LogoWordmarkSvg } from "./assets/svg/logo-wordmark.svg" 7 import { ReactComponent as TableViewSvg } from "./assets/svg/table-view-icon.svg" 8 import { CustomNav } from "./CustomNav" 9 import { GlobalNav, GlobalNavProps } from "./GlobalNav" 10 import { usePathBuilder } from "./PathBuilder" 11 import { 12 AllResourceStatusSummary, 13 ResourceStatusSummaryRoot, 14 } from "./ResourceStatusSummary" 15 import { useSnapshotAction } from "./snapshot" 16 import { SnapshotBar } from "./SnapshotBar" 17 import { AnimDuration, Color, Font, FontSize, SizeUnit } from "./style-helpers" 18 import { showUpdate } from "./UpdateDialog" 19 20 const HeaderBarRoot = styled.nav` 21 display: flex; 22 align-items: center; 23 padding-left: ${SizeUnit(1)}; 24 background-color: ${Color.gray10}; 25 26 ${ResourceStatusSummaryRoot} { 27 justify-self: center; 28 flex-grow: 1; 29 justify-content: center; 30 } 31 ` 32 33 const Logo = styled(LogoWordmarkSvg)` 34 justify-self: flex-start; 35 & .fillStd { 36 transition: fill ${AnimDuration.short} ease; 37 fill: ${Color.grayLightest}; 38 } 39 &:hover .fillStd, 40 &.isSelected .fillStd { 41 fill: ${Color.gray70}; 42 } 43 display: block; 44 ` 45 46 const HeaderDivider = styled.div` 47 border-left: 1px solid ${Color.gray40}; 48 height: ${SizeUnit(0.7)}; 49 margin: ${SizeUnit(0.5)}; 50 ` 51 52 const ViewLinkText = styled.span` 53 bottom: 0; 54 color: ${Color.gray70}; 55 font-family: ${Font.monospace}; 56 font-size: ${FontSize.smallest}; 57 opacity: 0; 58 position: absolute; 59 transition: opacity ${AnimDuration.default} ease; 60 white-space: nowrap; 61 width: 100%; 62 ` 63 64 const viewLinkIconMixin = ` 65 display: flex; 66 transition: fill ${AnimDuration.default} ease; 67 height: 100%; 68 padding: ${SizeUnit(0.65)} 0; 69 fill: ${Color.gray50}; 70 71 &.isCurrent { 72 fill: ${Color.gray70}; 73 } 74 ` 75 76 const TableViewIcon = styled(TableViewSvg)` 77 ${viewLinkIconMixin} 78 /* "Hack" to right-align text */ 79 padding-left: ${SizeUnit(0.5)}; 80 ` 81 82 const DetailViewIcon = styled(DetailViewSvg)` 83 ${viewLinkIconMixin} 84 ` 85 86 const ViewLink = styled(Link)` 87 position: relative; 88 89 &:is(:hover, :focus, :active) { 90 ${ViewLinkText} { 91 opacity: 1; 92 } 93 94 ${TableViewIcon}, ${DetailViewIcon} { 95 fill: ${Color.blue}; 96 } 97 } 98 ` 99 100 const ViewLinkSection = styled.div` 101 align-items: center; 102 display: flex; 103 margin-left: ${SizeUnit(1)}; 104 margin-right: ${SizeUnit(1)}; 105 ` 106 107 type HeaderBarProps = { 108 view: Proto.webviewView 109 isSocketConnected: boolean 110 currentPage?: AnalyticsType.Detail | AnalyticsType.Grid 111 } 112 113 export default function HeaderBar({ 114 view, 115 currentPage, 116 isSocketConnected, 117 }: HeaderBarProps) { 118 let isSnapshot = usePathBuilder().isSnapshot() 119 let snapshot = useSnapshotAction() 120 let session = view?.uiSession?.status 121 let runningBuild = session?.runningTiltBuild 122 let suggestedVersion = session?.suggestedTiltVersion 123 let resources = view?.uiResources || [] 124 125 let globalNavProps: GlobalNavProps = { 126 isSnapshot, 127 snapshot, 128 showUpdate: showUpdate(view), 129 suggestedVersion, 130 runningBuild, 131 clusterConnections: view.clusters, 132 } 133 134 const pb = usePathBuilder() 135 136 const tableViewLinkClass = 137 currentPage === AnalyticsType.Grid ? "isCurrent" : "" 138 const detailViewLinkClass = 139 currentPage === AnalyticsType.Detail ? "isCurrent" : "" 140 141 // TODO (lizz): Consider refactoring nav to use more semantic pattern of ul + li 142 return ( 143 <> 144 <SnapshotBar className={`is-${currentPage}`} /> 145 <HeaderBarRoot aria-label="Dashboard menu"> 146 <Link to="/overview" aria-label="Tilt home"> 147 <Logo width="57px" /> 148 </Link> 149 <ViewLinkSection> 150 <ViewLink 151 to="/overview" 152 aria-label="Table view" 153 aria-current={currentPage === AnalyticsType.Grid} 154 > 155 <TableViewIcon className={tableViewLinkClass} role="presentation" /> 156 <ViewLinkText>Table</ViewLinkText> 157 </ViewLink> 158 <HeaderDivider role="presentation" /> 159 <ViewLink 160 to={pb.encpath`/r/(all)/overview`} 161 aria-label="Detail view" 162 aria-current={currentPage === AnalyticsType.Detail} 163 > 164 <DetailViewIcon 165 className={detailViewLinkClass} 166 role="presentation" 167 /> 168 <ViewLinkText>Detail</ViewLinkText> 169 </ViewLink> 170 </ViewLinkSection> 171 <AllResourceStatusSummary 172 displayText="Resources" 173 labelText="Status summary for all resources" 174 resources={resources} 175 isSocketConnected={isSocketConnected} 176 /> 177 <CustomNav view={view} /> 178 <GlobalNav {...globalNavProps} /> 179 </HeaderBarRoot> 180 </> 181 ) 182 }