diff --git a/03_source/mobile/public/assets/DemoDictionaryApp/icon/favicon.png b/03_source/mobile/public/assets/DemoDictionaryApp/icon/favicon.png new file mode 100644 index 0000000..51888a7 Binary files /dev/null and b/03_source/mobile/public/assets/DemoDictionaryApp/icon/favicon.png differ diff --git a/03_source/mobile/public/assets/DemoDictionaryApp/icon/icon.png b/03_source/mobile/public/assets/DemoDictionaryApp/icon/icon.png new file mode 100644 index 0000000..a7f6374 Binary files /dev/null and b/03_source/mobile/public/assets/DemoDictionaryApp/icon/icon.png differ diff --git a/03_source/mobile/public/assets/DemoDictionaryApp/shapes.svg b/03_source/mobile/public/assets/DemoDictionaryApp/shapes.svg new file mode 100644 index 0000000..d370b4d --- /dev/null +++ b/03_source/mobile/public/assets/DemoDictionaryApp/shapes.svg @@ -0,0 +1 @@ + diff --git a/03_source/mobile/src/App.tsx b/03_source/mobile/src/App.tsx index 894c129..52fe519 100644 --- a/03_source/mobile/src/App.tsx +++ b/03_source/mobile/src/App.tsx @@ -66,7 +66,7 @@ import PrivacyAgreement from './pages/PrivacyAgreement'; import AppRoute from './AppRoute'; // import DemoReactShop from './pages/DemoReactShop'; -import DemoWeatherApp from './pages/WeatherDemo'; +import DemoWeatherApp from './pages/DemoWeatherApp'; import DemoClubHouse from './pages/DemoClubHouse'; import DemoScoreBoard from './pages/DemoScoreBoard'; import DemoQuoteApp from './pages/DemoQuoteApp'; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab1.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab1.jsx index a6f4101..f107663 100644 --- a/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab1.jsx +++ b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab1.jsx @@ -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 ( - + - My Weather - - - getCurrentPosition()}> - - - + Dashboard handleBackClick()}> @@ -71,25 +49,66 @@ function Tab1() { Dashboard + + + handleBackClick()}> + + + - - -

Here's your location based weather

-
-
+ + + + + + + Ionic Dictionary App +

Based on the English language

+
+
+
+
-
- {currentWeather ? ( - - ) : ( - - )} -
+ + + + + Did you know? +

There are 171, 146 words in the English language!

