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