Kaynağa Gözat

WeatherIcon. Small changes to theme state

unknown 4 yıl önce
ebeveyn
işleme
e293325da7

+ 5 - 0
client/package-lock.json

@@ -13766,6 +13766,11 @@
       "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
       "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
     },
+    "skycons-ts": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/skycons-ts/-/skycons-ts-0.2.0.tgz",
+      "integrity": "sha512-GBn7Ox0dvZa9cin4NZIuBC4isdNYubSfJ+Rv0m5vkOQ8eBHPFApV98mbaAOseoKEBBjqsR1xDsY55rJ0HfwB6w=="
+    },
     "slash": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",

+ 1 - 0
client/package.json

@@ -23,6 +23,7 @@
     "redux": "^4.1.0",
     "redux-devtools-extension": "^2.13.9",
     "redux-thunk": "^2.3.0",
+    "skycons-ts": "^0.2.0",
     "typescript": "^4.2.4",
     "web-vitals": "^1.1.2"
   },

+ 1 - 1
client/src/components/Apps/AppCard/AppCard.tsx

@@ -1,7 +1,7 @@
 import { Link } from 'react-router-dom';
 
 import classes from './AppCard.module.css';
-import Icon from '../../UI/Icon/Icon';
+import Icon from '../../UI/Icons/Icon/Icon';
 
 import { App } from '../../../interfaces';
 

+ 1 - 1
client/src/components/Apps/AppForm/AppForm.tsx

@@ -4,7 +4,7 @@ import { addApp } from '../../../store/actions';
 import { NewApp } from '../../../interfaces/App';
 
 import classes from './AppForm.module.css';
