update demo-dictionary-app,

This commit is contained in:
louiscklaw
2025-06-04 18:04:47 +08:00
parent d76d43d17f
commit 9caca30e1e
30 changed files with 799 additions and 425 deletions

View File

@@ -1,8 +1,13 @@
import {
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardSubtitle,
IonCardTitle,
IonCol,
IonContent,
IonGrid,
IonHeader,
IonIcon,
IonPage,
@@ -11,54 +16,27 @@ import {
IonToolbar,
useIonRouter,
} from '@ionic/react';
import { bookOutline, chevronBackOutline, heart, search } from 'ionicons/icons';
import { useStoreState } from 'pullstate';
import { useRef } from 'react';
import { WordStore } from '../store';
import { getFavourites, getSearchCount } from '../store/Selectors';
import { Geolocation } from '@capacitor/geolocation';
import { useEffect, useState } from 'react';
import { SkeletonDashboard } from '../components/SkeletonDashboard';
import { chevronBackOutline, refreshOutline } from 'ionicons/icons';
import { CurrentWeather } from '../components/CurrentWeather';
function Tab1() {
const Tab1 = () => {
const router = useIonRouter();
const [currentWeather, setCurrentWeather] = useState(false);
useEffect(() => {
getCurrentPosition();
}, []);
const getCurrentPosition = async () => {
setCurrentWeather(false);
const coordinates = await Geolocation.getCurrentPosition();
getAddress(coordinates.coords);
};
const getAddress = async (coords) => {
const query = `${coords.latitude},${coords.longitude}`;
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${query}`
);
const data = await response.json();
console.log(data);
setCurrentWeather(data);
};
const pageRef = useRef();
const favourites = useStoreState(WordStore, getFavourites);
const searchCount = useStoreState(WordStore, getSearchCount);
function handleBackClick() {
router.goBack();
}
return (
<IonPage>
<IonPage ref={pageRef}>
<IonHeader>
<IonToolbar>
<IonTitle>My Weather</IonTitle>
<IonButtons slot="end">
<IonButton onClick={() => getCurrentPosition()}>
<IonIcon icon={refreshOutline} color="primary" />
</IonButton>
</IonButtons>
<IonTitle>Dashboard</IonTitle>
<IonButtons slot="start">
<IonButton onClick={() => handleBackClick()}>
@@ -71,25 +49,66 @@ function Tab1() {
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Dashboard</IonTitle>
<IonButtons slot="start">
<IonButton onClick={() => handleBackClick()}>
<IonIcon icon={chevronBackOutline} color="primary" />
</IonButton>
</IonButtons>
</IonToolbar>
</IonHeader>
<IonRow className="ion-margin-start ion-margin-end ion-justify-content-center ion-text-center">
<IonCol size="12">
<h4>Here's your location based weather</h4>
</IonCol>
</IonRow>
<IonGrid>
<IonRow className={`animate__animated animate__faster animate__fadeIn`}>
<IonCol size="12">
<IonCard>
<IonCardContent>
<IonIcon icon={bookOutline} color="primary" style={{ fontSize: '2rem' }} />
<IonCardTitle>Ionic Dictionary App</IonCardTitle>
<p>Based on the English language</p>
</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
<div style={{ marginTop: '-1.5rem' }}>
{currentWeather ? (
<CurrentWeather currentWeather={currentWeather} />
) : (
<SkeletonDashboard />
)}
</div>
<IonRow className={`animate__animated animate__faster animate__fadeIn`}>
<IonCol size="12">
<IonCard>
<IonCardContent>
<IonCardTitle>Did you know?</IonCardTitle>
<p>There are 171, 146 words in the English language!</p>
<IonButton expand="block" className="ion-margin-top" routerLink="/search">
Search now &rarr;
</IonButton>
</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
<IonRow className={`animate__animated animate__faster animate__fadeIn`}>
<IonCol size="6">
<IonCard routerLink="/favourites">
<IonCardContent className="ion-text-center">
<IonIcon icon={heart} color="primary" />
<IonCardTitle>{favourites.length}</IonCardTitle>
<IonCardSubtitle>Favourites</IonCardSubtitle>
</IonCardContent>
</IonCard>
</IonCol>
<IonCol size="6">
<IonCard routerLink="/favourites">
<IonCardContent className="ion-text-center">
<IonIcon icon={search} color="primary" />
<IonCardTitle>{searchCount}</IonCardTitle>
<IonCardSubtitle>Searches</IonCardSubtitle>
</IonCardContent>
</IonCard>
</IonCol>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
}
};
export default Tab1;

View File

@@ -2,6 +2,7 @@ import {
IonButton,
IonCol,
IonContent,
IonGrid,
IonHeader,
IonPage,
IonRow,
@@ -9,30 +10,32 @@ import {
IonTitle,
IonToolbar,
} from '@ionic/react';
import { useState } from 'react';
import { CurrentWeather } from '../components/CurrentWeather';
import { useState, useRef } from 'react';
import { NoSearch } from '../components/NoSearch';
import { NoResultsWordCard, WordCard } from '../components/WordCard';
import { WordStore } from '../store';
import { searchWord } from '../utils';
function Tab2() {
const [search, setSearch] = useState('');
const [currentWeather, setCurrentWeather] = useState(false);
const Tab2 = () => {
const pageRef = useRef();
const [searchTerm, setSearchTerm] = useState('');
const [searchResult, setSearchResult] = useState(false);
const [animatedClass, setAnimatedClass] = useState('');
const performSearch = async () => {
getAddress(search);
};
setAnimatedClass('animate__slideOutRight');
const result = searchTerm !== '' ? await searchWord(searchTerm) : undefined;
const getAddress = async (city) => {
const response = await fetch(
`https://api.weatherapi.com/v1/current.json?key=f93eb660b2424258bf5155016210712&q=${city}&aqi=no`
);
const data = await response.json();
setTimeout(() => setSearchResult(result === undefined ? 'none' : result), 250);
setTimeout(() => setAnimatedClass('animate__slideInLeft'), 250);
if (data && data.current && data.location) {
setCurrentWeather(data);
}
WordStore.update((s) => {
s.searchCount++;
});
};
return (
<IonPage>
<IonPage ref={pageRef}>
<IonHeader>
<IonToolbar>
<IonTitle>Search</IonTitle>
@@ -45,37 +48,36 @@ function Tab2() {
</IonToolbar>
</IonHeader>
<IonRow className="ion-justify-content-center ion-margin-top ion-align-items-center">
<IonCol size="7">
<IonSearchbar
placeholder="Try 'London'"
animated
value={search}
onIonChange={(e) => setSearch(e.target.value)}
/>
</IonCol>
<IonGrid>
<IonRow className="ion-align-items-center">
<IonCol size="9">
<IonSearchbar
animated
value={searchTerm}
onIonChange={(e) => setSearchTerm(e.target.value)}
/>
</IonCol>
<IonCol size="5">
<IonButton
expand="block"
className="ion-margin-start ion-margin-end"
onClick={performSearch}
>
Search
</IonButton>
</IonCol>
</IonRow>
<IonCol size="3">
<IonButton color="primary" onClick={performSearch}>
Search
</IonButton>
</IonCol>
</IonRow>
<div style={{ marginTop: '-0.8rem' }}>
{currentWeather ? (
<CurrentWeather currentWeather={currentWeather} />
) : (
<h3 className="ion-text-center">Your search result will appear here</h3>
{searchResult && searchResult !== 'none' && (
<WordCard word={searchResult} animatedClass={animatedClass} pageRef={pageRef} />
)}
</div>
{searchResult && searchResult === 'none' && (
<NoResultsWordCard word={searchResult} animatedClass={animatedClass} />
)}
{!searchResult && <NoSearch />}
</IonGrid>
</IonContent>
</IonPage>
);
}
};
export default Tab2;

View File

@@ -0,0 +1,45 @@
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import { useStoreState } from 'pullstate';
import { useRef, useState } from 'react';
import { NoFavourites } from '../components/NoFavourites';
import { WordCard } from '../components/WordCard';
import { WordStore } from '../store';
import { getFavourites } from '../store/Selectors';
const Tab3 = () => {
const pageRef = useRef();
const favourites = useStoreState(WordStore, getFavourites);
const [animatedClass, setAnimatedClass] = useState('animate__slideInLeft');
return (
<IonPage ref={pageRef}>
<IonHeader>
<IonToolbar>
<IonTitle>Favourites</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Favourites</IonTitle>
</IonToolbar>
</IonHeader>
{favourites.map((favourite, index) => {
return (
<WordCard
key={index}
word={favourite}
animatedClass={animatedClass}
pageRef={pageRef}
/>
);
})}
{favourites.length < 1 && <NoFavourites />}
</IonContent>
</IonPage>
);
};
export default Tab3;