Skip to content

Commit

Permalink
chore(search): add loader if searching and up packages (#1)
Browse files Browse the repository at this point in the history
* chore(search): add loader if searching

* fix(ts-error): weird

* fix(ts-error): another one from package upgrade
  • Loading branch information
AnilSeervi authored Dec 18, 2023
1 parent 12b74eb commit ee21d93
Show file tree
Hide file tree
Showing 8 changed files with 1,205 additions and 1,149 deletions.
80 changes: 51 additions & 29 deletions components/atom/command-menu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
/* eslint-disable @next/next/no-img-element */
'use client'

import { Params } from '@/app/page'
import useDebounce from '@/lib/useDebounce'
import { cn } from '@/lib/utils'
import { tempValue } from '@/utils'
import { useTheme } from 'next-themes'
import { useRouter } from 'next/navigation'
import { useCallback, useEffect, useState } from 'react'
import { Button } from '../ui/button'
import { Icons } from '../ui/icons'
import {
CommandDialog,
CommandEmpty,
Expand All @@ -12,12 +18,8 @@ import {
CommandList,
CommandSeparator,
} from '../ui/command'
import { useCallback, useEffect, useState } from 'react'
import { useTheme } from 'next-themes'
import useDebounce from '@/lib/useDebounce'
import { tempValue } from '@/utils'
import { cn } from '@/lib/utils'
import { useRouter } from 'next/navigation'
import { Icons } from '../ui/icons'
import Loader from '../ui/loader'

type SearchResults = {
id: number
Expand All @@ -41,24 +43,28 @@ type SearchResults = {
}
}

function CommandMenu({ units }: { units: boolean }) {
function CommandMenu({ units }: { units: Params['units'] }) {
const router = useRouter()
const [open, setOpen] = useState(false)
const { setTheme } = useTheme()
const [query, setQuery] = useState('')
const [query, setQuery] = useState({ value: '', loading: false })
const [searchResults, setSearchResults] = useState<SearchResults[]>([])

useDebounce(
() => {
if (query.length > 0)
fetch('/api/find?q=' + query)
if (query.value.trim().length > 2) {
fetch('/api/find?q=' + query.value)
.then((res) => res.json())
.then((data) => {
setSearchResults(data)
})
.finally(() => {
setQuery((query) => ({ ...query, loading: false }))
})
}
},
200,
[query]
[query.value]
)
useEffect(() => {
const down = (e: KeyboardEvent) => {
Expand All @@ -75,7 +81,7 @@ function CommandMenu({ units }: { units: boolean }) {
const runCommand = useCallback((command: () => unknown) => {
setOpen(false)
command()
setQuery('')
setQuery({ value: '', loading: false })
}, [])

return (
Expand All @@ -85,25 +91,40 @@ function CommandMenu({ units }: { units: boolean }) {
</Button>
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput
placeholder='Type a command or search...'
onValueChange={(e) => setQuery(e)}
value={query}
placeholder='Search a city(eg. London)'
onValueChange={(e) => {
setSearchResults([])
setQuery({ value: e, loading: e.trim().length > 2 })
}}
value={query.value}
/>
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading='Search City'>
<CommandEmpty>
{query.value.trim().length < 3
? 'Type at least 3 characters to search.'
: 'No results found.'}
</CommandEmpty>
{query.loading && (
<CommandItem
disabled
className='flex items-center justify-center'
value={query.value}
>
<Loader className='scale-150' />
</CommandItem>
)}
<CommandGroup
heading='Search City'
className={cn(!query.value && 'hidden')}
>
{searchResults.map((result) => (
<CommandItem
key={result.id}
value={query + result.name + result.id}
value={query.value + result.name + result.id}
onSelect={() =>
runCommand(() =>
router.replace(
`/?lat=${result.coord.lat}&lon=${result.coord.lon}&city=${
result.name
}&country=${result.sys.country}&units=${
units ? 'imperial' : 'metric'
}`
`/?lat=${result.coord.lat}&lon=${result.coord.lon}&city=${result.name}&country=${result.sys.country}&units=${units}`
)
)
}
Expand All @@ -123,8 +144,9 @@ function CommandMenu({ units }: { units: boolean }) {
</div>
<div className='flex basis-1/5 items-baseline'>
<span>
{tempValue(result.main.temp, units, true)}&deg;
{units ? 'F' : 'C'}
{tempValue(result.main.temp, units === 'imperial', true)}
&deg;
{units === 'imperial' ? 'F' : 'C'}
</span>
<span className='ml-1 text-muted-foreground'>
<i
Expand All @@ -147,21 +169,21 @@ function CommandMenu({ units }: { units: boolean }) {
<CommandSeparator />
<CommandGroup heading='Theme'>
<CommandItem
value='light'
value=''
onSelect={() => runCommand(() => setTheme('light'))}
>
<Icons.sun className='mr-2 h-4 w-4' />
Light
</CommandItem>
<CommandItem
value='dark'
value=''
onSelect={() => runCommand(() => setTheme('dark'))}
>
<Icons.moon className='mr-2 h-4 w-4' />
Dark
</CommandItem>
<CommandItem
value='system'
value=''
onSelect={() => runCommand(() => setTheme('system'))}
>
<Icons.laptop className='mr-2 h-4 w-4' />
Expand Down
8 changes: 4 additions & 4 deletions components/screen/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import CommandMenu from '../atom/command-menu'
import ModeToggle from '../atom/toggle-menu'
import type { Params } from '@/app/page'
import GetGPS from '../atom/use-gps'
import { getTime } from '@/utils'
import CommandMenu from '../atom/command-menu'
import ModeToggle from '../atom/toggle-menu'
import ToggleUnits from '../atom/toggle-units'
import GetGPS from '../atom/use-gps'

type NavBarProps = {
units: Params['units']
Expand All @@ -15,7 +15,7 @@ function NavBar({ units, timezone }: NavBarProps) {
<nav className='flex items-center justify-between'>
<div className='flex items-center gap-3'>
<GetGPS />
<CommandMenu units={units === 'imperial'} />
<CommandMenu units={units} />
</div>
<div className='flex flex-col items-center'>
<span className='text-sm lg:text-base'>
Expand Down
15 changes: 5 additions & 10 deletions components/ui/command.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use client'

import * as React from 'react'
import { DialogProps } from '@radix-ui/react-dialog'
import { Command as CommandPrimitive } from 'cmdk'
import * as React from 'react'

import { cn } from '@/lib/utils'
import { Dialog, DialogContent } from '@/components/ui/dialog'
import { cn } from '@/lib/utils'
import { Search } from 'lucide-react'

const Command = React.forwardRef<
Expand Down Expand Up @@ -144,12 +144,7 @@ CommandShortcut.displayName = 'CommandShortcut'

export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
CommandDialog, CommandEmpty,
CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut
}

16 changes: 5 additions & 11 deletions components/ui/dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
'use client'

import * as React from 'react'
import { cn } from '@/lib/utils'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { X as CloseIcon } from 'lucide-react'
import { cn } from '@/lib/utils'
import * as React from 'react'

const Dialog = DialogPrimitive.Root

const DialogTrigger = DialogPrimitive.Trigger

const DialogPortal = ({
className,
...props
}: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={cn(className)} {...props} />
<DialogPrimitive.Portal {...props} />
)
DialogPortal.displayName = DialogPrimitive.Portal.displayName

Expand Down Expand Up @@ -112,11 +111,6 @@ const DialogDescription = React.forwardRef<
DialogDescription.displayName = DialogPrimitive.Description.displayName

export {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger
}

18 changes: 9 additions & 9 deletions components/ui/icons.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
Moon,
SunMedium,
Locate,
Search,
Laptop,
LocateFixed,
type Icon as LucideIcon,
ChevronUp,
ChevronDown,
LucideProps,
ChevronLeft,
ChevronRight,
ChevronUp,
Laptop,
Locate,
LocateFixed,
LucideProps,
Moon,
Search,
SunMedium,
type LucideIcon,
} from 'lucide-react'

export type Icon = LucideIcon
Expand Down
58 changes: 58 additions & 0 deletions components/ui/loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { SVGProps } from "react"

function Loader(props:SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 24 24"
{...props}
>
<circle cx="12" cy="12" r="0" fill="#888888">
<animate
id="svgSpinnersPulse20"
fill="freeze"
attributeName="r"
begin="0;svgSpinnersPulse21.begin+0.6s"
calcMode="spline"
dur="1.2s"
keySplines=".52,.6,.25,.99"
values="0;11"
></animate>
<animate
fill="freeze"
attributeName="opacity"
begin="0;svgSpinnersPulse21.begin+0.6s"
calcMode="spline"
dur="1.2s"
keySplines=".52,.6,.25,.99"
values="1;0"
></animate>
</circle>
<circle cx="12" cy="12" r="0" fill="#888888">
<animate
id="svgSpinnersPulse21"
fill="freeze"
attributeName="r"
begin="svgSpinnersPulse20.begin+0.6s"
calcMode="spline"
dur="1.2s"
keySplines=".52,.6,.25,.99"
values="0;11"
></animate>
<animate
fill="freeze"
attributeName="opacity"
begin="svgSpinnersPulse20.begin+0.6s"
calcMode="spline"
dur="1.2s"
keySplines=".52,.6,.25,.99"
values="1;0"
></animate>
</circle>
</svg>
)
}

export default Loader
38 changes: 19 additions & 19 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,32 @@
},
"dependencies": {
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-dialog": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.6.1",
"class-variance-authority": "^0.7.0",
"cmdk": "^0.2.0",
"lucide-react": "^0.258.0",
"next": "13.4.8",
"lucide-react": "^0.298.0",
"next": "14.0.4",
"next-themes": "^0.2.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/node": "20.3.3",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.6",
"autoprefixer": "10.4.14",
"clsx": "^1.2.1",
"eslint": "8.44.0",
"eslint-config-next": "13.4.8",
"postcss": "8.4.24",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.3.0",
"tailwind-merge": "^1.13.2",
"tailwindcss": "3.3.2",
"tailwindcss-animate": "^1.0.6",
"typescript": "5.1.6"
"@types/node": "20.10.5",
"@types/react": "18.2.45",
"@types/react-dom": "18.2.18",
"autoprefixer": "10.4.16",
"clsx": "^2.0.0",
"eslint": "8.56.0",
"eslint-config-next": "14.0.4",
"postcss": "8.4.32",
"prettier": "^3.1.1",
"prettier-plugin-tailwindcss": "^0.5.9",
"tailwind-merge": "^2.1.0",
"tailwindcss": "3.3.6",
"tailwindcss-animate": "^1.0.7",
"typescript": "5.3.3"
}
}
Loading

0 comments on commit ee21d93

Please sign in to comment.