string, 'location' => string, ); type NavSection = shape( 'name' => string, 'location' => ?string, 'items' => Vector, ); final class :hack:nav extends :x:element { private function getNavSections(): Vector { return Vector{ shape( 'name' => 'Home', 'location' => '/', 'items' => Vector {}, ), shape( 'name' => 'GitHub', 'location' => 'http://github.com/facebook/hack-example-site', 'items' => Vector {}, ), shape( 'name' => 'Recipes', 'location' => null, 'items' => Vector { shape( 'name' => '$_GET and $_POST', 'location' => '/recipes/get-and-post/', ), shape( 'name' => 'Assert', 'location' => '/recipes/assert/', ), shape( 'name' => 'DB Result', 'location' => '/recipes/db-result/', ), shape( 'name' => 'Unescaped String', 'location' => '/recipes/unescaped-string/', ), shape( 'name' => 'User ID', 'location' => '/recipes/user-id/', ), }, ), }; } private function renderNavItems(Vector $items): :xhp { $render_item = $item ==>
  • {$item['name']}
  • ; return {$items->map($render_item)->toArray()} ; } private function renderNavSection(NavSection $section): :xhp { $section_item = ; if ($section['location'] !== null) { $section_item = {$section_item}; } return ; } public function render(): :xhp { $sections = $this->getNavSections() ->map($section ==> $this->renderNavSection($section)); return ; } }