Added option to set custom greetings. Moved HomeHeader to separate file. Cleaned up README file
This commit is contained in:
parent
4e20527834
commit
aca8b0261e
17 changed files with 149 additions and 124 deletions
|
@ -1,5 +1,7 @@
|
|||
### v1.7.4 (TBA)
|
||||
- [WIP] Added option to set custom greetings and date ([#103](https://github.com/pawelmalak/flame/issues/103))
|
||||
- Added iOS "Add to homescreen" icon ([#131](https://github.com/pawelmalak/flame/issues/131))
|
||||
- Added 3 new themes
|
||||
|
||||
### v1.7.3 (2021-10-28)
|
||||
- Fixed bug with custom CSS not updating
|
||||
|
|
57
README.md
57
README.md
|
@ -1,15 +1,10 @@
|
|||
# Flame
|
||||
|
||||
[![JS Badge](https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black)](https://shields.io/)
|
||||
[![TS Badge](https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white)](https://shields.io/)
|
||||
[![Node Badge](https://img.shields.io/badge/Node.js-43853D?style=for-the-badge&logo=node.js&logoColor=white)](https://shields.io/)
|
||||
[![React Badge](https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB)](https://shields.io/)
|
||||
|
||||
![Homescreen screenshot](./.github/_home.png)
|
||||
|
||||
## Description
|
||||
|
||||
Flame is self-hosted startpage for your server. Its design is inspired (heavily) by [SUI](https://github.com/jeroenpardon/sui). Flame is very easy to setup and use. With built-in editors it allows you to setup your very own appliaction hub in no time - no file editing necessary.
|
||||
Flame is self-hosted startpage for your server. Its design is inspired (heavily) by [SUI](https://github.com/jeroenpardon/sui). Flame is very easy to setup and use. With built-in editors it allows you to setup your very own application hub in no time - no file editing necessary.
|
||||
|
||||
## Technology
|
||||
|
||||
|
@ -42,7 +37,15 @@ npm run dev
|
|||
|
||||
### With Docker (recommended)
|
||||
|
||||
[Docker Hub](https://hub.docker.com/r/pawelmalak/flame)
|
||||
[Docker Hub link](https://hub.docker.com/r/pawelmalak/flame)
|
||||
|
||||
```sh
|
||||
docker pull pawelmalak/flame:latest
|
||||
|
||||
# for ARM architecture (e.g. RaspberryPi)
|
||||
docker pull pawelmalak/flame:multiarch
|
||||
```
|
||||
|
||||
|
||||
#### Building images
|
||||
|
||||
|
@ -96,13 +99,13 @@ Follow instructions from wiki: [Installation without Docker](https://github.com/
|
|||
|
||||
- Applications
|
||||
- Create, update, delete and organize applications using GUI
|
||||
- Pin your favourite apps to homescreen
|
||||
- Pin your favourite apps to the homescreen
|
||||
|
||||
![Homescreen screenshot](./.github/_apps.png)
|
||||
|
||||
- Bookmarks
|
||||
- Create, update, delete and organize bookmarks and categories using GUI
|
||||
- Pin your favourite categories to homescreen
|
||||
- Pin your favourite categories to the homescreen
|
||||
|
||||
![Homescreen screenshot](./.github/_bookmarks.png)
|
||||
|
||||
|
@ -111,7 +114,7 @@ Follow instructions from wiki: [Installation without Docker](https://github.com/
|
|||
- Get current temperature, cloud coverage and weather status with animated icons
|
||||
|
||||
- Themes
|
||||
- Customize your page by choosing from 12 color themes
|
||||
- Customize your page by choosing from 15 color themes
|
||||
|
||||
![Homescreen screenshot](./.github/_themes.png)
|
||||
|
||||
|
@ -125,23 +128,7 @@ To use search bar you need to type your search query with selected prefix. For e
|
|||
|
||||
> You can change where to open search results (same/new tab) in the settings
|
||||
|
||||
#### Supported search engines
|
||||
|
||||
| Name | Prefix | Search URL |
|
||||
| ---------- | ------ | ----------------------------------- |
|
||||
| Disroot | /ds | http://search.disroot.org/search?q= |
|
||||
| DuckDuckGo | /d | https://duckduckgo.com/?q= |
|
||||
| Google | /g | https://www.google.com/search?q= |
|
||||
|
||||
#### Supported services
|
||||
|
||||
| Name | Prefix | Search URL |
|
||||
| ------------------ | ------ | --------------------------------------------- |
|
||||
| IMDb | /im | https://www.imdb.com/find?q= |
|
||||
| Reddit | /r | https://www.reddit.com/search?q= |
|
||||
| Spotify | /sp | https://open.spotify.com/search/ |
|
||||
| The Movie Database | /mv | https://www.themoviedb.org/search?query= |
|
||||
| Youtube | /yt | https://www.youtube.com/results?search_query= |
|
||||
For list of supported search engines, shortcuts and more about searching functionality visit [project wiki](https://github.com/pawelmalak/flame/wiki/Search-bar).
|
||||
|
||||
### Setting up weather module
|
||||
|
||||
|
@ -159,13 +146,13 @@ labels:
|
|||
- flame.type=application # "app" works too
|
||||
- flame.name=My container
|
||||
- flame.url=https://example.com
|
||||
- flame.icon=icon-name # Optional, default is "docker"
|
||||
- flame.icon=icon-name # optional, default is "docker"
|
||||
# - flame.icon=custom to make changes in app. ie: custom icon upload
|
||||
```
|
||||
|
||||
And you must have activated the Docker sync option in the settings panel.
|
||||
> "Use Docker API" option must be enabled for this to work. You can find it in Settings > Other > Docker section
|
||||
|
||||
You can set up different apps in the same label adding `;` between each one.
|
||||
You can also set up different apps in the same label adding `;` between each one.
|
||||
|
||||
```yml
|
||||
labels:
|
||||
|
@ -208,13 +195,11 @@ metadata:
|
|||
- flame.pawelmalak/type=application # "app" works too
|
||||
- flame.pawelmalak/name=My container
|
||||
- flame.pawelmalak/url=https://example.com
|
||||
- flame.pawelmalak/icon=icon-name # Optional, default is "kubernetes"
|
||||
- flame.pawelmalak/icon=icon-name # optional, default is "kubernetes"
|
||||
```
|
||||
|
||||
And you must have activated the Kubernetes sync option in the settings panel.
|
||||
> "Use Kubernetes Ingress API" option must be enabled for this to work. You can find it in Settings > Other > Kubernetes section
|
||||
|
||||
### Custom CSS
|
||||
### Custom CSS and themes
|
||||
|
||||
> This is an experimental feature. Its behaviour might change in the future.
|
||||
>
|
||||
> Follow instructions from wiki: [Custom CSS](https://github.com/pawelmalak/flame/wiki/Custom-CSS)
|
||||
See project wiki for [Custom CSS](https://github.com/pawelmalak/flame/wiki/Custom-CSS) and [Custom theme with CSS](https://github.com/pawelmalak/flame/wiki/Custom-theme-with-CSS).
|
31
client/src/components/Home/Header/Header.module.css
Normal file
31
client/src/components/Home/Header/Header.module.css
Normal file
|
@ -0,0 +1,31 @@
|
|||
.Header h1 {
|
||||
color: var(--color-primary);
|
||||
font-weight: 700;
|
||||
font-size: 4em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Header p {
|
||||
color: var(--color-primary);
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.HeaderMain {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.SettingsLink {
|
||||
visibility: visible;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.SettingsLink {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
49
client/src/components/Home/Header/Header.tsx
Normal file
49
client/src/components/Home/Header/Header.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Config, GlobalState } from '../../../interfaces';
|
||||
import WeatherWidget from '../../Widgets/WeatherWidget/WeatherWidget';
|
||||
import { getDateTime } from './functions/getDateTime';
|
||||
import { greeter } from './functions/greeter';
|
||||
import classes from './Header.module.css';
|
||||
|
||||
interface Props {
|
||||
config: Config;
|
||||
}
|
||||
|
||||
const Header = (props: Props): JSX.Element => {
|
||||
const [dateTime, setDateTime] = useState<string>(getDateTime());
|
||||
const [greeting, setGreeting] = useState<string>(greeter());
|
||||
|
||||
useEffect(() => {
|
||||
let dateTimeInterval: NodeJS.Timeout;
|
||||
|
||||
dateTimeInterval = setInterval(() => {
|
||||
setDateTime(getDateTime());
|
||||
setGreeting(greeter());
|
||||
}, 1000);
|
||||
|
||||
return () => window.clearInterval(dateTimeInterval);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header className={classes.Header}>
|
||||
<p>{dateTime}</p>
|
||||
<Link to="/settings" className={classes.SettingsLink}>
|
||||
Go to Settings
|
||||
</Link>
|
||||
<span className={classes.HeaderMain}>
|
||||
<h1>{greeting}</h1>
|
||||
<WeatherWidget />
|
||||
</span>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state: GlobalState) => {
|
||||
return {
|
||||
config: state.config.config,
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(Header);
|
|
@ -1,4 +1,4 @@
|
|||
export const dateTime = (): string => {
|
||||
export const getDateTime = (): string => {
|
||||
const days = [
|
||||
'Sunday',
|
||||
'Monday',
|
17
client/src/components/Home/Header/functions/greeter.ts
Normal file
17
client/src/components/Home/Header/functions/greeter.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
export const greeter = (): string => {
|
||||
const now = new Date().getHours();
|
||||
let msg: string;
|
||||
|
||||
const greetingsSchemaRaw =
|
||||
localStorage.getItem('greetingsSchema') ||
|
||||
'Good evening!;Good afternoon!;Good morning!;Good night!';
|
||||
const greetingsSchema = greetingsSchemaRaw.split(';');
|
||||
|
||||
if (now >= 18) msg = greetingsSchema[0];
|
||||
else if (now >= 12) msg = greetingsSchema[1];
|
||||
else if (now >= 6) msg = greetingsSchema[2];
|
||||
else if (now >= 0) msg = greetingsSchema[3];
|
||||
else msg = 'Hello!';
|
||||
|
||||
return msg;
|
||||
};
|
|
@ -1,24 +1,3 @@
|
|||
.Header h1 {
|
||||
color: var(--color-primary);
|
||||
font-weight: 700;
|
||||
font-size: 4em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.Header p {
|
||||
color: var(--color-primary);
|
||||
font-weight: 300;
|
||||
text-transform: uppercase;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.HeaderMain {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.SettingsButton {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
|
@ -40,21 +19,12 @@
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
.SettingsLink {
|
||||
visibility: visible;
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
@media (min-width: 769px) {
|
||||
.SettingsButton {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.SettingsLink {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.HomeSpace {
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,8 @@ import classes from './Home.module.css';
|
|||
// Components
|
||||
import AppGrid from '../Apps/AppGrid/AppGrid';
|
||||
import BookmarkGrid from '../Bookmarks/BookmarkGrid/BookmarkGrid';
|
||||
import WeatherWidget from '../Widgets/WeatherWidget/WeatherWidget';
|
||||
import SearchBar from '../SearchBar/SearchBar';
|
||||
|
||||
// Functions
|
||||
import { greeter } from './functions/greeter';
|
||||
import { dateTime } from './functions/dateTime';
|
||||
import Header from './Header/Header';
|
||||
|
||||
interface ComponentProps {
|
||||
getApps: Function;
|
||||
|
@ -48,11 +44,6 @@ const Home = (props: ComponentProps): JSX.Element => {
|
|||
categoriesLoading,
|
||||
} = props;
|
||||
|
||||
const [header, setHeader] = useState({
|
||||
dateTime: dateTime(),
|
||||
greeting: greeter(),
|
||||
});
|
||||
|
||||
// Local search query
|
||||
const [localSearch, setLocalSearch] = useState<null | string>(null);
|
||||
const [appSearchResult, setAppSearchResult] = useState<null | App[]>(null);
|
||||
|
@ -74,23 +65,6 @@ const Home = (props: ComponentProps): JSX.Element => {
|
|||
}
|
||||
}, [getCategories]);
|
||||
|
||||
// Refresh greeter and time
|
||||
useEffect(() => {
|
||||
let interval: any;
|
||||
|
||||
// Start interval only when hideHeader is false
|
||||
if (!props.config.hideHeader) {
|
||||
interval = setInterval(() => {
|
||||
setHeader({
|
||||
dateTime: dateTime(),
|
||||
greeting: greeter(),
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (localSearch) {
|
||||
// Search through apps
|
||||
|
@ -126,20 +100,7 @@ const Home = (props: ComponentProps): JSX.Element => {
|
|||
<div></div>
|
||||
)}
|
||||
|
||||
{!props.config.hideHeader ? (
|
||||
<header className={classes.Header}>
|
||||
<p>{header.dateTime}</p>
|
||||
<Link to="/settings" className={classes.SettingsLink}>
|
||||
Go to Settings
|
||||
</Link>
|
||||
<span className={classes.HeaderMain}>
|
||||
<h1>{header.greeting}</h1>
|
||||
<WeatherWidget />
|
||||
</span>
|
||||
</header>
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
{!props.config.hideHeader ? <Header /> : <div></div>}
|
||||
|
||||
{!props.config.hideApps ? (
|
||||
<Fragment>
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
export const greeter = (): string => {
|
||||
const now = new Date().getHours();
|
||||
let msg: string;
|
||||
|
||||
if (now >= 18) msg = 'Good evening!';
|
||||
else if (now >= 12) msg = 'Good afternoon!';
|
||||
else if (now >= 6) msg = 'Good morning!';
|
||||
else if (now >= 0) msg = 'Good night!';
|
||||
else msg = 'Hello!';
|
||||
|
||||
return msg;
|
||||
}
|
|
@ -187,6 +187,21 @@ const OtherSettings = (props: ComponentProps): JSX.Element => {
|
|||
<option value={0}>False</option>
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="greetingsSchema">Custom greetings</label>
|
||||
<input
|
||||
type="text"
|
||||
id="greetingsSchema"
|
||||
name="greetingsSchema"
|
||||
placeholder="Good day;Hi;Bye!"
|
||||
value={formData.greetingsSchema}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
<span>
|
||||
Greetings must be separated with semicolon. Only 4 messages can be
|
||||
used
|
||||
</span>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor="hideApps">Hide applications</label>
|
||||
<select
|
||||
|
|
|
@ -21,4 +21,5 @@ export interface Config {
|
|||
unpinStoppedApps: boolean;
|
||||
useAmericanDate: boolean;
|
||||
disableAutofocus: boolean;
|
||||
greetingsSchema: string;
|
||||
}
|
||||
|
|
|
@ -27,4 +27,5 @@ export interface OtherSettingsForm {
|
|||
kubernetesApps: boolean;
|
||||
unpinStoppedApps: boolean;
|
||||
useAmericanDate: boolean;
|
||||
greetingsSchema: string;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ export const getConfig = () => async (dispatch: Dispatch) => {
|
|||
|
||||
// Store settings for priority UI elements
|
||||
localStorage.setItem('useAmericanDate', `${res.data.data.useAmericanDate}`);
|
||||
localStorage.setItem('greetingsSchema', `${res.data.data.greetingsSchema}`);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
@ -52,6 +53,7 @@ export const updateConfig = (formData: any) => async (dispatch: Dispatch) => {
|
|||
|
||||
// Store settings for priority UI elements
|
||||
localStorage.setItem('useAmericanDate', `${res.data.data.useAmericanDate}`);
|
||||
localStorage.setItem('greetingsSchema', `${res.data.data.greetingsSchema}`);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
|
|
@ -23,4 +23,5 @@ export const configTemplate: Config = {
|
|||
unpinStoppedApps: false,
|
||||
useAmericanDate: false,
|
||||
disableAutofocus: false,
|
||||
greetingsSchema: 'Good evening!;Good afternoon!;Good morning!;Good night!',
|
||||
};
|
||||
|
|
|
@ -15,6 +15,7 @@ export const otherSettingsTemplate: OtherSettingsForm = {
|
|||
kubernetesApps: true,
|
||||
unpinStoppedApps: true,
|
||||
useAmericanDate: false,
|
||||
greetingsSchema: 'Good evening!;Good afternoon!;Good morning!;Good night!',
|
||||
};
|
||||
|
||||
export const weatherSettingsTemplate: WeatherForm = {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
class ErrorResponse extends Error {
|
||||
constructor(message, statusCode) {
|
||||
super(message);
|
||||
this.statusCode = statusCode
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ErrorResponse;
|
||||
module.exports = ErrorResponse;
|
||||
|
|
|
@ -20,5 +20,6 @@
|
|||
"kubernetesApps": false,
|
||||
"unpinStoppedApps": false,
|
||||
"useAmericanDate": false,
|
||||
"disableAutofocus": false
|
||||
"disableAutofocus": false,
|
||||
"greetingsSchema": "Good evening!;Good afternoon!;Good morning!;Good night!"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue