From d6c87e33f04e1fb345ee806773c9aaf4060b8c48 Mon Sep 17 00:00:00 2001 From: louiscklaw Date: Fri, 6 Jun 2025 14:22:22 +0800 Subject: [PATCH] update demo pull state, --- .../components/Person.tsx | 24 ++++++ .../pages/DemoPullstateTutorial/data/index.js | 45 +++++++++++ .../src/pages/DemoPullstateTutorial/index.tsx | 18 +++-- .../DemoPullstateTutorial/pages/Tab1.css | 0 .../DemoPullstateTutorial/pages/Tab1.tsx | 63 +++++++++++++++ .../DemoPullstateTutorial/pages/Tab2.css | 0 .../DemoPullstateTutorial/pages/Tab2.tsx | 34 ++++++++ .../store/PeopleStore.js | 19 +++++ .../DemoPullstateTutorial/store/Selectors.js | 7 ++ .../DemoPullstateTutorial/store/index.js | 1 + .../theme/variables.scss | 79 +++++++++++++++++++ 11 files changed, 282 insertions(+), 8 deletions(-) create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/components/Person.tsx create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/data/index.js create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.css create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.tsx create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.css create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.tsx create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/store/PeopleStore.js create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/store/Selectors.js create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/store/index.js create mode 100644 03_source/mobile/src/pages/DemoPullstateTutorial/theme/variables.scss diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/components/Person.tsx b/03_source/mobile/src/pages/DemoPullstateTutorial/components/Person.tsx new file mode 100644 index 0000000..2edc34d --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/components/Person.tsx @@ -0,0 +1,24 @@ +import { IonAvatar, IonButton, IonItem, IonLabel } from '@ionic/react'; +import { toggleFollowing } from '../store/PeopleStore'; + +export const Person = ({ person }): React.JSX.Element => { + return ( + + + avatar + + +

{person.name}

+

{person.title}

+
+ + toggleFollowing(person.id)} + > + {person.following ? 'Following' : 'Follow'} + +
+ ); +}; diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/data/index.js b/03_source/mobile/src/pages/DemoPullstateTutorial/data/index.js new file mode 100644 index 0000000..9e1fff8 --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/data/index.js @@ -0,0 +1,45 @@ +export const people = [ + + { + id: 1, + name: "Alan Montgomery", + title: "Mobile Team Lead", + avatar: "https://pbs.twimg.com/profile_images/1420489989163524096/GwHdYSky_400x400.jpg", + following: false + }, + { + id: 2, + name: "Max Lynch", + title: "CEO | Co Founder", + avatar: "https://pbs.twimg.com/profile_images/1318970727173885953/bln98FNj_400x400.jpg", + following: false + }, + { + id: 3, + name: "Mike Hartington", + title: "Senior Dev Rel", + avatar: "https://pbs.twimg.com/profile_images/1084993841898446849/DJ8XtR6L_400x400.jpg", + following: false + }, + { + id: 4, + name: "Matt Netkow", + title: "Head of Product Marketing", + avatar: "https://pbs.twimg.com/profile_images/1323383930150621187/GKc0nVzi_400x400.jpg", + following: false + }, + { + id: 5, + name: "Ben Sperry", + title: "CDO | Co Founder", + avatar: "https://pbs.twimg.com/profile_images/1407747959345795072/McJb-RvC_400x400.jpg", + following: false + }, + { + id: 6, + name: "Liam DeBeasi", + title: "Software Engineer", + avatar: "https://pbs.twimg.com/profile_images/1105953692669366273/ZNK4lRAJ_400x400.jpg", + following: false + } +]; \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/index.tsx b/03_source/mobile/src/pages/DemoPullstateTutorial/index.tsx index 0b8f21b..f5313e3 100644 --- a/03_source/mobile/src/pages/DemoPullstateTutorial/index.tsx +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/index.tsx @@ -1,16 +1,18 @@ import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react'; -import { cloudOutline, searchOutline } from 'ionicons/icons'; +import { list, people } from 'ionicons/icons'; import { Route, Redirect } from 'react-router'; -import Tab1 from './AppPages/Tab1'; -import Tab2 from './AppPages/Tab2'; +// import Tab1 from './AppPages/Tab1'; +// import Tab2 from './AppPages/Tab2'; import './style.scss'; +import Tab1 from './pages/Tab1'; +import Tab2 from './pages/Tab2'; function DemoPullstateTutorial() { return ( - + @@ -25,12 +27,12 @@ function DemoPullstateTutorial() { {/* */} - - Dashboard + + List - - Search + + Following diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.css b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.css new file mode 100644 index 0000000..e69de29 diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.tsx b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.tsx new file mode 100644 index 0000000..98513db --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab1.tsx @@ -0,0 +1,63 @@ +import { + IonButton, + IonButtons, + IonContent, + IonHeader, + IonIcon, + IonPage, + IonTitle, + IonToolbar, + useIonRouter, +} from '@ionic/react'; +import { PeopleStore } from '../store'; +import { Person } from '../components/Person'; +import './Tab1.css'; +import { useStoreState } from 'pullstate'; +import { getPeople } from '../store/Selectors'; +import { chevronBackOutline } from 'ionicons/icons'; + +const Tab1 = (): React.JSX.Element => { + const people = useStoreState(PeopleStore, getPeople); + + console.log(people); + + const router = useIonRouter(); + function handleBackClick() { + router.goBack(); + } + + return ( + + + + List of People + + + handleBackClick()}> + + + + + + + + + List of People + + + handleBackClick()}> + + + + + + + {people.map((person, index) => { + return ; + })} + + + ); +}; + +export default Tab1; diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.css b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.css new file mode 100644 index 0000000..e69de29 diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.tsx b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.tsx new file mode 100644 index 0000000..7a95a49 --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/pages/Tab2.tsx @@ -0,0 +1,34 @@ +import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react'; +import { useStoreState } from 'pullstate'; +import { Person } from '../components/Person'; +import { PeopleStore } from '../store'; +import { getFollowing } from '../store/Selectors'; +import './Tab2.css'; +import React from 'react'; + +const Tab2 = (): React.JSX.Element => { + const people = useStoreState(PeopleStore, getFollowing); + + return ( + + + + Following + + + + + + Following + + + + {people.map((person, index) => { + return ; + })} + + + ); +}; + +export default Tab2; diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/store/PeopleStore.js b/03_source/mobile/src/pages/DemoPullstateTutorial/store/PeopleStore.js new file mode 100644 index 0000000..e80c158 --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/store/PeopleStore.js @@ -0,0 +1,19 @@ +import { Store } from "pullstate"; + +import { people } from "../data"; + +const PeopleStore = new Store({ + + people: people +}); + +export const toggleFollowing = personId => { + + PeopleStore.update(s => { + + const personIndex = s.people.findIndex(person => person.id === personId); + s.people[personIndex].following = !s.people[personIndex].following; + }); +} + +export default PeopleStore; \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/store/Selectors.js b/03_source/mobile/src/pages/DemoPullstateTutorial/store/Selectors.js new file mode 100644 index 0000000..1c3bdc6 --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/store/Selectors.js @@ -0,0 +1,7 @@ +import { createSelector } from "reselect"; + +const getState = state => state; + +// Gets +export const getPeople = createSelector(getState, state => state.people); +export const getFollowing = createSelector(getState, state => state.people.filter(person => person.following)); \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/store/index.js b/03_source/mobile/src/pages/DemoPullstateTutorial/store/index.js new file mode 100644 index 0000000..9beff78 --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/store/index.js @@ -0,0 +1 @@ +export { default as PeopleStore } from "./PeopleStore"; \ No newline at end of file diff --git a/03_source/mobile/src/pages/DemoPullstateTutorial/theme/variables.scss b/03_source/mobile/src/pages/DemoPullstateTutorial/theme/variables.scss new file mode 100644 index 0000000..8606e9f --- /dev/null +++ b/03_source/mobile/src/pages/DemoPullstateTutorial/theme/variables.scss @@ -0,0 +1,79 @@ +.demo-pullstate-tutorial { + /* Ionic Variables and Theming. For more info, please see: +http://ionicframework.com/docs/theming/ */ + + /** 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; + } +}