Compare commits
8 Commits
df9992454b
...
develop/mo
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d909805283 | ||
![]() |
8c46a93e61 | ||
![]() |
82507b4b31 | ||
![]() |
85651ff204 | ||
![]() |
9caca30e1e | ||
![]() |
d76d43d17f | ||
![]() |
dff07ddcb0 | ||
![]() |
b78709db9b |
@@ -1,6 +1,15 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100
|
||||
"printWidth": 160,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "src/App.tsx",
|
||||
"options": {
|
||||
"printWidth": 240
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -9,7 +9,11 @@ android {
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-barcode-scanner')
|
||||
implementation project(':capacitor-clipboard')
|
||||
implementation project(':capacitor-geolocation')
|
||||
implementation project(':capacitor-preferences')
|
||||
implementation project(':capacitor-share')
|
||||
|
||||
}
|
||||
|
||||
|
@@ -2,5 +2,17 @@
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-barcode-scanner'
|
||||
project(':capacitor-barcode-scanner').projectDir = new File('../node_modules/@capacitor/barcode-scanner/android')
|
||||
|
||||
include ':capacitor-clipboard'
|
||||
project(':capacitor-clipboard').projectDir = new File('../node_modules/@capacitor/clipboard/android')
|
||||
|
||||
include ':capacitor-geolocation'
|
||||
project(':capacitor-geolocation').projectDir = new File('../node_modules/@capacitor/geolocation/android')
|
||||
|
||||
include ':capacitor-preferences'
|
||||
project(':capacitor-preferences').projectDir = new File('../node_modules/@capacitor/preferences/android')
|
||||
|
||||
include ':capacitor-share'
|
||||
project(':capacitor-share').projectDir = new File('../node_modules/@capacitor/share/android')
|
||||
|
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
while true; do
|
||||
npm i -D
|
||||
yarn -D
|
||||
|
||||
npm run dev
|
||||
yarn run dev
|
||||
|
||||
echo "restarting..."
|
||||
sleep 1
|
||||
|
@@ -11,7 +11,11 @@ install! 'cocoapods', :disable_input_output_paths => true
|
||||
def capacitor_pods
|
||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorBarcodeScanner', :path => '../../node_modules/@capacitor/barcode-scanner'
|
||||
pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard'
|
||||
pod 'CapacitorGeolocation', :path => '../../node_modules/@capacitor/geolocation'
|
||||
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
||||
pod 'CapacitorShare', :path => '../../node_modules/@capacitor/share'
|
||||
end
|
||||
|
||||
target 'App' do
|
||||
|
6965
03_source/mobile/package-lock.json
generated
@@ -7,24 +7,35 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@capacitor/android": "7.0.1",
|
||||
"@capacitor/barcode-scanner": "^2.0.3",
|
||||
"@capacitor/clipboard": "^7.0.1",
|
||||
"@capacitor/core": "^7.0.0",
|
||||
"@capacitor/geolocation": "^7.1.2",
|
||||
"@capacitor/ios": "7.0.1",
|
||||
"@capacitor/preferences": "^7.0.0",
|
||||
"@capacitor/share": "^7.0.1",
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
"@ionic/react": "^8.5.0",
|
||||
"@ionic/react-router": "^8.5.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@react-hook/window-size": "^3.1.1",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@types/react-redux": "^7.1.34",
|
||||
"axios": "^1.9.0",
|
||||
"date-fns": "^2.25.0",
|
||||
"ionicons": "^7.1.2",
|
||||
"leaflet": "^1.9.4",
|
||||
"pigeon-maps": "^0.22.1",
|
||||
"pullstate": "^1",
|
||||
"react": "19.0.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-confetti": "^6.4.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-hook-form": "^7.55.0",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-qr-code": "^2.0.15",
|
||||
"react-qr-reader": "^3.0.0-beta-1",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^5.3.4",
|
||||
"react-router-dom": "^5.3.4",
|
||||
@@ -32,7 +43,8 @@
|
||||
"react-use": "^17.6.0",
|
||||
"reselect": "^4.0.0",
|
||||
"sass": "^1.85.1",
|
||||
"swiper": "^9.1.1",
|
||||
"swiper": "^11.2.8",
|
||||
"use-sound": "^5.0.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -64,7 +76,7 @@
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"lint-staged": "^13.2.0",
|
||||
"prettier": "^2.8.6",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "^5.8.2",
|
||||
"vite": "^6.2.0"
|
||||
},
|
||||
|
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/DemoDictionaryApp/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/DemoQuizApp/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/DemoQuizApp/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/DemoQuizApp/main.png
Normal file
After Width: | Height: | Size: 39 KiB |
1
03_source/mobile/public/assets/DemoQuizApp/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/DemoRecipeApp/bookmark.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/DemoRecipeApp/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/DemoRecipeApp/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/DemoRecipeApp/placeholder.png
Normal file
After Width: | Height: | Size: 42 KiB |
1
03_source/mobile/public/assets/DemoRecipeApp/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/DemoShopAppUi/cart.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
03_source/mobile/public/assets/DemoShopAppUi/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/DemoShopAppUi/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
1
03_source/mobile/public/assets/DemoShopAppUi/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/DemoShopAppUi/shop.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/autumn.png
Normal file
After Width: | Height: | Size: 235 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar.jpeg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar1.png
Normal file
After Width: | Height: | Size: 358 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar2.png
Normal file
After Width: | Height: | Size: 424 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar3.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar4.png
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar5.png
Normal file
After Width: | Height: | Size: 264 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/avatar6.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/cover1.jpeg
Normal file
After Width: | Height: | Size: 249 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/cover2.jpeg
Normal file
After Width: | Height: | Size: 216 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/cover4.jpeg
Normal file
After Width: | Height: | Size: 180 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/cover5.jpeg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/cover6.jpeg
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/flower.jpeg
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/h.jpeg
Normal file
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/ocean.jpeg
Normal file
After Width: | Height: | Size: 64 KiB |
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/spring.png
Normal file
After Width: | Height: | Size: 288 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/summer.png
Normal file
After Width: | Height: | Size: 210 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/van.jpeg
Normal file
After Width: | Height: | Size: 174 KiB |
BIN
03_source/mobile/public/assets/DemoSlidingProfile/winter.png
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
03_source/mobile/public/assets/ScoreBoard/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/ScoreBoard/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 682 KiB |
After Width: | Height: | Size: 820 KiB |
BIN
03_source/mobile/public/assets/ScoreBoard/scoreboardheader.jpeg
Normal file
After Width: | Height: | Size: 49 KiB |
1
03_source/mobile/public/assets/ScoreBoard/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/WeatherDemo/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/WeatherDemo/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/WeatherDemo/map.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
1
03_source/mobile/public/assets/WeatherDemo/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/WeatherDemo/temp.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
03_source/mobile/public/assets/WeatherDemo/temp2.png
Normal file
After Width: | Height: | Size: 971 B |
BIN
03_source/mobile/public/assets/WeatherDemo/wind.png
Normal file
After Width: | Height: | Size: 896 B |
BIN
03_source/mobile/public/assets/react-shop/beds.jpeg
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
03_source/mobile/public/assets/react-shop/coats3.jpeg
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
03_source/mobile/public/assets/react-shop/coffee_table.jpeg
Normal file
After Width: | Height: | Size: 389 KiB |
BIN
03_source/mobile/public/assets/react-shop/dresses3.jpeg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
03_source/mobile/public/assets/react-shop/formal_shirts2.jpeg
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
03_source/mobile/public/assets/react-shop/home.jpeg
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
03_source/mobile/public/assets/react-shop/icon/favicon.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
03_source/mobile/public/assets/react-shop/icon/icon.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
03_source/mobile/public/assets/react-shop/jeans.jpeg
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
03_source/mobile/public/assets/react-shop/makeup2.jpeg
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
03_source/mobile/public/assets/react-shop/men.jpeg
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
03_source/mobile/public/assets/react-shop/office.jpeg
Normal file
After Width: | Height: | Size: 82 KiB |
1
03_source/mobile/public/assets/react-shop/shapes.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="350" height="140" xmlns="http://www.w3.org/2000/svg" style="background:#f6f7f9"><g fill="none" fill-rule="evenodd"><path fill="#F04141" style="mix-blend-mode:multiply" d="M61.905-34.23l96.194 54.51-66.982 54.512L22 34.887z"/><circle fill="#10DC60" style="mix-blend-mode:multiply" cx="155.5" cy="135.5" r="57.5"/><path fill="#3880FF" style="mix-blend-mode:multiply" d="M208.538 9.513l84.417 15.392L223.93 93.93z"/><path fill="#FFCE00" style="mix-blend-mode:multiply" d="M268.625 106.557l46.332-26.75 46.332 26.75v53.5l-46.332 26.75-46.332-26.75z"/><circle fill="#7044FF" style="mix-blend-mode:multiply" cx="299.5" cy="9.5" r="38.5"/><rect fill="#11D3EA" style="mix-blend-mode:multiply" transform="rotate(-60 148.47 37.886)" x="143.372" y="-7.056" width="10.196" height="89.884" rx="5.098"/><path d="M-25.389 74.253l84.86 8.107c5.498.525 9.53 5.407 9.004 10.905a10 10 0 0 1-.057.477l-12.36 85.671a10.002 10.002 0 0 1-11.634 8.42l-86.351-15.226c-5.44-.959-9.07-6.145-8.112-11.584l13.851-78.551a10 10 0 0 1 10.799-8.219z" fill="#7044FF" style="mix-blend-mode:multiply"/><circle fill="#0CD1E8" style="mix-blend-mode:multiply" cx="273.5" cy="106.5" r="20.5"/></g></svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
03_source/mobile/public/assets/react-shop/sportswear2.jpeg
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
03_source/mobile/public/assets/react-shop/women.jpeg
Normal file
After Width: | Height: | Size: 47 KiB |
@@ -64,6 +64,33 @@ import ServiceAgreement from './pages/ServiceAgreement';
|
||||
import paths from './paths';
|
||||
import PrivacyAgreement from './pages/PrivacyAgreement';
|
||||
import AppRoute from './AppRoute';
|
||||
//
|
||||
import DemoReactShop from './pages/DemoReactShop';
|
||||
import DemoWeatherApp from './pages/DemoWeatherApp';
|
||||
import DemoClubHouse from './pages/DemoClubHouse';
|
||||
import DemoScoreBoard from './pages/DemoScoreBoard';
|
||||
import DemoQuoteApp from './pages/DemoQuoteApp';
|
||||
import DemoQrScanner from './pages/DemoQrScanner';
|
||||
// DemoShopAppUi
|
||||
import DemoShopAppUi from './pages/DemoShopAppUi';
|
||||
// DemoDictionaryApp
|
||||
import DemoDictionaryApp from './pages/DemoDictionaryApp';
|
||||
// demo-recipe-app
|
||||
import DemoRecipeApp from './pages/DemoRecipeApp';
|
||||
|
||||
// DemoSlidingProfile
|
||||
import DemoSlidingProfile from './pages/DemoSlidingProfile';
|
||||
|
||||
// DemoQuizApp
|
||||
import DemoQuizApp from './pages/DemoQuizApp';
|
||||
import DemoBlogPostUi from './pages/DemoBlogPostUi';
|
||||
import DemoReactTravelApp from './pages/DemoReactTravelApp';
|
||||
import DemoPinterestFloatingTabBar from './pages/DemoPinterestFloatingTabBar';
|
||||
import DemoRestaurantFinder from './pages/DemoRestaurantFinder';
|
||||
import DemoReactOverlayHooks from './pages/DemoReactOverlayHooks';
|
||||
import DemoReactSwitchTabs from './pages/DemoReactSwitchTabs';
|
||||
import DemoReactPollApp from './pages/DemoReactPollApp';
|
||||
import DemoReactWhatsAppClone from './pages/DemoReactWhatsAppClone';
|
||||
|
||||
setupIonicReact();
|
||||
|
||||
@@ -89,14 +116,7 @@ interface DispatchProps {
|
||||
|
||||
interface IonicAppProps extends StateProps, DispatchProps {}
|
||||
|
||||
const IonicApp: React.FC<IonicAppProps> = ({
|
||||
darkMode,
|
||||
schedule,
|
||||
setIsLoggedIn,
|
||||
setUsername,
|
||||
loadConfData,
|
||||
loadUserData,
|
||||
}) => {
|
||||
const IonicApp: React.FC<IonicAppProps> = ({ darkMode, schedule, setIsLoggedIn, setUsername, loadConfData, loadUserData }) => {
|
||||
useEffect(() => {
|
||||
loadUserData();
|
||||
loadConfData();
|
||||
@@ -119,10 +139,34 @@ const IonicApp: React.FC<IonicAppProps> = ({
|
||||
|
||||
<AppRoute />
|
||||
|
||||
{/* */}
|
||||
<Route path="/tabs" render={() => <MainTabs />} />
|
||||
|
||||
<Route path={paths.DEMO_WEATHER_APP} render={() => <DemoWeatherApp />} />
|
||||
{/* */}
|
||||
{/* */}
|
||||
{/* */}
|
||||
{/* */}
|
||||
<Route path={paths.DEMO_REACT_WHATSAPP_CLONE} render={() => <DemoReactWhatsAppClone />} />
|
||||
|
||||
<Route path={paths.DEMO_REACT_POLL_APP} render={() => <DemoReactPollApp />} />
|
||||
|
||||
<Route path={paths.DEMO_BLOG_POST_UI} render={() => <DemoBlogPostUi />} />
|
||||
<Route path={paths.DEMO_CLUB_HOUSE} render={() => <DemoClubHouse />} />
|
||||
<Route path={paths.DEMO_DICTIONARY_APP} render={() => <DemoDictionaryApp />} />
|
||||
<Route path={paths.DEMO_PINTEREST_FLOATING_TAB_BAR} render={() => <DemoPinterestFloatingTabBar />} />
|
||||
<Route path={paths.DEMO_QR_SCANNER} render={() => <DemoQrScanner />} />
|
||||
<Route path={paths.DEMO_QUIZ_APP} render={() => <DemoQuizApp />} />
|
||||
<Route path={paths.DEMO_QUOTE_APP} render={() => <DemoQuoteApp />} />
|
||||
<Route path={paths.DEMO_REACT_OVERLAY_HOOKS} render={() => <DemoReactOverlayHooks />} />
|
||||
<Route path={paths.DEMO_REACT_POLL_APP} render={() => <DemoReactPollApp />} />
|
||||
<Route path={paths.DEMO_REACT_SHOP} render={() => <DemoReactShop />} />
|
||||
<Route path={paths.DEMO_REACT_SWITCH_TABS} render={() => <DemoReactSwitchTabs />} />
|
||||
<Route path={paths.DEMO_REACT_TRAVEL_APP} render={() => <DemoReactTravelApp />} />
|
||||
<Route path={paths.DEMO_RECIPE_APP} render={() => <DemoRecipeApp />} />
|
||||
<Route path={paths.DEMO_RESTAURANT_FINDER} render={() => <DemoRestaurantFinder />} />
|
||||
<Route path={paths.DEMO_SCORE_BOARD} render={() => <DemoScoreBoard />} />
|
||||
<Route path={paths.DEMO_SHOP_APP_UI} render={() => <DemoShopAppUi />} />
|
||||
<Route path={paths.DEMO_SLIDING_PROFILE} render={() => <DemoSlidingProfile />} />
|
||||
|
||||
<Route path="/account" component={Account} />
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/mylogin" component={MyLogin} />
|
||||
@@ -131,7 +175,6 @@ const IonicApp: React.FC<IonicAppProps> = ({
|
||||
<Route path="/support" component={Support} />
|
||||
<Route path="/tutorial" component={Tutorial} />
|
||||
|
||||
{/* */}
|
||||
<Route
|
||||
path="/logout"
|
||||
render={() => {
|
||||
|
@@ -7,14 +7,12 @@ import NotImplemented from './pages/NotImplemented';
|
||||
import EventDetail from './pages/EventDetail';
|
||||
import MemberProfile from './pages/MemberProfile';
|
||||
import paths from './paths';
|
||||
import Helloworld from './pages/Helloworld';
|
||||
import Settings from './pages/Settings';
|
||||
import ChangeLanguage from './pages/ChangeLanguage';
|
||||
import ServiceAgreement from './pages/ServiceAgreement';
|
||||
import PrivacyAgreement from './pages/PrivacyAgreement';
|
||||
// import OrderDetails from './pages/OrderDetail';
|
||||
import OrderDetail from './pages/OrderDetail';
|
||||
import SpeakerDetail from './pages/SpeakerDetail';
|
||||
|
||||
const AppRoute: React.FC = () => {
|
||||
return (
|
||||
|
@@ -10,6 +10,9 @@ import Favourites from './pages/Favourites';
|
||||
import MyProfile from './pages/MyProfile';
|
||||
import EventList from './pages/EventList';
|
||||
import Helloworld from './pages/Helloworld';
|
||||
// import WeatherDemo from './pages/WeatherDemo/Tab1';
|
||||
import DemoList from './pages/DemoList';
|
||||
// import DemoReactShop from './pages/DemoReactShop';
|
||||
|
||||
const TabAppRoute: React.FC = () => {
|
||||
return (
|
||||
@@ -33,6 +36,12 @@ const TabAppRoute: React.FC = () => {
|
||||
|
||||
{/* */}
|
||||
<Route path={paths.PROFILE} render={() => <MyProfile />} exact={true} />
|
||||
|
||||
{/* */}
|
||||
<Route path="/tabs/demo-list" render={() => <DemoList />} exact={true} />
|
||||
|
||||
{/* */}
|
||||
<Route path="/tabs/helloworld" render={() => <Helloworld />} exact={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@@ -15,13 +15,18 @@ import { endpoints } from '../../pages/MyLogin/endpoints';
|
||||
|
||||
export const loadUserData = () => async (dispatch: React.Dispatch<any>) => {
|
||||
dispatch(setLoading(true));
|
||||
|
||||
const data = await getUserData();
|
||||
dispatch(setData(data));
|
||||
|
||||
dispatch(setLoading(false));
|
||||
};
|
||||
|
||||
export const setLoading = (isLoading: boolean) =>
|
||||
({ type: 'set-user-loading', isLoading } as const);
|
||||
({
|
||||
type: 'set-user-loading',
|
||||
isLoading,
|
||||
} as const);
|
||||
|
||||
export const setData = (data: Partial<UserState>) =>
|
||||
({
|
||||
@@ -30,6 +35,7 @@ export const setData = (data: Partial<UserState>) =>
|
||||
} as const);
|
||||
|
||||
export const logoutUser = () => async (dispatch: React.Dispatch<any>) => {
|
||||
//
|
||||
await setIsLoggedInData(false);
|
||||
dispatch(setUsername());
|
||||
};
|
||||
@@ -44,6 +50,8 @@ export const setIsLoggedIn = (loggedIn: boolean) => async (dispatch: React.Dispa
|
||||
|
||||
export const setUsername = (username?: string) => async (dispatch: React.Dispatch<any>) => {
|
||||
await setUsernameData(username);
|
||||
console.log('setUsername triggered');
|
||||
|
||||
return {
|
||||
type: 'set-username',
|
||||
username,
|
||||
@@ -52,6 +60,7 @@ export const setUsername = (username?: string) => async (dispatch: React.Dispatc
|
||||
|
||||
export const setAccessToken = (token?: string) => async (dispatch: React.Dispatch<any>) => {
|
||||
await setAccessTokenData(token);
|
||||
|
||||
return {
|
||||
type: 'set-access-token',
|
||||
token,
|
||||
@@ -120,5 +129,4 @@ export type UserActions =
|
||||
| ActionType<typeof setHasSeenTutorial>
|
||||
| ActionType<typeof setDarkMode>
|
||||
| ActionType<typeof setAccessToken>
|
||||
// | ActionType<typeof setSession>
|
||||
| ActionType<typeof checkUserSession>;
|
||||
|
@@ -15,11 +15,9 @@ export function userReducer(state: UserState, action: UserActions): UserState {
|
||||
return { ...state, darkMode: action.darkMode };
|
||||
case 'set-is-loggedin':
|
||||
return { ...state, isLoggedin: action.loggedIn };
|
||||
case 'set-access-token':
|
||||
return { ...state, token: action.token };
|
||||
case 'check-user-session':
|
||||
return { ...state, isSessionValid: action.sessionValid };
|
||||
// case 'set-active-session':
|
||||
// return { ...state, session: action.session };
|
||||
// case 'set-access-token':
|
||||
// return { ...state, token: action.token };
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
export interface UserState {
|
||||
isLoggedin: boolean;
|
||||
username?: string;
|
||||
darkMode: boolean;
|
||||
hasSeenTutorial: boolean;
|
||||
loading: boolean;
|
||||
username?: string;
|
||||
hasSeenTutorial: boolean;
|
||||
darkMode: boolean;
|
||||
isLoggedin: boolean;
|
||||
isSessionValid: boolean;
|
||||
session?: any;
|
||||
token?: string;
|
||||
|
@@ -0,0 +1,7 @@
|
||||
.view-post-footer {
|
||||
|
||||
background-color: white;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
IonBackButton,
|
||||
IonBadge,
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonCardSubtitle,
|
||||
IonCardTitle,
|
||||
IonCol,
|
||||
IonContent,
|
||||
IonFooter,
|
||||
IonGrid,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonNote,
|
||||
IonPage,
|
||||
IonRow,
|
||||
IonText,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
} from '@ionic/react';
|
||||
import { bookmarkOutline, shareOutline } from 'ionicons/icons';
|
||||
import { useParams } from 'react-router';
|
||||
import { blogPosts } from '../localData';
|
||||
import './BlogPost.css';
|
||||
|
||||
const BlogPost = () => {
|
||||
const { id } = useParams();
|
||||
const post = blogPosts.filter((post) => parseInt(post.id) === parseInt(id))[0];
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Blog</IonTitle>
|
||||
<IonButtons slot="start">
|
||||
<IonBackButton text="Blog Posts" />
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<img src={post.image} alt="post header" />
|
||||
|
||||
<IonGrid className="ion-padding-start ion-padding-end">
|
||||
<IonRow className="ion-align-items-center ion-justify-content-between">
|
||||
<IonRow className="ion-align-items-center ion-justify-content-between">
|
||||
<img src={post.authorImage} className="post-author-avatar" alt="post author" />
|
||||
<IonCardSubtitle className="ion-no-margin ion-no-padding ion-margin-start">
|
||||
{post.author}
|
||||
</IonCardSubtitle>
|
||||
</IonRow>
|
||||
<IonNote>{post.date}</IonNote>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<IonCardTitle className="post-title">{post.title}</IonCardTitle>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<IonText color="medium">{post.content}</IonText>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
</IonGrid>
|
||||
</IonContent>
|
||||
|
||||
<IonFooter className="view-post-footer">
|
||||
<IonRow className="post-footer ion-align-self-center ion-justify-content-between">
|
||||
<div>
|
||||
<IonButton fill="clear" color="primary">
|
||||
<IonIcon icon={shareOutline} />
|
||||
</IonButton>
|
||||
<IonButton fill="clear" color="primary">
|
||||
<IonIcon icon={bookmarkOutline} />
|
||||
</IonButton>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<IonBadge color="primary" className="post-category">
|
||||
{post.category}
|
||||
</IonBadge>
|
||||
</div>
|
||||
</IonRow>
|
||||
</IonFooter>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPost;
|
51
03_source/mobile/src/pages/DemoBlogPostUi/AppPages/Home.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonContent,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonPage,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
useIonRouter,
|
||||
} from '@ionic/react';
|
||||
import { Post } from '../components/Post';
|
||||
import { blogPosts } from '../localData';
|
||||
import { chevronBackOutline } from 'ionicons/icons';
|
||||
|
||||
const Home = () => {
|
||||
const router = useIonRouter();
|
||||
|
||||
function handleBackClick() {
|
||||
router.goBack();
|
||||
}
|
||||
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Ionic Blog</IonTitle>
|
||||
|
||||
<IonButtons slot="start">
|
||||
<IonButton onClick={() => handleBackClick()}>
|
||||
<IonIcon icon={chevronBackOutline} color="primary" />
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">Ionic Blog</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
{blogPosts.map((post, index) => (
|
||||
<Post post={post} key={`post_${index}`} />
|
||||
))}
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
@@ -0,0 +1,37 @@
|
||||
.post-author-avatar {
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
border-radius: 500px;
|
||||
}
|
||||
|
||||
.post-title {
|
||||
font-size: 1.4rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.post-content {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.post-footer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-content: center;
|
||||
width: 100%;
|
||||
border-top: 2px solid rgb(245, 245, 245);
|
||||
margin-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.post-category {
|
||||
margin-top: 1.1rem;
|
||||
}
|
||||
|
||||
.post-image {
|
||||
width: 100%;
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
IonBadge,
|
||||
IonButton,
|
||||
IonCard,
|
||||
IonCardContent,
|
||||
IonCardHeader,
|
||||
IonCardSubtitle,
|
||||
IonCardTitle,
|
||||
IonIcon,
|
||||
IonNote,
|
||||
IonRow,
|
||||
} from '@ionic/react';
|
||||
import { bookmarkOutline, shareOutline } from 'ionicons/icons';
|
||||
|
||||
import './Post.css';
|
||||
|
||||
export const Post = ({ post }) => {
|
||||
return (
|
||||
<IonCard routerLink={`/demo-blog-post-ui/post/${post.id}`}>
|
||||
<img src={post.image} alt="main post" className="post-image" />
|
||||
|
||||
<IonCardHeader>
|
||||
<IonRow className="ion-align-items-center ion-justify-content-between">
|
||||
<IonRow className="ion-align-items-center ion-justify-content-between">
|
||||
<img src={post.authorImage} className="post-author-avatar" alt="post author" />
|
||||
<IonCardSubtitle className="ion-no-margin ion-no-padding ion-margin-start">
|
||||
{post.author}
|
||||
</IonCardSubtitle>
|
||||
</IonRow>
|
||||
<IonNote>{post.date}</IonNote>
|
||||
</IonRow>
|
||||
<IonCardTitle className="post-title">{post.title}</IonCardTitle>
|
||||
</IonCardHeader>
|
||||
|
||||
<IonCardContent>
|
||||
<p className="post-content">{post.content}</p>
|
||||
|
||||
<IonRow className="post-footer ion-align-self-center ion-justify-content-between">
|
||||
<div>
|
||||
<IonButton fill="clear" color="primary">
|
||||
<IonIcon icon={shareOutline} />
|
||||
</IonButton>
|
||||
<IonButton fill="clear" color="primary">
|
||||
<IonIcon icon={bookmarkOutline} />
|
||||
</IonButton>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<IonBadge color="primary" className="post-category">
|
||||
{post.category}
|
||||
</IonBadge>
|
||||
</div>
|
||||
</IonRow>
|
||||
</IonCardContent>
|
||||
</IonCard>
|
||||
);
|
||||
};
|
27
03_source/mobile/src/pages/DemoBlogPostUi/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { IonIcon, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs } from '@ionic/react';
|
||||
|
||||
import { cloudOutline, searchOutline } from 'ionicons/icons';
|
||||
import { Route, Redirect } from 'react-router';
|
||||
|
||||
import Home from './AppPages/Home';
|
||||
import BlogPost from './AppPages/BlogPost';
|
||||
|
||||
import './style.scss';
|
||||
|
||||
function DemoBlogPostUi() {
|
||||
return (
|
||||
<IonRouterOutlet className="demo-blog-post-ui">
|
||||
<Route exact path="/demo-blog-post-ui/home">
|
||||
<Home />
|
||||
</Route>
|
||||
|
||||
<Route exact path="/demo-blog-post-ui/post/:id">
|
||||
<BlogPost />
|
||||
</Route>
|
||||
|
||||
<Redirect exact path="/demo-blog-post-ui" to="/demo-blog-post-ui/home" />
|
||||
</IonRouterOutlet>
|
||||
);
|
||||
}
|
||||
|
||||
export default DemoBlogPostUi;
|
98
03_source/mobile/src/pages/DemoBlogPostUi/localData/index.js
Normal file
@@ -0,0 +1,98 @@
|
||||
export const blogPosts = [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "How to Convince Your Boss to Choose Ionic",
|
||||
"title_link": "https://ionicframework.com/blog/convince-boss-choose-ionic-app-development/",
|
||||
"date": "August 3, 2021",
|
||||
"author": "By Kim Maida",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2021/07/kim-maida-150x150.jpg",
|
||||
"category": "ANNOUNCEMENTS",
|
||||
"category_link": "https://ionicframework.com/blog//blog/category/announcements",
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/how-to-convince-your-boss_image_1aug2021.png",
|
||||
"content": "Greetings, friend! You’re a web developer, team lead, or engineering manager who has discovered that Ionic products are awesome. They have helped you build cross-platform applications quickly, made the app development process enjoyable, and solved important mobile development problems. You can see that Ionic would be extremely beneficial in your daily job, but are wondering how to convince your boss to endorse the adoption of new software. In a nutshell:"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Ioniconf 2021 Conference Recap",
|
||||
"title_link": "https://ionicframework.com/blog/ioniconf-2021-conference-recap/",
|
||||
"date": "July 29, 2021",
|
||||
"author": "By Mike Hartington",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2018/08/mike-headshot-2-smaller-150x150.png",
|
||||
"category": "ANNOUNCEMENTS",
|
||||
"category_link": "https://ionicframework.com/blog//blog/category/announcements",
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/06/og-imgx2.png",
|
||||
"content": "And with that, Ioniconf 2021 has concluded! Ioniconf, our online conference for Ionic developers and the wider web development community, featured twelve expert Ionic speakers and was attended by many thousands of Ionic community members. We’re thrilled by the community’s reception to the event and are already looking forward to our next event taking place in September. Read on for a recap and links to all recorded talks."
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Announcing Identity Vault 5.0",
|
||||
"title_link": "https://ionicframework.com/blog/announcing-identity-vault-5-0/",
|
||||
"date": "July 28, 2021",
|
||||
"author": "By Dallas James",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2021/07/dallas-james-150x150.jpg",
|
||||
"category": "PRODUCT",
|
||||
"category_link": "https://ionicframework.com/blog//blog/category/announcements",
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/iv-5-feature-image.png",
|
||||
"content": "Today I’m excited to announce Identity Vault 5.0, the newest version of Ionic’s mobile biometrics solution. Featuring the latest in native security best practices, Identity Vault improves frontend security in any Ionic app by making it easy to add secure biometric authentication in minutes."
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Building with Stencil: Clock Component",
|
||||
"title_link": "https://ionicframework.com/blog/building-with-stencil-clock-component/",
|
||||
"date": "July 22, 2021",
|
||||
"author": "By Kevin Hoyt",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2021/07/2520666-150x150.jpg",
|
||||
"category": "ANNOUNCEMENTS",
|
||||
"category_link": "https://ionicframework.com/blog//blog/category/announcements",
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/Image-from-iOS.png",
|
||||
"content": "I have not seen a clock in a web-based user interface in a long time. This makes sense — they are pretty redundant these days. You have a clock on your watch, on your mobile device, and on your desktop, and those are just the digital versions available at a glance. Nonetheless, the process of building a clock can reveal a lot about how a platform works."
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"title": "Building with Stencil: Calendar Component",
|
||||
"title_link": "https://ionicframework.com/blog/building-with-stencil-calendar-component/",
|
||||
"date": "July 19, 2021",
|
||||
"author": "By Kevin Hoyt",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2021/07/2520666-150x150.jpg",
|
||||
"category": "TUTORIALS",
|
||||
"category_link": null,
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/ionic-blog-post-image_first-look-01.png",
|
||||
"content": "Take a look at the month view of a calendar and you will see several rows of numbers. The numbers themselves, increasing in value one after the other, are arranged in columns. HTML and CSS provide us with a number of tools to display content in rows and columns. Making a calendar component should be easy, right? Right?"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "Introducing the New Overlay Hooks for Ionic React",
|
||||
"title_link": "https://ionicframework.com/blog/introducing-the-new-overlay-hooks-for-ionic-react/",
|
||||
"date": "July 14, 2021",
|
||||
"author": "By Ely Lucas",
|
||||
"authorImage": "https://secure.gravatar.com/avatar/45ad19965b4bde97e9f4396ea01ed184?s=32&r=g",
|
||||
"category": "ENGINEERING",
|
||||
"category_link": null,
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/react-overlay-hooks-feature-image.png",
|
||||
"content": "Hello Friends! We know everyone is excited about the new features in Ionic Framework 6.0 beta, but that doesn’t mean we’re done with V5! In Ionic React 5.6, we packaged up a new set of hooks for controlling our overlay components that we think you might like. What is an overlay you ask? It’s the term we give components that display over your current content, such as alerts, modals, toasts, etc."
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"title": "The Future of Stencil: Expanded Team, New Software Platform, and More",
|
||||
"title_link": "https://ionicframework.com/blog/the-future-of-stencil-expanded-team-new-software-platform-and-more/",
|
||||
"date": "July 7, 2021",
|
||||
"author": "By Nick Hyatt",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2018/11/Nick-Hyatt-Headshot-150x150.jpeg",
|
||||
"category": "ANNOUNCEMENTS",
|
||||
"category_link": null,
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/07/stencil-future-feature-image.png",
|
||||
"content": "Today I’m excited to share some news about Stencil, Ionic’s open source toolchain that generates small, fast, and 100% standards-based Web Components that run in every browser. As you might have noticed, we’ve been actively increasing our investments across the entire Ionic App Platform, including the recent launch of Capacitor 3.0, Ionic Portals, tons of Appflow improvements, and the upcoming Ionic Framework v6."
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "Announcing the Ionic Framework v6 Beta",
|
||||
"title_link": "https://ionicframework.com/blog/announcing-the-ionic-framework-v6-beta/",
|
||||
"date": "June 29, 2021",
|
||||
"author": "By Liam DeBeasi",
|
||||
"authorImage": "https://ionicframework.com/blog/wp-content/uploads/2020/01/ZNK4lRAJ_400x400-150x150.jpg",
|
||||
"category": "ANNOUNCEMENTS",
|
||||
"category_link": null,
|
||||
"image": "https://ionicframework.com/blog/wp-content/uploads/2021/06/framework6-feature-image.png",
|
||||
"content": "Earlier this week I had the privilege of giving the Ionic Framework Update at Ioniconf 2021 where we announced the Ionic Framework v6 beta. Ionic Framework has come far from its roots as an AngularJS-only UI library to a truly cross-platform framework for building Web Native applications. As we look to the future of Ionic Framework, let’s talk about some of the improvements coming in Framework v6 and how you can get access to these improvements today."
|
||||
}
|
||||
];
|
79
03_source/mobile/src/pages/DemoBlogPostUi/style.scss
Normal file
@@ -0,0 +1,79 @@
|
||||
.demo-blog-post-ui {
|
||||
/* Ionic Variables and Theming. For more info, please see:
|
||||
http://ionicframework.com/docs/theming/ */
|
||||
|
||||
/** Ionic CSS Variables **/
|
||||
* {
|
||||
/** 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;
|
||||
}
|
||||
}
|
12
03_source/mobile/src/pages/DemoClubHouse/AppPages/Tab1.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.extra-padding {
|
||||
|
||||
padding-right: 1.3rem !important;
|
||||
padding-left: 1.3rem !important;
|
||||
}
|
||||
|
||||
.title {
|
||||
|
||||
font-weight: 600;
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
90
03_source/mobile/src/pages/DemoClubHouse/AppPages/Tab1.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import {
|
||||
IonButton,
|
||||
IonButtons,
|
||||
IonCol,
|
||||
IonContent,
|
||||
IonGrid,
|
||||
IonHeader,
|
||||
IonIcon,
|
||||
IonPage,
|
||||
IonRow,
|
||||
IonText,
|
||||
IonTitle,
|
||||
IonToolbar,
|
||||
useIonRouter,
|
||||
} from '@ionic/react';
|
||||
import { chevronBack, personOutline } from 'ionicons/icons';
|
||||
import { useStoreState } from 'pullstate';
|
||||
import { TalkStore } from '../store';
|
||||
import { getTalks } from '../store/Selectors';
|
||||
import './Tab1.css';
|
||||
|
||||
import { TalkCard } from '../components/TalkCard';
|
||||
import { useRef } from 'react';
|
||||
|
||||
const Tab1 = () => {
|
||||
const pageRef = useRef();
|
||||
const talks = useStoreState(TalkStore, getTalks);
|
||||
|
||||
const router = useIonRouter();
|
||||
function handleBackClick() {
|
||||
router.goBack();
|
||||
}
|
||||
|
||||
return (
|
||||
<IonPage ref={pageRef}>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>All Rooms</IonTitle>
|
||||
|
||||
<IonButtons slot="end">
|
||||
<IonButton>
|
||||
<IonIcon icon={personOutline} />
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
|
||||
<IonButtons slot="start">
|
||||
<IonButton onclick={handleBackClick}>
|
||||
<IonIcon icon={chevronBack} />
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonGrid className="ion-padding-start ion-padding-end extra-padding ion-padding-bottom ion-margin-bottom">
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<IonText color="dark">
|
||||
<p className="title">Upcoming</p>
|
||||
</IonText>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<TalkCard upcoming={true} talk={talks[0]} pageRef={pageRef} />
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<IonText color="dark">
|
||||
<p className="title">Happening Now</p>
|
||||
</IonText>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
{talks.map((talk, talkIndex) => {
|
||||
return talkIndex > 0 && <TalkCard key={talkIndex} talk={talk} pageRef={pageRef} />;
|
||||
})}
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
</IonGrid>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab1;
|
23
03_source/mobile/src/pages/DemoClubHouse/AppPages/Tab2.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import './Tab2.css';
|
||||
|
||||
const Tab2 = () => {
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>TO DO :)</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">TO DO :)</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab2;
|
23
03_source/mobile/src/pages/DemoClubHouse/AppPages/Tab3.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
|
||||
import './Tab3.css';
|
||||
|
||||
const Tab3 = () => {
|
||||
return (
|
||||
<IonPage>
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>TO DO :)</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
<IonContent fullscreen>
|
||||
<IonHeader collapse="condense">
|
||||
<IonToolbar>
|
||||
<IonTitle size="large">TO DO :)</IonTitle>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tab3;
|
100
03_source/mobile/src/pages/DemoClubHouse/components/TalkCard.jsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import { IonCardSubtitle, IonIcon, IonModal, IonNote, IonRow, useIonModal } from "@ionic/react";
|
||||
import { bulb, micOutline, personOutline } from "ionicons/icons";
|
||||
import { useStoreState } from "pullstate";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { CategoryStore } from '../store';
|
||||
import { getPeople } from "../store/PeopleStore";
|
||||
import { getCategory } from '../store/Selectors';
|
||||
|
||||
import styles from "./TalkCard.module.css";
|
||||
import { TalkModal } from "./TalkModal";
|
||||
|
||||
export const TalkCard = ({ upcoming = false, talk, pageRef }) => {
|
||||
|
||||
const talkCategory = useStoreState(CategoryStore, getCategory(talk.category_id));
|
||||
const [ speakers, setSpeakers ] = useState([]);
|
||||
const [ showModal, setShowModal ] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setSpeakers(getPeople(talk.speakers));
|
||||
}, [ talk ]);
|
||||
|
||||
// const [ present, dismiss ] = useIonModal(TalkModal, {
|
||||
|
||||
// dismiss: () => dismiss(),
|
||||
// talk,
|
||||
// speakers,
|
||||
// category: talkCategory
|
||||
// });
|
||||
|
||||
// const handleShowTalk = () => {
|
||||
|
||||
// console.log("in here");
|
||||
|
||||
// present({
|
||||
|
||||
// // presentingElement: pageRef.current
|
||||
// });
|
||||
// }
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={ `${ styles.talkCard } ${ upcoming && styles.upcomingCard }` } onClick={ () => setShowModal(true) }>
|
||||
<div className={ styles.cardTitle }>
|
||||
<IonIcon color={ upcoming ? "primary" : "white" } icon={ bulb } />
|
||||
<IonCardSubtitle color={ upcoming ? "light" : "primary" }>{ talkCategory.name } talks</IonCardSubtitle>
|
||||
</div>
|
||||
|
||||
<div className={ styles.talkTitle }>
|
||||
<h3>{ talk.title }</h3>
|
||||
</div>
|
||||
|
||||
{ !upcoming &&
|
||||
|
||||
<IonRow className={ styles.talkSpeakers }>
|
||||
{ speakers.map((speaker, index) => {
|
||||
|
||||
return (
|
||||
|
||||
<div key={ `speaker_${ index }` } className={ styles.talkSpeaker }>
|
||||
<img src={ speaker.image } alt="avatar" />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</IonRow>
|
||||
}
|
||||
|
||||
{ upcoming &&
|
||||
<div className={ styles.talkDate }>
|
||||
<IonNote color="secondary">{ talk.time }</IonNote>
|
||||
<div className={ styles.detailCount }>
|
||||
<IonIcon icon={ micOutline } color="light " />
|
||||
<span>{ talk.speakers } Speakers</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
{ !upcoming &&
|
||||
|
||||
<div className={ styles.talkDetails }>
|
||||
<div className={ styles.detailCount }>
|
||||
<IonIcon icon={ micOutline } color="primary" />
|
||||
<span>{ talk.speakers } Speakers</span>
|
||||
</div>
|
||||
|
||||
<div className={ styles.detailCount }>
|
||||
<IonIcon icon={ personOutline } color="primary" />
|
||||
<span>{ talk.audience } Audience</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<IonModal isOpen={ showModal } onDidDismiss={ () => setShowModal(false) } presentingElement={ pageRef.current }>
|
||||
<TalkModal dismiss={ () => setShowModal(false) } speakers={ speakers } talk={ talk } category={ talkCategory } />
|
||||
</IonModal>
|
||||
</>
|
||||
);
|
||||
}
|
@@ -0,0 +1,105 @@
|
||||
.talkCard {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.1);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.talkCard:not(:first-child) {
|
||||
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.upcomingCard {
|
||||
|
||||
background-color: var(--ion-color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cardTitle ion-icon {
|
||||
|
||||
border-radius: 500px;
|
||||
padding: 0.2rem;
|
||||
margin-right: 0.75rem;
|
||||
background-color: var(--ion-color-primary);
|
||||
margin-top: -0.2rem;
|
||||
}
|
||||
|
||||
.upcomingCard .cardTitle ion-icon {
|
||||
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.talkTitle h3 {
|
||||
|
||||
font-size: 1.3rem !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.talkDate {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.talkSpeakers {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.talkSpeaker {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
border-radius: 12px;
|
||||
margin-right: 0.2rem;
|
||||
background-color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
.talkSpeaker img {
|
||||
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.talkDetails {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.detailCount {
|
||||
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.detailCount ion-icon {
|
||||
|
||||
font-size: 1.2rem;
|
||||
margin-right: 0.3rem;
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
import { IonButton, IonButtons, IonCardSubtitle, IonCol, IonContent, IonGrid, IonHeader, IonIcon, IonPage, IonRow, IonTitle, IonToolbar } from "@ionic/react";
|
||||
import { bulb, exitOutline, micOutline, personOutline } from "ionicons/icons";
|
||||
import { useStoreState } from "pullstate";
|
||||
import { PeopleStore } from "../store";
|
||||
import { getAllPeople } from "../store/Selectors";
|
||||
|
||||
import styles from "./TalkModal.module.css";
|
||||
|
||||
export const TalkModal = ({ dismiss, talk, category, speakers }) => {
|
||||
|
||||
const people = useStoreState(PeopleStore, getAllPeople);
|
||||
|
||||
return (
|
||||
|
||||
<IonPage className="talk-modal">
|
||||
<IonHeader>
|
||||
<IonToolbar>
|
||||
<IonTitle>Talk Room</IonTitle>
|
||||
|
||||
<IonButtons slot="end">
|
||||
<IonButton color="primary" onClick={ dismiss }>
|
||||
<IonIcon icon={ exitOutline } />
|
||||
{/* Leave Room */}
|
||||
</IonButton>
|
||||
</IonButtons>
|
||||
</IonToolbar>
|
||||
</IonHeader>
|
||||
|
||||
<IonContent className={ styles.modal }>
|
||||
<IonGrid className="ion-padding-start ion-padding-end ion-margin-start ion-margin-end">
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<div className={ styles.cardTitle }>
|
||||
<IonIcon color="white" icon={ bulb } />
|
||||
<IonCardSubtitle color="primary">{ category.name } talks</IonCardSubtitle>
|
||||
</div>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow className={ styles.talkTitle }>
|
||||
<IonCol size="12">
|
||||
<h1>{ talk.title }</h1>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<div className={ styles.detailCount }>
|
||||
<IonIcon icon={ micOutline } color="primary" />
|
||||
<span>{ talk.speakers } Speakers</span>
|
||||
</div>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow className={ styles.talkSpeakers }>
|
||||
{ speakers.map((speaker, index) => {
|
||||
|
||||
return (
|
||||
|
||||
<IonCol className={ styles.speakerContainer }>
|
||||
<div key={ `speaker_${ index }` } className={ `${ styles.talkSpeaker } ${ index === 0 && styles.activeSpeaker }` }>
|
||||
<img src={ speaker.image } alt="avatar" />
|
||||
</div>
|
||||
<p>{ speaker.name.split(" ")[0] }</p>
|
||||
</IonCol>
|
||||
);
|
||||
})}
|
||||
</IonRow>
|
||||
|
||||
<IonRow>
|
||||
<IonCol size="12">
|
||||
<div className={ styles.detailCount }>
|
||||
<IonIcon icon={ personOutline } color="primary" />
|
||||
<span>{ talk.audience } Audience</span>
|
||||
</div>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
|
||||
<IonRow className={ styles.talkSpeakers }>
|
||||
{ [ ...Array(talk.audience)].map((audience, index) => {
|
||||
|
||||
return (
|
||||
|
||||
<IonCol size="3" className={ `${ styles.speakerContainer } ${ styles.audienceContainer }` }>
|
||||
<div key={ `speaker_${ index }` } className={ styles.talkSpeaker }>
|
||||
<img src={ people[Math.floor(Math.random() * 30)].image } alt="avatar" />
|
||||
</div>
|
||||
<p>{ people[Math.floor(Math.random() * 30)].name.split(" ")[0] }</p>
|
||||
</IonCol>
|
||||
);
|
||||
})}
|
||||
</IonRow>
|
||||
</IonGrid>
|
||||
</IonContent>
|
||||
</IonPage>
|
||||
);
|
||||
}
|
@@ -0,0 +1,150 @@
|
||||
.talkCard {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
padding: 2rem;
|
||||
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.1);
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.talkCard:not(:first-child) {
|
||||
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.upcomingCard {
|
||||
|
||||
background-color: var(--ion-color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cardTitle {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cardTitle ion-icon {
|
||||
|
||||
border-radius: 500px;
|
||||
padding: 0.2rem;
|
||||
margin-right: 0.75rem;
|
||||
background-color: var(--ion-color-primary);
|
||||
margin-top: -0.2rem;
|
||||
}
|
||||
|
||||
.upcomingCard .cardTitle ion-icon {
|
||||
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.talkTitle {
|
||||
|
||||
margin-top: -1rem;
|
||||
}
|
||||
|
||||
.talkTitle h3 {
|
||||
|
||||
font-size: 1.3rem !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.talkDate {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.talkSpeakers {
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.speakerContainer {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.audienceContainer {
|
||||
|
||||
margin-bottom: 1rem;
|
||||
/* margin: 0.5rem; */
|
||||
}
|
||||
|
||||
.talkSpeaker {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
border-radius: 12px;
|
||||
margin-right: 0.2rem;
|
||||
background-color: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
.audienceContainer .talkSpeaker {
|
||||
|
||||
background-color: #f2efe5;
|
||||
border: 2px solid #dfd9c7;
|
||||
}
|
||||
|
||||
.talkSpeaker img {
|
||||
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.speakerContainer p {
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-top: 0.2rem;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.talkDetails {
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.detailCount {
|
||||
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.detailCount ion-icon {
|
||||
|
||||
font-size: 1.2rem;
|
||||
margin-right: 0.3rem;
|
||||
margin-left: -0.4rem;
|
||||
}
|
||||
|
||||
.activeSpeaker {
|
||||
|
||||
border: 3px solid rgb(255, 187, 0);
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
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 (
|
||||
<IonCol size="6">
|
||||
<IonRow className="ion-justify-content-center ion-align-items-center">
|
||||
<IonCol size="3">
|
||||
{!property.isIcon && (
|
||||
<img alt={property.alt} src={property.icon} height="32" width="32" />
|
||||
)}
|
||||
{property.isIcon && (
|
||||
<IonIcon icon={property.icon} color="medium" style={{ fontSize: '2rem' }} />
|
||||
)}
|
||||
</IonCol>
|
||||
|
||||
<IonCol size="9">
|
||||
<IonCardSubtitle>{property.label}</IonCardSubtitle>
|
||||
<IonNote>{property.value}</IonNote>
|
||||
</IonCol>
|
||||
</IonRow>
|
||||
</IonCol>
|
||||
);
|
||||
};
|