-
Notifications
You must be signed in to change notification settings - Fork 0
[NO TICKET] Add shebangs for commands & refactor serach modal component #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
4341bd1
feat(SearchModal): Add search mode
TylerAdamMartinez 8f93ff6
fix(SearchModal): Patch docs search
TylerAdamMartinez 1bdd5ec
refactor(SearchModal): Broke logic into a hook & results into components
TylerAdamMartinez 5a42dbf
chore(SearchModal): Remove shebang prompt to keep easter egg hidden
TylerAdamMartinez File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import { Box, Stack, Typography } from '@mui/material' | ||
| import { Description } from '@mui/icons-material' | ||
| import { COMMANDS } from '@/utils/searchModal' | ||
|
|
||
| type CommandKey = (typeof COMMANDS)[number]['key'] | ||
|
|
||
| type CommandResultsProps = { | ||
| commands: readonly { | ||
| key: CommandKey | ||
| label: string | ||
| description: string | ||
| }[] | ||
| onSelect: (command: CommandKey) => void | ||
| } | ||
|
|
||
| export const CommandResults = ({ | ||
| commands, | ||
| onSelect, | ||
| }: CommandResultsProps) => ( | ||
| <Box sx={{ py: 1 }}> | ||
| <Stack sx={{ px: 1.5, pb: 0.5 }}> | ||
| <Typography | ||
| variant="overline" | ||
| sx={{ color: 'text.disabled', fontSize: 10, letterSpacing: 1 }} | ||
| > | ||
| Commands | ||
| </Typography> | ||
| </Stack> | ||
|
|
||
| {commands.map((command) => ( | ||
| <Box | ||
| key={command.key} | ||
| onClick={() => onSelect(command.key)} | ||
| sx={{ | ||
| display: 'flex', | ||
| alignItems: 'flex-start', | ||
| gap: 1.5, | ||
| px: 1.5, | ||
| py: 1, | ||
| borderRadius: 1, | ||
| cursor: 'pointer', | ||
| '&:hover': { bgcolor: 'action.hover' }, | ||
| }} | ||
| > | ||
| <Description | ||
| sx={{ | ||
| fontSize: 18, | ||
| color: 'text.secondary', | ||
| flexShrink: 0, | ||
| mt: '2px', | ||
| }} | ||
| /> | ||
| <Box sx={{ minWidth: 0, flex: 1 }}> | ||
| <Typography variant="body2" fontWeight={600}> | ||
| {command.label} | ||
| </Typography> | ||
| <Typography variant="caption" color="text.secondary"> | ||
| {command.description} | ||
| </Typography> | ||
| </Box> | ||
| </Box> | ||
| ))} | ||
| </Box> | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| import { Box, Chip, Divider, Typography } from '@mui/material' | ||
| import { Description, Opacity, Person } from '@mui/icons-material' | ||
| import { GroupType } from '@/constants' | ||
| import { ContactResult, SearchResult, WellResult } from '@/interfaces/ocotillo' | ||
| import { highlight } from '@/utils' | ||
|
|
||
| const TypeIcon = ({ group }: { group: GroupType }) => { | ||
| const sx = { fontSize: 18, color: 'text.secondary', flexShrink: 0, mt: '2px' } | ||
|
|
||
| switch (group) { | ||
| case GroupType.Wells: | ||
| case GroupType.Springs: | ||
| return <Opacity sx={sx} /> | ||
| case GroupType.Contacts: | ||
| return <Person sx={sx} /> | ||
| case GroupType.Assets: | ||
| return <Description sx={sx} /> | ||
| default: | ||
| return null | ||
| } | ||
| } | ||
|
|
||
| const buildSubtitle = (option: SearchResult): string | null => { | ||
| if (option.group === GroupType.Wells || option.group === GroupType.Springs) { | ||
| const properties = (option as WellResult).properties | ||
| const parts: string[] = [] | ||
|
|
||
| if (properties.owner_name) parts.push(`Owner: ${properties.owner_name}`) | ||
| if (properties.county) parts.push(properties.county) | ||
| if (properties.site_name) parts.push(properties.site_name) | ||
| if (properties.thing_type) parts.push(properties.thing_type) | ||
| if (properties.well_depth) | ||
| parts.push(`${properties.well_depth.toFixed(0)} ft`) | ||
| if (properties.hole_depth) { | ||
| parts.push(`hole ${properties.hole_depth.toFixed(0)} ft`) | ||
| } | ||
| if (properties.well_purposes?.length) | ||
| parts.push(...properties.well_purposes) | ||
|
|
||
| return parts.length ? parts.join(' · ') : null | ||
| } | ||
|
|
||
| if (option.group === GroupType.Contacts) { | ||
| const properties = (option as ContactResult).properties | ||
| const parts: string[] = [] | ||
|
|
||
| if (properties.phone?.length) parts.push(properties.phone[0]) | ||
| if (properties.address?.length) parts.push(properties.address[0]) | ||
|
|
||
| return parts.length ? parts.join(' · ') : null | ||
| } | ||
|
|
||
| return null | ||
| } | ||
|
|
||
| const RelatedThings = ({ | ||
| things, | ||
| query, | ||
| }: { | ||
| things: { id: number; label: string; thing_type: string }[] | ||
| query: string | ||
| }) => { | ||
| if (!things?.length) return null | ||
|
|
||
| return ( | ||
| <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5, mt: 0.5 }}> | ||
| {things.slice(0, 4).map((thing) => ( | ||
| <Chip | ||
| key={thing.id} | ||
| size="small" | ||
| icon={<Opacity sx={{ fontSize: '12px !important' }} />} | ||
| label={highlight(thing.label, query)} | ||
| variant="outlined" | ||
| sx={{ fontSize: 11 }} | ||
| /> | ||
| ))} | ||
| {things.length > 4 && ( | ||
| <Chip | ||
| size="small" | ||
| label={`+${things.length - 4} more`} | ||
| variant="outlined" | ||
| sx={{ fontSize: 11 }} | ||
| /> | ||
| )} | ||
| </Box> | ||
| ) | ||
| } | ||
|
|
||
| const ResultRow = ({ | ||
| option, | ||
| query, | ||
| onClick, | ||
| }: { | ||
| option: SearchResult | ||
| query: string | ||
| onClick: () => void | ||
| }) => { | ||
| const subtitle = buildSubtitle(option) | ||
| const relatedThings = | ||
| option.group === GroupType.Contacts | ||
| ? (option as ContactResult).properties.things | ||
| : option.group === GroupType.Assets | ||
| ? (option as any).properties?.things | ||
| : null | ||
|
|
||
| return ( | ||
| <Box | ||
| onClick={onClick} | ||
| sx={{ | ||
| display: 'flex', | ||
| alignItems: 'flex-start', | ||
| gap: 1.5, | ||
| px: 1.5, | ||
| py: 1, | ||
| borderRadius: 1, | ||
| cursor: 'pointer', | ||
| '&:hover': { bgcolor: 'action.hover' }, | ||
| }} | ||
| > | ||
| <TypeIcon group={option.group} /> | ||
| <Box sx={{ minWidth: 0, flex: 1 }}> | ||
| <Typography variant="body2" fontWeight={600} sx={{ lineHeight: 1.4 }}> | ||
| {highlight(option.label, query)} | ||
| </Typography> | ||
| {subtitle && ( | ||
| <Typography | ||
| variant="caption" | ||
| color="text.secondary" | ||
| sx={{ lineHeight: 1.4, display: 'block' }} | ||
| > | ||
| {subtitle} | ||
| </Typography> | ||
| )} | ||
| {relatedThings && ( | ||
| <RelatedThings things={relatedThings} query={query} /> | ||
| )} | ||
| </Box> | ||
| </Box> | ||
| ) | ||
| } | ||
|
|
||
| type DefaultResultsProps = { | ||
| grouped: Map<GroupType, SearchResult[]> | ||
| query: string | ||
| onSelect: (result: SearchResult) => void | ||
| } | ||
|
|
||
| export const DefaultResults = ({ | ||
| grouped, | ||
| query, | ||
| onSelect, | ||
| }: DefaultResultsProps) => ( | ||
| <Box sx={{ py: 0.5 }}> | ||
| {Array.from(grouped.entries()).map(([group, items], groupIndex) => ( | ||
| <Box key={group}> | ||
| {groupIndex > 0 && <Divider sx={{ my: 0.5 }} />} | ||
| {items.map((option, index) => ( | ||
| <ResultRow | ||
| key={`${option.group}-${(option as any).properties?.id ?? index}`} | ||
| option={option} | ||
| query={query} | ||
| onClick={() => onSelect(option)} | ||
| /> | ||
| ))} | ||
| </Box> | ||
| ))} | ||
| </Box> | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import { Box, Typography } from '@mui/material' | ||
| import { Description } from '@mui/icons-material' | ||
| import { DocEntry } from '@/utils/docsSearch' | ||
| import { buildDocExcerpt } from '@/utils/searchModal' | ||
| import { highlight } from '@/utils' | ||
|
|
||
| type DocsResultsProps = { | ||
| docs: DocEntry[] | ||
| query: string | ||
| onSelect: (doc: DocEntry) => void | ||
| } | ||
|
|
||
| export const DocsResults = ({ docs, query, onSelect }: DocsResultsProps) => ( | ||
| <Box sx={{ py: 0.5 }}> | ||
| {docs.map((doc) => ( | ||
| <Box | ||
| key={doc.id} | ||
| onClick={() => onSelect(doc)} | ||
| sx={{ | ||
| display: 'flex', | ||
| alignItems: 'flex-start', | ||
| gap: 1.5, | ||
| px: 1.5, | ||
| py: 1, | ||
| borderRadius: 1, | ||
| cursor: 'pointer', | ||
| '&:hover': { bgcolor: 'action.hover' }, | ||
| }} | ||
| > | ||
| <Description | ||
| sx={{ fontSize: 18, color: 'text.secondary', flexShrink: 0, mt: '2px' }} | ||
| /> | ||
| <Box sx={{ minWidth: 0, flex: 1 }}> | ||
| <Typography variant="body2" fontWeight={600} sx={{ lineHeight: 1.4 }}> | ||
| {highlight(doc.title, query)} | ||
| </Typography> | ||
| <Typography | ||
| variant="caption" | ||
| color="text.secondary" | ||
| sx={{ lineHeight: 1.4, display: 'block' }} | ||
| > | ||
| {highlight(buildDocExcerpt(doc, query), query)} | ||
| </Typography> | ||
| </Box> | ||
| </Box> | ||
| ))} | ||
| </Box> | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| import { Typography } from '@mui/material' | ||
|
|
||
| type EmptyStateProps = { | ||
| color?: 'error' | 'text.secondary' | ||
| message: string | ||
| } | ||
|
|
||
| export const EmptyState = ({ | ||
| color = 'text.secondary', | ||
| message, | ||
| }: EmptyStateProps) => ( | ||
| <Typography | ||
| variant="body2" | ||
| color={color} | ||
| sx={{ px: 2, py: 2, textAlign: 'center' }} | ||
| > | ||
| {message} | ||
| </Typography> | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| import { Box, Stack, Typography } from '@mui/material' | ||
| import { ArcadeGame, GAMES } from '@/utils/searchModal' | ||
|
|
||
| type GameResultsProps = { | ||
| games: typeof GAMES | ||
| term: string | ||
| onSelect: (game: ArcadeGame) => void | ||
| } | ||
|
|
||
| export const GameResults = ({ games, term, onSelect }: GameResultsProps) => ( | ||
| <Box sx={{ py: 1 }}> | ||
| <Stack sx={{ px: 1.5, pb: 0.5 }}> | ||
| <Typography | ||
| variant="overline" | ||
| sx={{ color: 'text.disabled', fontSize: 10, letterSpacing: 1 }} | ||
| > | ||
| Games | ||
| </Typography> | ||
| </Stack> | ||
|
|
||
| {games.map((game) => ( | ||
| <Box | ||
| key={game.key} | ||
| onClick={() => onSelect(game.key)} | ||
| sx={{ | ||
| display: 'flex', | ||
| alignItems: 'flex-start', | ||
| gap: 1.5, | ||
| px: 1.5, | ||
| py: 1, | ||
| borderRadius: 1, | ||
| cursor: 'pointer', | ||
| '&:hover': { bgcolor: 'action.hover' }, | ||
| }} | ||
| > | ||
| <Typography variant="body2" sx={{ minWidth: 0, flex: 1 }}> | ||
| <Box component="span" fontWeight={600}> | ||
| {game.label} | ||
| </Box> | ||
| <Typography | ||
| component="span" | ||
| variant="caption" | ||
| color="text.secondary" | ||
| sx={{ ml: 1 }} | ||
| > | ||
| {game.description} | ||
| </Typography> | ||
| </Typography> | ||
| </Box> | ||
| ))} | ||
|
|
||
| {games.length === 0 && ( | ||
| <Typography | ||
| variant="body2" | ||
| color="text.secondary" | ||
| sx={{ px: 2, py: 2, textAlign: 'center' }} | ||
| > | ||
| No games found for "{term}". | ||
| </Typography> | ||
| )} | ||
| </Box> | ||
| ) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Broke up the Modal Results into their respective components in the Search folder.