diff --git a/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.css b/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.css new file mode 100644 index 0000000..e99f514 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.css @@ -0,0 +1,24 @@ +.container { + text-align: center; + position: absolute; + left: 0; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.container strong { + font-size: 20px; + line-height: 26px; +} + +.container p { + font-size: 16px; + line-height: 22px; + color: #8c8c8c; + margin: 0; +} + +.container a { + text-decoration: none; +} \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.js b/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.js new file mode 100644 index 0000000..4f60628 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/components/ExploreContainer.js @@ -0,0 +1,12 @@ +import './ExploreContainer.css'; + +const ExploreContainer = () => { + return ( +
+ Ready to create an app? +

Start with Ionic UI Components

+
+ ); +}; + +export default ExploreContainer; diff --git a/03_source/mobile/src/pages/DemoReactItemList/index.tsx b/03_source/mobile/src/pages/DemoReactItemList/index.tsx index f5bfc42..3fabe7c 100644 --- a/03_source/mobile/src/pages/DemoReactItemList/index.tsx +++ b/03_source/mobile/src/pages/DemoReactItemList/index.tsx @@ -1,28 +1,26 @@ -import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react'; +import { IonRouterOutlet, IonTabs } from '@ionic/react'; -import { cloudOutline, searchOutline } from 'ionicons/icons'; import { Route, Redirect } from 'react-router'; -import Tab1 from './AppPages/Tab1'; -import Tab2 from './AppPages/Tab2'; - -import './style.scss'; +import './theme/variables.scss'; +import Home from './pages/Home'; +import Movies from './pages/Movies'; function DemoReactItemList() { return ( - - + + - - + + - + - {/* */} + {/* @@ -33,6 +31,7 @@ function DemoReactItemList() { Search + */} ); } diff --git a/03_source/mobile/src/pages/DemoReactItemList/module.d.ts b/03_source/mobile/src/pages/DemoReactItemList/module.d.ts new file mode 100644 index 0000000..4af7be7 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/module.d.ts @@ -0,0 +1,9 @@ +declare module '*.module.css' { + const classes: { readonly [key: string]: string }; + export default classes; +} + +declare module '*.module.scss' { + const classes: { readonly [key: string]: string }; + export default classes; +} diff --git a/03_source/mobile/src/pages/DemoReactItemList/pages/Home.module.scss b/03_source/mobile/src/pages/DemoReactItemList/pages/Home.module.scss new file mode 100644 index 0000000..bbd295d --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/pages/Home.module.scss @@ -0,0 +1,127 @@ +.page { + ion-header { + background-color: #5a55ca; + } + + ion-toolbar { + --border-style: none; + --background: #5a55ca; + --color: white; + --min-height: 8rem; + + // --stripe: #645fd1; + --stripe: #5a55ca; + --bg: #645fd1; + --background: transparent; + background: + linear-gradient(135deg, var(--bg) 25%, transparent 25%) -50px 0, + linear-gradient(225deg, var(--bg) 25%, transparent 25%) -50px 0, + linear-gradient(315deg, var(--bg) 25%, transparent 25%), + linear-gradient(45deg, var(--bg) 25%, transparent 25%); + background-size: 100px 100px; + background-color: var(--stripe); + + ion-button { + font-size: 1.2rem; + font-weight: 800; + } + } + + ion-content { + --background: #5a55ca; + overflow: hidden; + } + + ion-card-subtitle { + padding-left: 1.2rem; + margin-top: 1.9rem; + padding-bottom: 0.3rem; + --color: white; + } + + .results { + --color: #5a55ca; + } + + ion-searchbar { + --border-radius: 10px; + --background: white; + --color: black; + min-height: 5rem; + padding: 1rem; + padding-top: 0; + margin-top: -1rem; + } + + ion-list { + background-color: #e7edfb; + } + + ion-footer { + background-color: #e7edfb; + padding: 1rem; + + ion-button { + --background: #5a55ca; + --background-focused: #6f6bbb; + --background-activated: #6f6bbb; + --padding-top: 1rem; + --padding-bottom: 1rem; + --padding-start: 0.75rem; + --padding-end: 0.75rem; + height: 3.5rem; + font-weight: 700; + } + } +} + +.mainContent { + background-color: #e7edfb; + height: 100%; + width: 100%; + overflow: scroll !important; + border-top-left-radius: 30px; + border-top-right-radius: 30px; +} + +.employeeItem { + --border-radius: 10px; + --padding-start: 1rem; + --padding-end: 1rem; + --padding-top: 1rem; + --padding-bottom: 1rem; + padding: 1rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + min-height: 5rem; + + img { + width: 3rem; + border-radius: 10px; + border: 2px solid #e7edfb; + } + + ion-label { + padding-left: 1.2rem; + + h2 { + font-weight: 600; + letter-spacing: -0.02rem; + } + + p { + letter-spacing: -0.03rem; + } + } + + ion-button { + --background: #5a55ca; + --background-focused: #6f6bbb; + --background-activated: #6f6bbb; + --padding-top: 1rem; + --padding-bottom: 1rem; + --padding-start: 0.75rem; + --padding-end: 0.75rem; + margin-top: -0.2rem; + } +} diff --git a/03_source/mobile/src/pages/DemoReactItemList/pages/Home.tsx b/03_source/mobile/src/pages/DemoReactItemList/pages/Home.tsx new file mode 100644 index 0000000..f631a9a --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/pages/Home.tsx @@ -0,0 +1,152 @@ +import { + IonButton, + IonButtons, + IonCardSubtitle, + IonContent, + IonFooter, + IonHeader, + IonIcon, + IonItem, + IonLabel, + IonList, + IonPage, + IonSearchbar, + IonToolbar, +} from '@ionic/react'; +import { chevronBack, chevronForward, trashOutline } from 'ionicons/icons'; +import { useEffect, useState } from 'react'; +import styles from './Home.module.scss'; + +const Home = () => { + const [employees, setEmployees] = useState([ + { + id: 1, + name: 'Alan Montgomery', + title: 'Mobile Team Lead', + avatar: 'https://pbs.twimg.com/profile_images/1383061489469292548/5dhsPd4j_400x400.jpg', + }, + { + id: 2, + name: 'Max Lynch', + title: 'CEO | Co Founder', + avatar: 'https://pbs.twimg.com/profile_images/1318970727173885953/bln98FNj_400x400.jpg', + }, + { + id: 3, + name: 'Mike Hartington', + title: 'Senior Dev Rel', + avatar: 'https://pbs.twimg.com/profile_images/1084993841898446849/DJ8XtR6L_400x400.jpg', + }, + { + id: 4, + name: 'Matt Netkow', + title: 'Head of Product Marketing', + avatar: 'https://pbs.twimg.com/profile_images/1323383930150621187/GKc0nVzi_400x400.jpg', + }, + { + id: 5, + name: 'Ben Sperry', + title: 'CDO | Co Founder', + avatar: 'https://pbs.twimg.com/profile_images/1328390491126308864/jHHgl5Dm_400x400.jpg', + }, + { + id: 6, + name: 'Liam DeBeasi', + title: 'Software Engineer', + avatar: 'https://pbs.twimg.com/profile_images/1105953692669366273/ZNK4lRAJ_400x400.jpg', + }, + ]); + + const [results, setResults] = useState(employees); + + const remove = (id) => { + document.getElementById(`employeeItem_${id}`).classList.add('animate__slideOutRight'); + + setTimeout(() => { + const tempEmployees = [...employees]; + const newEmployees = tempEmployees.filter((e) => parseInt(e.id) !== parseInt(id)); + setResults(newEmployees); + setEmployees(newEmployees); + }, 700); + }; + + const search = (e) => { + const searchTerm = e.currentTarget.value; + + if (searchTerm !== '') { + const searchTermLower = searchTerm.toLowerCase(); + + const newResults = employees.filter((e) => e.name.toLowerCase().includes(searchTermLower)); + setResults(newResults); + } else { + setResults(employees); + } + }; + + return ( + + + + + + +  Employee List + + + + + + Movies  + + + + + + + +
+ + {results.length} {results.legnth === 1 ? 'employee' : 'employees'} found + + search(e)} + onKeyPress={(e) => search(e)} + placeholder="Search..." + icon={search} + slot="end" + /> + + + {results.map((employee, index) => { + return ( + + employee avatar + + +

{employee.name}

+

{employee.title}

+
+ + remove(employee.id)}> + + +
+ ); + })} +
+
+
+ + + Add new employee + +
+ ); +}; + +export default Home; diff --git a/03_source/mobile/src/pages/DemoReactItemList/pages/Movies.tsx b/03_source/mobile/src/pages/DemoReactItemList/pages/Movies.tsx new file mode 100644 index 0000000..28946b2 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/pages/Movies.tsx @@ -0,0 +1,154 @@ +import { IonButton, IonButtons, IonCardSubtitle, IonContent, IonFooter, IonHeader, IonIcon, IonInfiniteScroll, IonInfiniteScrollContent, IonItem, IonLabel, IonList, IonPage, IonRow, IonSearchbar, IonToolbar } from '@ionic/react'; +import { chevronBack, trashOutline } from 'ionicons/icons'; +import { useEffect, useState } from 'react'; +import styles from './Home.module.scss'; + +const Movies = () => { + + const [ movies, setMovies ] = useState([]); + const [ currentPage, setCurrentPage ] = useState(1); + const [ searchTerm, setSearchTerm ] = useState(""); + const [ totalResults, setTotalResults ] = useState(0); + + const search = (e) => { + + const searchTermVal = e.currentTarget.value; + + if (searchTermVal !== "") { + + const searchTermLower = searchTermVal.toLowerCase(); + searchData(searchTermLower); + setSearchTerm(searchTermLower); + } else { + + getData(true, 1); + setSearchTerm(""); + setCurrentPage(1); + } + } + + const searchData = async (searchTermVal, page = 1) => { + + const imageBaseURL = "https://image.tmdb.org/t/p/w200"; + const response = await fetch(`https://api.themoviedb.org/3/search/movie?api_key=24600637ab41d89f6dd63b4c52e8b14e&query=${ searchTermVal }&page=${ page }`); + const data = await response.json(); + + data.results.forEach(movie => { + + var imageURL = ""; + + if (movie.poster_path !== null) { + + imageURL = `${ imageBaseURL }${ movie.poster_path }`; + } else { + + imageURL = "https://critics.io/img/movies/poster-placeholder.png"; + } + + movie.image = imageURL; + }); + + console.log("in more"); + console.log(data.results); + + setTotalResults(data.total_results); + page === 1 ? setMovies(data.results) : setMovies([ ...movies, ...data.results ]); + } + + const getData = async (initialFetch = true, page = 1) => { + + if (initialFetch) { + + console.log("initial fetch of movies"); + } + const imageBaseURL = "https://image.tmdb.org/t/p/w200"; + const response = await fetch(`https://api.themoviedb.org/3/movie/popular?api_key=24600637ab41d89f6dd63b4c52e8b14e&page=${ page }`); + const data = await response.json(); + + data.results.forEach(movie => { + + var imageURL = ""; + + if (movie.poster_path !== null) { + + imageURL = `${ imageBaseURL }${ movie.poster_path }`; + } else { + + imageURL = "https://critics.io/img/movies/poster-placeholder.png"; + } + + movie.image = imageURL; + }); + + console.log(data); + + setTotalResults(data.total_results); + initialFetch ? setMovies(data.results) : setMovies([ ...movies, ...data.results ]); + } + + useEffect(() => { + + getData(); + }, []); + + const fetchMore = async e => { + + console.log("in more"); + const newPage = currentPage + 1; + await setCurrentPage(newPage); + + searchTerm === "" ? getData(false, newPage) : searchData(searchTerm, newPage); + e.target.complete(); + } + + return ( + + + + + + + +  Movie List + + + +
+ { totalResults } { (totalResults === 1) ? "movie" : "movies" } found + search(e) } onKeyPress={ e => search(e) } placeholder="Search..." icon={ search } slot="end" /> +
+
+
+ + + + { movies.map((movie, index) => { + + return ( + + + employee avatar + + +

{ movie.title }

+

{ movie.overview }

+
+
+ ); + })} + + + + + +
+
+ + + Add a Movie + +
+ ); +}; + +export default Movies; \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoReactItemList/react-app-env.d.ts b/03_source/mobile/src/pages/DemoReactItemList/react-app-env.d.ts new file mode 100644 index 0000000..6431bc5 --- /dev/null +++ b/03_source/mobile/src/pages/DemoReactItemList/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/03_source/mobile/src/pages/DemoReactItemList/style.scss b/03_source/mobile/src/pages/DemoReactItemList/style.scss deleted file mode 100644 index 37c1e1a..0000000 --- a/03_source/mobile/src/pages/DemoReactItemList/style.scss +++ /dev/null @@ -1,103 +0,0 @@ -#about-page { - ion-toolbar { - position: absolute; - - top: 0; - left: 0; - right: 0; - - --background: transparent; - --color: white; - } - - 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; - } - - /* - * iOS Only - */ - - .ios .about-info { - --ion-padding: 19px; - } - - .ios .about-info h3 { - font-weight: 700; - } -} - -#date-input-popover { - --offset-y: -var(--ion-safe-area-bottom); - - --max-width: 90%; - --width: 336px; -} diff --git a/03_source/mobile/src/pages/DemoReactItemList/theme/variables.scss b/03_source/mobile/src/pages/DemoReactItemList/theme/variables.scss index 363baa2..e69de29 100644 --- a/03_source/mobile/src/pages/DemoReactItemList/theme/variables.scss +++ b/03_source/mobile/src/pages/DemoReactItemList/theme/variables.scss @@ -1,98 +0,0 @@ -.demo-react-item-list { - /* Ionic Variables and Theming. For more info, please see: -http://ionicframework.com/docs/theming/ */ - - * { - font-family: 'Poppins', sans-serif; - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - -webkit-font-feature-settings: 'calt' on; - font-feature-settings: 'calt' on; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important; - -webkit-text-size-adjust: 100%; - } - - /** Ionic CSS Variables **/ - :root { - /** primary **/ - --ion-color-primary: #3880ff; - --ion-color-primary-rgb: 56, 128, 255; - --ion-color-primary-contrast: #ffffff; - --ion-color-primary-contrast-rgb: 255, 255, 255; - --ion-color-primary-shade: #3171e0; - --ion-color-primary-tint: #4c8dff; - - /** 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: #f4f5f8; - --ion-color-light-rgb: 244, 245, 248; - --ion-color-light-contrast: #000000; - --ion-color-light-contrast-rgb: 0, 0, 0; - --ion-color-light-shade: #d7d8da; - --ion-color-light-tint: #f5f6f9; - } - - input.searchbar-input { - padding-top: 1.5rem !important; - padding-bottom: 1.5rem !important; - } - - ion-searchbar ion-icon { - margin-top: 0.4rem; - } -}