+ + Search now → + +
+
+
+
+ + + + + + + {favourites.length} + Favourites + + + + + + + + {searchCount} + Searches + + + + +
); -} +}; export default Tab1; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab2.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab2.jsx index 216544f..d3a8909 100644 --- a/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab2.jsx +++ b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab2.jsx @@ -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 ( - + Search @@ -45,37 +48,36 @@ function Tab2() { - - - setSearch(e.target.value)} - /> - + + + + setSearchTerm(e.target.value)} + /> + - - - Search - - - + + + Search + + + -
- {currentWeather ? ( - - ) : ( -

Your search result will appear here

+ {searchResult && searchResult !== 'none' && ( + )} -
+ + {searchResult && searchResult === 'none' && ( + + )} + + {!searchResult && } +
); -} +}; export default Tab2; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab3.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab3.jsx new file mode 100644 index 0000000..d12efc2 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/AppPages/Tab3.jsx @@ -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 ( + + + + Favourites + + + + + + Favourites + + + + {favourites.map((favourite, index) => { + return ( + + ); + })} + + {favourites.length < 1 && } + + + ); +}; + +export default Tab3; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/NoFavourites.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/NoFavourites.jsx new file mode 100644 index 0000000..0f446f7 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/NoFavourites.jsx @@ -0,0 +1,22 @@ +import { IonCol, IonLabel, IonRow } from '@ionic/react'; + +export const NoFavourites = () => ( + + + +

You don't have any favourites yet!

+

+ Any time you see the heart icon, press it to add the related word to your favourites and + quickly access it from here. +

+ +
+
+
+); diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/NoSearch.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/NoSearch.jsx new file mode 100644 index 0000000..27f6fa3 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/NoSearch.jsx @@ -0,0 +1,23 @@ +import { IonCol, IonLabel, IonRow } from '@ionic/react'; + +export const NoSearch = () => ( + + + +

Search for a word in the English language

+

+ This app will give you word meaninigs, phonetics, origin and also an audio clip so you can + hear what it sounds like. +

+ +
+
+
+); diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCard.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCard.jsx new file mode 100644 index 0000000..9ec2346 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCard.jsx @@ -0,0 +1,129 @@ +import { + IonBadge, + IonButton, + IonCard, + IonCardContent, + IonCardSubtitle, + IonCardTitle, + IonCol, + IonIcon, + IonNote, + IonRow, + useIonModal, +} from '@ionic/react'; +import { checkmarkCircleOutline, chevronForward, closeCircleOutline } from 'ionicons/icons'; +import WordModal from './WordModal'; + +export const WordCard = ({ word, animatedClass, pageRef }) => { + const closeModal = () => { + hideModal(); + }; + + const openModal = () => { + showModal({ + presentingElement: pageRef.current, + onDidDismiss: hideModal, + }); + }; + + const [showModal, hideModal] = useIonModal(WordModal, { + dismiss: closeModal, + word, + }); + + return ( + + + + + {word.word} +
+ {word.meanings && + word.meanings.map((meaning, index) => { + return ( + + {meaning.partOfSpeech} +   + + ); + })} +
+ {word.origin} + + + + {word.meanings.length} + meanings + + + + {word.phonetics.length} + phonetics + + + + + + audio + + + + + + + View  + + + + +
+
+
+
+ ); +}; + +export const NoResultsWordCard = ({ word, animatedClass }) => { + return ( + + + + + Whoops... +
+ no results  + found +
+ + No results have been found for your search criteria! Please try another word. + + + + + 0 + meanings + + + + 0 + phonetics + + + + + + audio + + +
+
+
+
+ ); +}; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCardHeading.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCardHeading.jsx new file mode 100644 index 0000000..ff23fc0 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordCardHeading.jsx @@ -0,0 +1,10 @@ +import { IonText } from "@ionic/react"; + +export const WordCardHeading = ({ text }) => ( + +
+ +

{ text }

+
+
+); \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/WordMeaning.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordMeaning.jsx new file mode 100644 index 0000000..1f5d3b7 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordMeaning.jsx @@ -0,0 +1,18 @@ +import { IonBadge } from '@ionic/react'; + +export const WordMeaning = ({ meaning, index }) => ( +
0 ? 'ion-padding-top' : ''}> + + {meaning.partOfSpeech} + +
+ {meaning.definitions.map((definition, index2) => { + return ( +

0 ? 'ion-padding-top' : ''}> + {index2 + 1}.  + {definition.definition} +

+ ); + })} +
+); diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/WordModal.jsx b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordModal.jsx new file mode 100644 index 0000000..0896a4b --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/components/WordModal.jsx @@ -0,0 +1,122 @@ +import { + IonBadge, + IonButton, + IonButtons, + IonCard, + IonCardContent, + IonCardHeader, + IonCardSubtitle, + IonCardTitle, + IonCol, + IonContent, + IonGrid, + IonHeader, + IonIcon, + IonNote, + IonPage, + IonRow, + IonText, + IonTitle, + IonToolbar, +} from '@ionic/react'; +import { heart, heartOutline, play } from 'ionicons/icons'; +import { useStoreState } from 'pullstate'; +import { WordStore } from '../store'; +import { getFavourites } from '../store/Selectors'; +import { addToFavourites } from '../store/WordStore'; +import { WordCardHeading } from './WordCardHeading'; +import { WordMeaning } from './WordMeaning'; + +const WordModal = ({ dismiss, word }) => { + const favourites = useStoreState(WordStore, getFavourites); + const isFavourite = favourites.includes(word); + const audio = word.phonetics[0] ? word.phonetics[0].audio : false; + + const playAudio = () => { + const audioElement = new Audio(`https:${audio}`); + audioElement.play(); + }; + + return ( + + + + + addToFavourites(word)}> + + + + View Word + + + Close + + + + + + + + + + {word.word} +
+ {word.meanings && + word.meanings.map((meaning, index) => { + return ( + + + {meaning.partOfSpeech} + +   + + ); + })} +
+ {word.origin} +
+
+
+
+ + {audio && ( + + + + + + + + + + + + + + + + + + )} + + + + + + + + {word.meanings && + word.meanings.map((meaning, index) => { + return ; + })} + + + + +
+
+
+ ); +}; + +export default WordModal; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/index.tsx b/03_source/mobile/src/pages/DemoDictionaryApp/index.tsx index 0cc5228..8e1f78b 100644 --- a/03_source/mobile/src/pages/DemoDictionaryApp/index.tsx +++ b/03_source/mobile/src/pages/DemoDictionaryApp/index.tsx @@ -1,38 +1,44 @@ import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react'; -import { cloudOutline, searchOutline } from 'ionicons/icons'; +import { cloudOutline, heart, search, searchOutline, statsChart } from 'ionicons/icons'; import { Route, Redirect } from 'react-router'; import Tab1 from './AppPages/Tab1'; import Tab2 from './AppPages/Tab2'; +import Tab3 from './AppPages/Tab3'; -function DemoWeatherApp() { +import './style.scss'; + +function DemoDictionaryApp() { return ( - + - + - + - - + + + + {/* */} - - - Dashboard + + - - - Search + + + + + ); } -export default DemoWeatherApp; +export default DemoDictionaryApp; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/store/Selectors.js b/03_source/mobile/src/pages/DemoDictionaryApp/store/Selectors.js new file mode 100644 index 0000000..eeb9eb0 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/store/Selectors.js @@ -0,0 +1,8 @@ +import { createSelector } from 'reselect'; + +const getState = state => state; + +// General getters +export const getFavourites = createSelector(getState, state => state.favourites); +export const getPopularWords = createSelector(getState, state => state.popularWords); +export const getSearchCount = createSelector(getState, state => state.searchCount); \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/store/WordStore.js b/03_source/mobile/src/pages/DemoDictionaryApp/store/WordStore.js new file mode 100644 index 0000000..374c814 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/store/WordStore.js @@ -0,0 +1,29 @@ +import { Store } from "pullstate"; + +const WordStore = new Store({ + + favourites: [], + popularWords: [], + searchCount: 0 +}); + +export default WordStore; + +export const addToFavourites = (passedWord) => { + + const currentFavourites = WordStore.getRawState().favourites; + const added = !currentFavourites.includes(passedWord); + + WordStore.update(s => { + + if (currentFavourites.includes(passedWord)) { + + s.favourites = currentFavourites.filter(word => word !== passedWord); + } else { + + s.favourites = [ ...s.favourites, passedWord ]; + } + }); + + return added; +} \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/store/index.js b/03_source/mobile/src/pages/DemoDictionaryApp/store/index.js new file mode 100644 index 0000000..b232728 --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/store/index.js @@ -0,0 +1 @@ +export { default as WordStore } from "./WordStore"; diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/style.scss b/03_source/mobile/src/pages/DemoDictionaryApp/style.scss index 37c1e1a..bb952e0 100644 --- a/03_source/mobile/src/pages/DemoDictionaryApp/style.scss +++ b/03_source/mobile/src/pages/DemoDictionaryApp/style.scss @@ -1,103 +1,240 @@ -#about-page { - ion-toolbar { - position: absolute; +/* Ionic Variables and Theming. For more info, please see: +http://ionicframework.com/docs/theming/ */ - top: 0; - left: 0; - right: 0; +/** Ionic CSS Variables **/ +.demo-dictionary-app { + * { + /** primary **/ + --ion-color-primary: #953cd0; + --ion-color-primary-rgb: 149, 60, 208; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #8335b7; + --ion-color-primary-tint: #a050d5; - --background: transparent; - --color: white; + /** secondary **/ + --ion-color-secondary: #3dc2ff; + --ion-color-secondary-rgb: 61, 194, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #36abe0; + --ion-color-secondary-tint: #50c8ff; + + /** tertiary **/ + --ion-color-tertiary: #5260ff; + --ion-color-tertiary-rgb: 82, 96, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #4854e0; + --ion-color-tertiary-tint: #6370ff; + + /** success **/ + --ion-color-success: #2dd36f; + --ion-color-success-rgb: 45, 211, 111; + --ion-color-success-contrast: #ffffff; + --ion-color-success-contrast-rgb: 255, 255, 255; + --ion-color-success-shade: #28ba62; + --ion-color-success-tint: #42d77d; + + /** warning **/ + --ion-color-warning: #ffc409; + --ion-color-warning-rgb: 255, 196, 9; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0ac08; + --ion-color-warning-tint: #ffca22; + + /** danger **/ + --ion-color-danger: #eb445a; + --ion-color-danger-rgb: 235, 68, 90; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #cf3c4f; + --ion-color-danger-tint: #ed576b; + + /** dark **/ + --ion-color-dark: #222428; + --ion-color-dark-rgb: 34, 36, 40; + --ion-color-dark-contrast: #ffffff; + --ion-color-dark-contrast-rgb: 255, 255, 255; + --ion-color-dark-shade: #1e2023; + --ion-color-dark-tint: #383a3e; + + /** medium **/ + --ion-color-medium: #92949c; + --ion-color-medium-rgb: 146, 148, 156; + --ion-color-medium-contrast: #ffffff; + --ion-color-medium-contrast-rgb: 255, 255, 255; + --ion-color-medium-shade: #808289; + --ion-color-medium-tint: #9d9fa6; + + /** light **/ + --ion-color-light: #ffffff; + --ion-color-light-rgb: 255, 255, 255; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #e0e0e0; + --ion-color-light-tint: #ffffff; + + --ion-background-color: #1e1b27 !important; + --ion-tab-bar-color-selected: #953cd0; + --ion-tab-bar-color: #412f6e; + --ion-text-color: white; + --ion-tab-bar-background: #191620; + --ion-toolbar-background: #191620 !important; + --ion-item-background: #000000 !important; + + --ion-card-background: #272333 !important; + --ion-modal-background: #272333 !important; } - ion-toolbar ion-back-button, - ion-toolbar ion-button, - ion-toolbar ion-menu-button { - --color: white; - } - - .about-header { - position: relative; - - width: 100%; - height: 30%; - } - - .about-header .about-image { - position: absolute; - - top: 0; - left: 0; - bottom: 0; - right: 0; - - background-position: center; - background-size: cover; - background-repeat: no-repeat; - - opacity: 0; - - transition: opacity 500ms ease-in-out; - } - - .about-header .madison { - background-image: url('/assets/WeatherDemo/img/about/madison.jpg'); - } - - .about-header .austin { - background-image: url('/assets/WeatherDemo/img/about/austin.jpg'); - } - - .about-header .chicago { - background-image: url('/assets/WeatherDemo/img/about/chicago.jpg'); - } - - .about-header .seattle { - background-image: url('/assets/WeatherDemo/img/about/seattle.jpg'); - } - - .about-info { - position: relative; - margin-top: -10px; - border-radius: 10px; - background: var(--ion-background-color, #fff); - z-index: 2; // display rounded border above header image - } - - .about-info h3 { - margin-top: 0; - } - - .about-info ion-list { - padding-top: 0; - } - - .about-info p { - line-height: 130%; - - color: var(--ion-color-dark); - } - - .about-info ion-icon { - margin-inline-end: 32px; + ion-tab-bar { + --border-style: none; + border: none; } /* - * iOS Only + * Dark Colors + * ------------------------------------------- */ - .ios .about-info { - --ion-padding: 19px; + ion-modal { + -ms-overflow-style: none; /* for Internet Explorer, Edge */ + scrollbar-width: none; /* for Firefox */ + overflow-y: scroll; } - .ios .about-info h3 { - font-weight: 700; + body { + overflow: hidden !important; + --ion-color-primary: #953cd0; + --ion-color-primary-rgb: 149, 60, 208; + --ion-color-primary-contrast: #ffffff; + --ion-color-primary-contrast-rgb: 255, 255, 255; + --ion-color-primary-shade: #8335b7; + --ion-color-primary-tint: #a050d5; + + --ion-color-secondary: #50c8ff; + --ion-color-secondary-rgb: 80, 200, 255; + --ion-color-secondary-contrast: #ffffff; + --ion-color-secondary-contrast-rgb: 255, 255, 255; + --ion-color-secondary-shade: #46b0e0; + --ion-color-secondary-tint: #62ceff; + + --ion-color-tertiary: #6a64ff; + --ion-color-tertiary-rgb: 106, 100, 255; + --ion-color-tertiary-contrast: #ffffff; + --ion-color-tertiary-contrast-rgb: 255, 255, 255; + --ion-color-tertiary-shade: #5d58e0; + --ion-color-tertiary-tint: #7974ff; + + --ion-color-success: #2fdf75; + --ion-color-success-rgb: 47, 223, 117; + --ion-color-success-contrast: #000000; + --ion-color-success-contrast-rgb: 0, 0, 0; + --ion-color-success-shade: #29c467; + --ion-color-success-tint: #44e283; + + --ion-color-warning: #ffd534; + --ion-color-warning-rgb: 255, 213, 52; + --ion-color-warning-contrast: #000000; + --ion-color-warning-contrast-rgb: 0, 0, 0; + --ion-color-warning-shade: #e0bb2e; + --ion-color-warning-tint: #ffd948; + + --ion-color-danger: #ff4961; + --ion-color-danger-rgb: 255, 73, 97; + --ion-color-danger-contrast: #ffffff; + --ion-color-danger-contrast-rgb: 255, 255, 255; + --ion-color-danger-shade: #e04055; + --ion-color-danger-tint: #ff5b71; + + --ion-color-dark: #f4f5f8; + --ion-color-dark-rgb: 244, 245, 248; + --ion-color-dark-contrast: #000000; + --ion-color-dark-contrast-rgb: 0, 0, 0; + --ion-color-dark-shade: #d7d8da; + --ion-color-dark-tint: #f5f6f9; + + --ion-color-medium: #989aa2; + --ion-color-medium-rgb: 152, 154, 162; + --ion-color-medium-contrast: #000000; + --ion-color-medium-contrast-rgb: 0, 0, 0; + --ion-color-medium-shade: #86888f; + --ion-color-medium-tint: #a2a4ab; + + --ion-color-light: #ffffff; + --ion-color-light-rgb: 255, 255, 255; + --ion-color-light-contrast: #000000; + --ion-color-light-contrast-rgb: 0, 0, 0; + --ion-color-light-shade: #e0e0e0; + --ion-color-light-tint: #ffffff; + } + + /* + * iOS Dark Theme + * ------------------------------------------- + */ + + .ios body { + /* --ion-background-color: #000000; */ + /* --ion-background-color-rgb: 0,0,0; */ + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-color-step-50: #0d0d0d; + --ion-color-step-100: #1a1a1a; + --ion-color-step-150: #262626; + --ion-color-step-200: #333333; + --ion-color-step-250: #404040; + --ion-color-step-300: #4d4d4d; + --ion-color-step-350: #595959; + --ion-color-step-400: #666666; + --ion-color-step-450: #737373; + --ion-color-step-500: #808080; + --ion-color-step-550: #8c8c8c; + --ion-color-step-600: #999999; + --ion-color-step-650: #a6a6a6; + --ion-color-step-700: #b3b3b3; + --ion-color-step-750: #bfbfbf; + --ion-color-step-800: #cccccc; + --ion-color-step-850: #d9d9d9; + --ion-color-step-900: #e6e6e6; + --ion-color-step-950: #f2f2f2; + } + + /* + * Material Design Dark Theme + * ------------------------------------------- + */ + + .md body { + /* --ion-background-color: #121212; */ + /* --ion-background-color-rgb: 18,18,18; */ + + --ion-text-color: #ffffff; + --ion-text-color-rgb: 255, 255, 255; + + --ion-border-color: #222222; + + --ion-color-step-50: #1e1e1e; + --ion-color-step-100: #2a2a2a; + --ion-color-step-150: #363636; + --ion-color-step-200: #414141; + --ion-color-step-250: #4d4d4d; + --ion-color-step-300: #595959; + --ion-color-step-350: #656565; + --ion-color-step-400: #717171; + --ion-color-step-450: #7d7d7d; + --ion-color-step-500: #898989; + --ion-color-step-550: #949494; + --ion-color-step-600: #a0a0a0; + --ion-color-step-650: #acacac; + --ion-color-step-700: #b8b8b8; + --ion-color-step-750: #c4c4c4; + --ion-color-step-800: #d0d0d0; + --ion-color-step-850: #dbdbdb; + --ion-color-step-900: #e7e7e7; + --ion-color-step-950: #f3f3f3; } } - -#date-input-popover { - --offset-y: -var(--ion-safe-area-bottom); - - --max-width: 90%; - --width: 336px; -} diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/utils.js b/03_source/mobile/src/pages/DemoDictionaryApp/utils.js new file mode 100644 index 0000000..fa5327f --- /dev/null +++ b/03_source/mobile/src/pages/DemoDictionaryApp/utils.js @@ -0,0 +1,21 @@ +import { WordStore } from './store'; + +const API_URL = 'https://api.dictionaryapi.dev/api/v2/entries/en/'; + +export const searchWord = async (word, returnOne = true) => { + const response = await fetch(`${API_URL}${word.toLowerCase()}`); + const data = await response.json(); + + return returnOne ? data[0] : data; +}; + +export const fetchPopularWords = async () => { + const words = ['mobile', 'applications', 'ionic', 'framework']; + + words.forEach(async (word) => { + const wordData = await searchWord(word, false); + WordStore.update((s) => { + s.popularWords = [...s.popularWords, wordData[0]]; + }); + }); +}; diff --git a/03_source/mobile/src/pages/DemoList/index.tsx b/03_source/mobile/src/pages/DemoList/index.tsx index 8274af1..dd90a4e 100644 --- a/03_source/mobile/src/pages/DemoList/index.tsx +++ b/03_source/mobile/src/pages/DemoList/index.tsx @@ -252,6 +252,14 @@ const SettingsPage: React.FC = ({ + + + router.push(paths.DEMO_DICTIONARY_APP, 'forward')}> + + Demo Dictionary App + + + {/* REQ0058/logout */} diff --git a/03_source/mobile/src/pages/WeatherDemo/AppPages/Tab1.jsx b/03_source/mobile/src/pages/DemoWeatherApp/AppPages/Tab1.jsx similarity index 100% rename from 03_source/mobile/src/pages/WeatherDemo/AppPages/Tab1.jsx rename to 03_source/mobile/src/pages/DemoWeatherApp/AppPages/Tab1.jsx diff --git a/03_source/mobile/src/pages/WeatherDemo/AppPages/Tab2.jsx b/03_source/mobile/src/pages/DemoWeatherApp/AppPages/Tab2.jsx similarity index 100% rename from 03_source/mobile/src/pages/WeatherDemo/AppPages/Tab2.jsx rename to 03_source/mobile/src/pages/DemoWeatherApp/AppPages/Tab2.jsx diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/CurrentWeather/WeatherProperty.tsx b/03_source/mobile/src/pages/DemoWeatherApp/components/CurrentWeather/WeatherProperty.tsx similarity index 100% rename from 03_source/mobile/src/pages/DemoDictionaryApp/components/CurrentWeather/WeatherProperty.tsx rename to 03_source/mobile/src/pages/DemoWeatherApp/components/CurrentWeather/WeatherProperty.tsx diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/CurrentWeather/index.tsx b/03_source/mobile/src/pages/DemoWeatherApp/components/CurrentWeather/index.tsx similarity index 100% rename from 03_source/mobile/src/pages/DemoDictionaryApp/components/CurrentWeather/index.tsx rename to 03_source/mobile/src/pages/DemoWeatherApp/components/CurrentWeather/index.tsx diff --git a/03_source/mobile/src/pages/DemoDictionaryApp/components/SkeletonDashboard/index.tsx b/03_source/mobile/src/pages/DemoWeatherApp/components/SkeletonDashboard/index.tsx similarity index 100% rename from 03_source/mobile/src/pages/DemoDictionaryApp/components/SkeletonDashboard/index.tsx rename to 03_source/mobile/src/pages/DemoWeatherApp/components/SkeletonDashboard/index.tsx diff --git a/03_source/mobile/src/pages/WeatherDemo/index.tsx b/03_source/mobile/src/pages/DemoWeatherApp/index.tsx similarity index 100% rename from 03_source/mobile/src/pages/WeatherDemo/index.tsx rename to 03_source/mobile/src/pages/DemoWeatherApp/index.tsx diff --git a/03_source/mobile/src/pages/WeatherDemo/style.scss b/03_source/mobile/src/pages/DemoWeatherApp/style.scss similarity index 100% rename from 03_source/mobile/src/pages/WeatherDemo/style.scss rename to 03_source/mobile/src/pages/DemoWeatherApp/style.scss diff --git a/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/WeatherProperty.tsx b/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/WeatherProperty.tsx deleted file mode 100644 index 52949af..0000000 --- a/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/WeatherProperty.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { IonCardSubtitle, IonCol, IonIcon, IonNote, IonRow } from '@ionic/react'; -import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons'; -import { useEffect, useState } from 'react'; - -export const WeatherProperty = ({ type, currentWeather }: { type: any; currentWeather: any }) => { - const [property, setProperty] = useState(false); - - const properties = { - wind: { - isIcon: false, - icon: '/assets/WeatherDemo/wind.png', - alt: 'wind', - label: 'Wind', - value: `${currentWeather.current.wind_mph}mph`, - }, - feelsLike: { - isIcon: true, - icon: thermometerOutline, - alt: 'feels like', - label: 'Feels like', - value: `${currentWeather.current.feelslike_c}°C`, - }, - indexUV: { - isIcon: true, - icon: sunnyOutline, - alt: 'index uv', - label: 'Index UV', - value: currentWeather.current.uv, - }, - pressure: { - isIcon: true, - icon: pulseOutline, - alt: 'pressure', - label: 'Pressure', - value: `${currentWeather.current.pressure_mb} mbar`, - }, - }; - - useEffect(() => { - setProperty(properties[type]); - }, [type]); - - return ( - - - - {!property.isIcon && ( - {property.alt} - )} - {property.isIcon && ( - - )} - - - - {property.label} - {property.value} - - - - ); -}; diff --git a/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/index.tsx b/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/index.tsx deleted file mode 100644 index ceb4332..0000000 --- a/03_source/mobile/src/pages/WeatherDemo/components/CurrentWeather/index.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { IonCard, IonCardContent, IonGrid, IonRow, IonText, IonCardTitle } from '@ionic/react'; -import { WeatherProperty } from './WeatherProperty'; - -export const CurrentWeather = ({ currentWeather }: { currentWeather: any }) => ( - - - - -