-import Icon from '../../UI/Icon/Icon';
+import Icon from '../../UI/Icons/Icon/Icon';
 
 interface ComponentProps {
   modalHandler: Function;

+ 1 - 1
client/src/components/Apps/AppTable/AppTable.tsx

@@ -3,7 +3,7 @@ import { App, GlobalState } from '../../../interfaces';
 import { pinApp, deleteApp } from '../../../store/actions';
 
 import classes from './AppTable.module.css';
-import Icon from '../../UI/Icon/Icon';
+import Icon from '../../UI/Icons/Icon/Icon';
 
 interface ComponentProps {
   apps: App[];

+ 31 - 1
client/src/components/Home/Home.module.css

@@ -2,7 +2,7 @@
   color: var(--color-primary);
   font-weight: 700;
   font-size: 4em;
-  margin-bottom: 0.5em;
+  display: inline-block;
 }
 
 .Header p {
@@ -12,6 +12,36 @@
   height: 30px;
 }
 
+.HeaderMain {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 2.5rem;
+}
+
+.WeatherWidget {
+  display: flex;
+}
+
+.WeatherDetails {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  font-size: 16px;
+  color: var(--color-primary);
+  margin-left: 10px;
+  font-weight: 500;
+}
+
+.WeatherDetails span:first-child {
+  border-bottom: 1px solid var(--color-primary);
+  padding-bottom: 5px;
+}
+
+.WeatherDetails span:last-child {
+  padding-top: 5px;
+}
+
 .SettingsButton {
   width: 35px;
   height: 35px;

+ 14 - 5
client/src/components/Home/Home.tsx

@@ -4,14 +4,12 @@ import { connect } from 'react-redux';
 import { GlobalState } from '../../interfaces/GlobalState';
 import { getApps } from '../../store/actions';
 
-import Icon from '../UI/Icon/Icon';
-import Modal from '../UI/Modal/Modal';
+import Icon from '../UI/Icons/Icon/Icon';
+import WeatherIcon from '../UI/Icons/WeatherIcon/WeatherIcon';
 
 import classes from './Home.module.css';
 import { Container } from '../UI/Layout/Layout';
-import Headline from '../UI/Headlines/Headline/Headline';
 import SectionHeadline from '../UI/Headlines/SectionHeadline/SectionHeadline';
-import Apps from '../Apps/Apps';
 import AppGrid from '../Apps/AppGrid/AppGrid';
 import { App } from '../../interfaces';
 import Spinner from '../UI/Spinner/Spinner';
@@ -63,7 +61,18 @@ const Home = (props: ComponentProps): JSX.Element => {
     <Container>
       <header className={classes.Header}>
         <p>{dateAndTime()}</p>
-        <h1>{greeter()}</h1>
+        <span className={classes.HeaderMain}>
+          <h1>{greeter()}</h1>
+          <div className={classes.WeatherWidget}>
+            <div className={classes.WeatherIcon}>
+              <WeatherIcon icon='clear-day' />
+            </div>
+            <div className={classes.WeatherDetails}>
+              <span>30°C</span>
+              <span>15°C</span>
+            </div>
+          </div>
+        </span>
       </header>
 
       <SectionHeadline title='Apps' link='/apps' />

+ 25 - 4
client/src/components/UI/Buttons/ActionButton/ActionButton.tsx

@@ -2,7 +2,7 @@ import { Fragment } from 'react';
 import { Link } from 'react-router-dom';
 
 import classes from './ActionButton.module.css';
-import Icon from '../../Icon/Icon';
+import Icon from '../../Icons/Icon/Icon';
 
 interface ComponentProps {
   name: string;
@@ -24,11 +24,32 @@ const ActionButton = (props: ComponentProps): JSX.Element => {
   );
 
   if (props.link) {
-    return (<Link to={props.link}>{body}</Link>)
+    return (
+      <Link
+        to={props.link}
+        tabIndex={0}>
+        {body}
+      </Link>
+    )
   } else if (props.handler) {
-    return (<div className={classes.ActionButton} onClick={props.handler}>{body}</div>)
+    return (
+      <div
+        className={classes.ActionButton}
+        onClick={props.handler}
+        onKeyPress={(e) => {
+          if (e.key === 'Enter' && props.handler) props.handler()
+        }}
+        tabIndex={0}
+        >{body}
+      </div>
+    )
   } else {
-    return (<div className={classes.ActionButton}>{body}</div>)
+    return (
+      <div
+        className={classes.ActionButton}>
+        {body}
+      </div>
+    )
   }
 }
 

+ 0 - 4
client/src/components/UI/Icon/Icon.module.css

@@ -1,4 +0,0 @@
-.Icon {
-  color: var(--color-primary);
-  width: 90%;
-}

+ 6 - 0
client/src/components/UI/Icons/Icon/Icon.module.css

@@ -0,0 +1,6 @@
+.Icon {
+  color: var(--color-primary);
+  /* for settings */
+  /* color: var(--color-background); */
+  width: 90%;
+}

+ 0 - 0
client/src/components/UI/Icon/Icon.tsx → client/src/components/UI/Icons/Icon/Icon.tsx


+ 34 - 0
client/src/components/UI/Icons/WeatherIcon/WeatherIcon.tsx

@@ -0,0 +1,34 @@
+import { useEffect } from 'react';
+import { connect } from 'react-redux';
+import { IconKey, Skycons } from 'skycons-ts';
+import { GlobalState, Theme } from '../../../../interfaces';
+
+interface ComponentProps {
+  theme: Theme;
+  icon: IconKey
+}
+
+const WeatherIcon = (props: ComponentProps): JSX.Element => {
+  const randomId = `icon-${Math.floor(Math.random() * 1000)}`;
+  useEffect(() => {
+    const delay = setTimeout(() => {
+      const skycons = new Skycons({'color': props.theme.colors.accent});
+      skycons.add(`weather-icon-${randomId}`, props.icon);
+      skycons.play();
+    }, 1);
+
+    return () => {
+      clearTimeout(delay);
+    }
+  }, []);
+
+  return <canvas id={`weather-icon-${randomId}`} width='50' height='50'></canvas>
+}
+
+const mapStateToProps = (state: GlobalState) => {
+  return {
+    theme: state.theme.theme
+  }
+}
+
+export default connect(mapStateToProps)(WeatherIcon);

+ 0 - 1
client/src/components/UI/Modal/Modal.tsx

@@ -1,5 +1,4 @@
 import classes from './Modal.module.css';
-import Icon from '../Icon/Icon';
 
 interface ComponentProps {
   isOpen: boolean;

+ 2 - 2
client/src/store/actions/actionTypes.ts

@@ -1,6 +1,6 @@
 import {
   GetAppsAction,
-  SetTheme,
+  SetThemeAction,
   PinAppAction,
   AddAppAction,
   DeleteAppAction
@@ -17,4 +17,4 @@ export enum ActionTypes {
   deleteApp = 'DELETE_APP'
 }
 
-export type Action = GetAppsAction<any> | SetTheme | PinAppAction | AddAppAction | DeleteAppAction;
+export type Action = GetAppsAction<any> | SetThemeAction | PinAppAction | AddAppAction | DeleteAppAction;

+ 5 - 5
client/src/store/actions/theme.ts

@@ -3,9 +3,9 @@ import { themes } from '../../components/Themer/themes.json';
 import { Theme } from '../../interfaces/Theme';
 import { ActionTypes } from './actionTypes';
 
-export interface SetTheme {
+export interface SetThemeAction {
   type: ActionTypes.setTheme,
-  payload: string
+  payload: Theme
 }
 
 export const setTheme = (themeName: string) => (dispatch: Dispatch) => {
@@ -15,14 +15,14 @@ export const setTheme = (themeName: string) => (dispatch: Dispatch) => {
     localStorage.setItem('theme', themeName);
     loadTheme(theme);
 
-    dispatch<SetTheme>({
+    dispatch<SetThemeAction>({
       type: ActionTypes.setTheme,
-      payload: themeName
+      payload: theme
     })
   }
 }
 
-export const loadTheme = (theme: Theme) => {
+export const loadTheme = (theme: Theme): void => {
   for (const [key, value] of Object.entries(theme.colors)) {
     document.body.style.setProperty(`--color-${key}`, value);
   }

+ 11 - 7
client/src/store/reducers/theme.ts

@@ -1,20 +1,24 @@
 import { ActionTypes, Action } from '../actions';
+import { Theme } from '../../interfaces/Theme';
 
 export interface State {
-  theme: string;
+  theme: Theme;
 }
 
 const initialState: State = {
-  theme: 'blues'
-}
-
-const setTheme = (state: State, action: Action): State => {
-  return { theme: action.payload };
+  theme: {
+    name: 'blues',
+    colors: {
+      background: '#2B2C56',
+      primary: '#EFF1FC',
+      accent: '#6677EB'
+    }
+  }
 }
 
 const themeReducer = (state = initialState, action: Action) => {
   switch (action.type) {
-    case ActionTypes.setTheme: return setTheme(state, action);
+    case ActionTypes.setTheme: return { theme: action.payload };
     default: return state;
   }
 }