- {currentWeather.location.region},{' '} - {currentWeather.location.country} -

-
- -
- condition - - -

{currentWeather.current.condition.text}

-
- - -

{new Date(currentWeather.location.localtime).toDateString()}

-
-
- - - {currentWeather.current.temp_c}℃ - - - - - - - - - - - - - -
-
-
-); diff --git a/03_source/mobile/src/pages/WeatherDemo/components/SkeletonDashboard/index.tsx b/03_source/mobile/src/pages/WeatherDemo/components/SkeletonDashboard/index.tsx deleted file mode 100644 index 234fb9b..0000000 --- a/03_source/mobile/src/pages/WeatherDemo/components/SkeletonDashboard/index.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { - IonCard, - IonCardContent, - IonCardSubtitle, - IonCardTitle, - IonCol, - IonGrid, - IonIcon, - IonNote, - IonRow, - IonSkeletonText, - IonText, - IonThumbnail, -} from '@ionic/react'; -import { pulseOutline, sunnyOutline, thermometerOutline } from 'ionicons/icons'; - -export const SkeletonDashboard = () => ( - - - - -

- -

-
- -
- - - - - -

- -

-
- - -

- -

-
-
- - - - - - - - - - - wind - - - - Wind - - - - - - - - - - - - - - - Feels like - - - - - - - - - - - - - - - - - Index UV - - - - - - - - - - - - - - - Pressure - - - - - - - - -
-
-
-);