diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index b02b79780..8b973d92f 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,12 +1,13 @@ name: โœจ Feature Request description: Request a feature to help improve Homarr! title: '' +labels: ['โœจ Feature'] body: - type: textarea id: feature attributes: label: Description - description: Describe the feature you would like to see. Tell us how you imagine it and try to provide as much usefull information as possible. **PLEASE** use images or drawings or anything to image your thoughts. Also please do not say "Like X and Y do" as we sometimes don't know what X and Y are. + description: Describe the feature you would like to see. Tell us how you imagine it and try to provide as much useful information as possible. **PLEASE** use images/screenshots, include details about X & Y when requesting changes like X & Y service does, make your description atleast 300 characters. Having an unclear issue with too little detail will result in your issue being marked as invalid and closed. placeholder: An outline of the feature you would like to see implemented, include as much detail as possible! validations: required: true @@ -21,3 +22,13 @@ body: - High (App breaking feature) validations: required: true + - type: checkboxes + id: idiot-check + attributes: + label: Please tick the boxes + description: Before submitting, please ensure that + options: + - label: You've read the [docs](https://github.com/ajnart/homarr#readme) + required: true + - label: You've checked for [duplicate issues](https://github.com/ajnart/homarr/issues) + required: true diff --git a/.github/ISSUE_TEMPLATE/idea.yml b/.github/ISSUE_TEMPLATE/idea.yml new file mode 100644 index 000000000..594101d00 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/idea.yml @@ -0,0 +1,23 @@ +name: ๐Ÿค” Idea +description: Tell us your idea! We may implement it. +title: '<title>' +labels: ['๐Ÿค” Idea'] +body: + - type: textarea + id: feature + attributes: + label: Description + description: Tell us your idea! Please add as much details as possible. + placeholder: Maybe move ... to ...! Maybe add the version of Homarr somewhere...! Etc. + validations: + required: true + - type: checkboxes + id: idiot-check + attributes: + label: Please tick the boxes + description: Before submitting, please ensure that + options: + - label: You've read the [docs](https://github.com/ajnart/homarr#readme) + required: true + - label: You've checked for [duplicate issues](https://github.com/ajnart/homarr/issues) + required: true diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0270806fe..4bd399d2a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,18 +1,24 @@ -name: Build and publish Docker image +name: Master docker CI +# Workflow to build and publish docker image on: push: + branches: [master] tags: - v* workflow_dispatch: env: - IMAGE_NAME: homarr + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as <account>/<repo> + IMAGE_NAME: ${{ github.repository }} jobs: # Push image to GitHub Packages. # See also https://docs.docker.com/docker-hub/builds/ - build: + yarn_install_and_build: + # Will run yarn install && yarn build runs-on: ubuntu-latest steps: - name: Setup @@ -20,9 +26,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Get yarn cache directory path + # to help speed up build times id: yarn-cache-dir-path run: echo "::set-output name=dir::$(yarn cache dir)" - name: Yarn cache + # to help speed up build times uses: actions/cache@v3 id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) with: @@ -43,6 +51,7 @@ jobs: - run: yarn install --frozen-lockfile - run: yarn build - name: Cache build output + # to copy needed files to docker build job uses: actions/cache@v2 id: restore-build with: @@ -52,11 +61,11 @@ jobs: ./public/ ./.next/static/ ./.next/standalone/ - ./packages.jsan + ./packages.json key: ${{ github.sha }} - docker: - needs: [build] + docker_image_build_and_push: + needs: [yarn_install_and_build] runs-on: ubuntu-latest permissions: packages: write @@ -73,14 +82,14 @@ jobs: ./public/ ./.next/static/ ./.next/standalone/ - ./packages.jsan + ./packages.json key: ${{ github.sha }} - name: Docker meta id: meta uses: docker/metadata-action@v4 with: # list of Docker images to use as base name for tags - images: ghcr.io/${{ github.repository }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # generate Docker tags based on the following events/attributes tags: | type=raw,value=latest @@ -90,7 +99,6 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to GHCR - if: github.event_name != 'pull_request' uses: docker/login-action@v2 with: registry: ghcr.io diff --git a/.github/workflows/docker_dev.yml b/.github/workflows/docker_dev.yml new file mode 100644 index 000000000..cbf6b819f --- /dev/null +++ b/.github/workflows/docker_dev.yml @@ -0,0 +1,116 @@ +name: Development CI +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +on: + push: + branches: [dev] + pull_request: + workflow_dispatch: + inputs: + tags: + requierd: true + description: 'Tags to deploy to' + +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as <account>/<repo> + IMAGE_NAME: ${{ github.repository }} + +jobs: + # Push image to GitHub Packages. + # See also https://docs.docker.com/docker-hub/builds/ + yarn_install_and_build: + runs-on: ubuntu-latest + steps: + - name: Setup + uses: actions/setup-node@v3 + - name: Checkout + uses: actions/checkout@v3 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - name: Yarn cache + uses: actions/cache@v3 + id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: ${{ runner.os }}-yarn- + - name: Nextjs cache + uses: actions/cache@v2 + with: + # See here for caching with `yarn` https://github.com/actions/cache/blob/main/examples.md#node---yarn or you can leverage caching with actions/setup-node https://github.com/actions/setup-node + path: | + ~/.npm + ${{ github.workspace }}/.next/cache + # Generate a new cache whenever packages or source files change. + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} + # If source files changed but packages didn't, rebuild from a prior cache. + restore-keys: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- + - run: yarn install --frozen-lockfile + - run: yarn build + - name: Cache build output + uses: actions/cache@v2 + id: restore-build + with: + path: | + ./next.config.js + ./pages/ + ./public/ + ./.next/static/ + ./.next/standalone/ + ./packages.json + key: ${{ github.sha }} + + docker_image_build_and_push: + needs: [yarn_install_and_build] + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + steps: + - name: Checkout + uses: actions/checkout@v2 + - uses: actions/cache@v2 + id: restore-build + with: + path: | + ./next.config.js + ./pages/ + ./public/ + ./.next/static/ + ./.next/standalone/ + ./packages.json + key: ${{ github.sha }} + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + # list of Docker images to use as base name for tags + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + # generate Docker tags based on the following events/attributes + tags: | + type=ref,event=pr + tpye=raw,value=dev,priority=1 + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + - name: Login to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + platforms: linux/amd64,linux/arm64,linux/arm/v7 + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.storybook/main.js b/.storybook/main.js index d1506f5e8..6449361d8 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,5 +1,5 @@ module.exports = { - stories: ['../components/**/*.story.mdx', '../components/**/*.story.*'], + stories: ['../src/components/**/*.story.mdx', '../src/components/**/*.story.*'], addons: [ 'storybook-dark-mode', '@storybook/addon-links', diff --git a/Dockerfile b/Dockerfile index 5d13c04aa..95fbce619 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,11 +10,10 @@ COPY /package.json ./package.json # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --chown=nextjs:nodejs /.next/standalone ./ -COPY --chown=nextjs:nodejs /.next/static ./.next/static +COPY /.next/standalone ./ +COPY /.next/static ./.next/static -USER nextjs EXPOSE 7575 ENV PORT 7575 VOLUME /app/data/configs -CMD ["node", "server.js"] +CMD ["node", "server.js"] \ No newline at end of file diff --git a/README.md b/README.md index f0c01a4ca..a05fd2ef5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,17 @@ - <h3 align="center">Homarr</h3> +<br/> +<p align="center"> + <a href="https://github.com/ajnart/homarr/actions/workflows/docker.yml"> + <img title="Docker CI Status" src="https://github.com/ajnart/homarr/actions/workflows/docker.yml/badge.svg" alt="CI Status"></a> + <a href="https://github.com/ajnart/homarr/releases/latest"> + <img alt="GitHub release (latest SemVer)" src="https://img.shields.io/github/v/release/ajnart/homarr"></a> + <a href="https://github.com/ajnart/homarr/pkgs/container/homarr"> + <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/ajnart/homarr?label=Downloads%20"></a> + </p> <p align="center"> -<img align="end" width=500 src="https://user-images.githubusercontent.com/49837342/168315259-b778c816-10fe-44db-bd25-3eea6f31b233.png" /> + <a href=""> +<img align="end" width=600 src="https://user-images.githubusercontent.com/49837342/168315259-b778c816-10fe-44db-bd25-3eea6f31b233.png" /> + <a/> </p> <p align = "center"> A homepage for <i>your</i> server. @@ -11,10 +21,11 @@ <br /> <i>Join the discord!</i> <br /> - <a href = "https://discord.gg/aCsmEV5RgA" > <img src="https://discordapp.com/api/guilds/972958686051962910/widget.png?style=shield" > </a> + <a href = "https://discord.gg/aCsmEV5RgA" > <img title="Discord" src="https://discordapp.com/api/guilds/972958686051962910/widget.png?style=shield" > </a> + <br/> + <br/> </p> - # ๐Ÿ“ƒ Table of Contents - [๐Ÿ“ƒ Table of Contents](#-table-of-contents) - [๐Ÿš€ Getting Started](#-getting-started) @@ -34,11 +45,6 @@ Homarr is a simple and lightweight homepage for your server, that helps you easi **[โคด๏ธ Back to Top](#-table-of-contents)** -## ๐Ÿ› Known Issues - -- Application cards not responsive https://github.com/ajnart/homarr/issues/47 -- Icon alignment out for specific icons https://github.com/ajnart/homarr/issues/82 - ## โšก Installation ### Deploying from Docker Image ๐Ÿณ diff --git a/components/AppShelf/AppShelf.tsx b/components/AppShelf/AppShelf.tsx deleted file mode 100644 index af5f85340..000000000 --- a/components/AppShelf/AppShelf.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React, { useState } from 'react'; -import { motion } from 'framer-motion'; -import { Text, AspectRatio, SimpleGrid, Card, Image, Group, Space } from '@mantine/core'; -import { useConfig } from '../../tools/state'; -import { serviceItem } from '../../tools/types'; -import AddItemShelfItem from './AddAppShelfItem'; -import { AppShelfItemWrapper } from './AppShelfItemWrapper'; -import AppShelfMenu from './AppShelfMenu'; - -const AppShelf = () => { - const { config } = useConfig(); - - return ( - <SimpleGrid m="xl" cols={5} spacing="xl"> - {config.services.map((service) => ( - <AppShelfItem key={service.name} service={service} /> - ))} - <AddItemShelfItem /> - </SimpleGrid> - ); -}; - -export function AppShelfItem(props: any) { - const { service }: { service: serviceItem } = props; - const [hovering, setHovering] = useState(false); - return ( - <motion.div - key={service.name} - onHoverStart={() => { - setHovering(true); - }} - onHoverEnd={() => { - setHovering(false); - }} - > - <AppShelfItemWrapper hovering={hovering}> - <Card.Section> - <Group position="apart" mx="lg"> - <Space /> - <Text - // TODO: #1 Remove this hack to get the text to be centered. - ml={15} - style={{ - alignSelf: 'center', - alignContent: 'center', - alignItems: 'center', - justifyContent: 'center', - justifyItems: 'center', - }} - mt="sm" - weight={500} - > - {service.name} - </Text> - <motion.div - style={{ - alignSelf: 'flex-end', - }} - animate={{ - opacity: hovering ? 1 : 0, - }} - > - <AppShelfMenu service={service} /> - </motion.div> - </Group> - </Card.Section> - <Card.Section> - <AspectRatio ratio={5 / 3} m="xl"> - <motion.i - whileHover={{ - cursor: 'pointer', - scale: 1.1, - }} - > - <Image - onClick={() => { - window.open(service.url); - }} - style={{ - maxWidth: '50%', - marginBottom: 10, - }} - src={service.icon} - /> - </motion.i> - </AspectRatio> - </Card.Section> - </AppShelfItemWrapper> - </motion.div> - ); -} - -export default AppShelf; diff --git a/components/Welcome/Welcome.story.tsx b/components/Welcome/Welcome.story.tsx deleted file mode 100644 index 9c4600005..000000000 --- a/components/Welcome/Welcome.story.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { Welcome } from './Welcome'; - -export default { - title: 'Welcome', -}; - -export const Usage = () => <Welcome />; diff --git a/components/Welcome/Welcome.styles.ts b/components/Welcome/Welcome.styles.ts deleted file mode 100644 index d1b99469f..000000000 --- a/components/Welcome/Welcome.styles.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createStyles } from '@mantine/core'; - -export default createStyles((theme) => ({ - title: { - color: theme.colorScheme === 'dark' ? theme.white : theme.black, - fontSize: 100, - fontWeight: 900, - letterSpacing: -2, - - [theme.fn.smallerThan('md')]: { - fontSize: 50, - }, - }, -})); diff --git a/components/Welcome/Welcome.test.tsx b/components/Welcome/Welcome.test.tsx deleted file mode 100644 index c3b94254e..000000000 --- a/components/Welcome/Welcome.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import { Welcome } from './Welcome'; - -describe('Welcome component', () => { - it('has correct Next.js theming section link', () => { - render(<Welcome />); - expect(screen.getByText('this guide')).toHaveAttribute( - 'href', - 'https://mantine.dev/theming/next/' - ); - }); -}); diff --git a/components/Welcome/Welcome.tsx b/components/Welcome/Welcome.tsx deleted file mode 100644 index 8ade7ec0b..000000000 --- a/components/Welcome/Welcome.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Title, Text, Anchor } from '@mantine/core'; -import useStyles from './Welcome.styles'; - -export function Welcome() { - const { classes } = useStyles(); - - return ( - <> - <Title className={classes.title} align="center" mt={100}> - Welcome to{' '} - <Text inherit variant="gradient" component="span"> - Mantine - </Text> - - - This starter Next.js project includes a minimal setup for server side rendering, if you want - to learn more on Mantine + Next.js integration follow{' '} - - this guide - - . To get started edit index.tsx file. - - - ); -} diff --git a/components/layout/Logo.tsx b/components/layout/Logo.tsx deleted file mode 100644 index 824688a1b..000000000 --- a/components/layout/Logo.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Text } from '@mantine/core'; -import * as React from 'react'; - -export function Logo({ style }: any) { - return ( - - Homarr - - ); -} diff --git a/data/configs/config_new.json b/data/configs/config_new.json index a938826f0..283a8b971 100644 --- a/data/configs/config_new.json +++ b/data/configs/config_new.json @@ -10,7 +10,7 @@ ], "settings": { "searchBar": true, - "searchUrl": "https://google.com/search?q=", + "searchUrl": "https://duckduckgo.com/?q=", "enabledModules": [] } } \ No newline at end of file diff --git a/data/constants.ts b/data/constants.ts index 3d4ed3dad..a03b01ee9 100644 --- a/data/constants.ts +++ b/data/constants.ts @@ -1,2 +1,2 @@ export const REPO_URL = 'ajnart/homarr'; -export const CURRENT_VERSION = 'v0.2.0'; +export const CURRENT_VERSION = 'v0.3.0'; diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 7365fc753..000000000 --- a/jest.config.js +++ /dev/null @@ -1,16 +0,0 @@ -const nextJest = require('next/jest'); - -const createJestConfig = nextJest({ - dir: './', -}); - -const customJestConfig = { - setupFilesAfterEnv: ['/jest.setup.js'], - moduleNameMapper: { - '^@/components/(.*)$': '/components/$1', - '^@/pages/(.*)$': '/pages/$1', - }, - testEnvironment: 'jest-environment-jsdom', -}; - -module.exports = createJestConfig(customJestConfig); diff --git a/jest.setup.js b/jest.setup.js deleted file mode 100644 index 666127af3..000000000 --- a/jest.setup.js +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom/extend-expect'; diff --git a/package.json b/package.json index 961298b49..6c6ee0354 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "homarr", - "version": "0.1.6", + "version": "0.3.0", "private": "false", - "description": "Homarr - A homepage for your server.", + "description": "Homarr - A homepage for your server.", "repository": { "type": "git", "url": "https://github.com/ajnart/homarr" diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 000000000..8565f6c31 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/favicon.svg b/public/favicon.svg index 5b4f8fe08..c5c6c1a70 100644 --- a/public/favicon.svg +++ b/public/favicon.svg @@ -1,6 +1 @@ - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/public/imgs/favicon.png b/public/imgs/favicon.png new file mode 100644 index 000000000..8565f6c31 Binary files /dev/null and b/public/imgs/favicon.png differ diff --git a/public/imgs/logo-color.svg b/public/imgs/logo-color.svg new file mode 100644 index 000000000..c5c6c1a70 --- /dev/null +++ b/public/imgs/logo-color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/imgs/logo.png b/public/imgs/logo.png new file mode 100644 index 000000000..2b0fd46aa Binary files /dev/null and b/public/imgs/logo.png differ diff --git a/public/imgs/logo.svg b/public/imgs/logo.svg new file mode 100644 index 000000000..9da9311c8 --- /dev/null +++ b/public/imgs/logo.svg @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/AppShelf/AddAppShelfItem.tsx b/src/components/AppShelf/AddAppShelfItem.tsx similarity index 89% rename from components/AppShelf/AddAppShelfItem.tsx rename to src/components/AppShelf/AddAppShelfItem.tsx index 5f42d2af2..9a413ba5d 100644 --- a/components/AppShelf/AddAppShelfItem.tsx +++ b/src/components/AppShelf/AddAppShelfItem.tsx @@ -10,6 +10,8 @@ import { Text, Card, LoadingOverlay, + ActionIcon, + Tooltip, } from '@mantine/core'; import { useForm } from '@mantine/form'; import { motion } from 'framer-motion'; @@ -19,13 +21,42 @@ import { useConfig } from '../../tools/state'; import { ServiceTypeList } from '../../tools/types'; import { AppShelfItemWrapper } from './AppShelfItemWrapper'; +export function AddItemShelfButton(props: any) { + const [opened, setOpened] = useState(false); + return ( + <> + setOpened(false)} + title="Add a service" + > + + + setOpened(true)} + > + + + + + + ); +} + export default function AddItemShelfItem(props: any) { const [opened, setOpened] = useState(false); return ( <> setOpened(false)} title="Add a service" diff --git a/components/AppShelf/AppShelf.story.tsx b/src/components/AppShelf/AppShelf.story.tsx similarity index 69% rename from components/AppShelf/AppShelf.story.tsx rename to src/components/AppShelf/AppShelf.story.tsx index 610f1370c..928510aac 100644 --- a/components/AppShelf/AppShelf.story.tsx +++ b/src/components/AppShelf/AppShelf.story.tsx @@ -1,3 +1,4 @@ +import { SimpleGrid } from '@mantine/core'; import AppShelf, { AppShelfItem } from './AppShelf'; export default { @@ -16,3 +17,10 @@ export default { export const Default = (args: any) => ; export const One = (args: any) => ; +export const Ten = (args: any) => ( + + {Array.from(Array(10)).map((_, i) => ( + + ))} + +); diff --git a/src/components/AppShelf/AppShelf.tsx b/src/components/AppShelf/AppShelf.tsx new file mode 100644 index 000000000..d76413811 --- /dev/null +++ b/src/components/AppShelf/AppShelf.tsx @@ -0,0 +1,104 @@ +import React, { useState } from 'react'; +import { motion } from 'framer-motion'; +import { Text, AspectRatio, SimpleGrid, Card, Image, useMantineTheme } from '@mantine/core'; +import { useConfig } from '../../tools/state'; +import { serviceItem } from '../../tools/types'; +import AppShelfMenu from './AppShelfMenu'; + +const AppShelf = () => { + const { config } = useConfig(); + + return ( + + {config.services.map((service) => ( + + ))} + + ); +}; + +export function AppShelfItem(props: any) { + const { service }: { service: serviceItem } = props; + const [hovering, setHovering] = useState(false); + const theme = useMantineTheme(); + return ( + { + setHovering(true); + }} + onHoverEnd={() => { + setHovering(false); + }} + > + + + + {service.name} + + + + + + + + + { + window.open(service.url); + }} + src={service.icon} + /> + + + + + + ); +} + +export default AppShelf; diff --git a/components/AppShelf/AppShelfItemWrapper.tsx b/src/components/AppShelf/AppShelfItemWrapper.tsx similarity index 78% rename from components/AppShelf/AppShelfItemWrapper.tsx rename to src/components/AppShelf/AppShelfItemWrapper.tsx index a305661e6..ffe409062 100644 --- a/components/AppShelf/AppShelfItemWrapper.tsx +++ b/src/components/AppShelf/AppShelfItemWrapper.tsx @@ -8,10 +8,6 @@ export function AppShelfItemWrapper(props: any) { style={{ boxShadow: hovering ? '0px 0px 3px rgba(0, 0, 0, 0.5)' : '0px 0px 1px rgba(0, 0, 0, 0.5)', backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1], - - //TODO: #3 Fix this temporary fix and make the width and height dynamic / responsive - width: 200, - height: 180, }} radius="md" > diff --git a/components/AppShelf/AppShelfMenu.tsx b/src/components/AppShelf/AppShelfMenu.tsx similarity index 100% rename from components/AppShelf/AppShelfMenu.tsx rename to src/components/AppShelf/AppShelfMenu.tsx diff --git a/components/ColorSchemeToggle/ColorSchemeSwitch.tsx b/src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx similarity index 100% rename from components/ColorSchemeToggle/ColorSchemeSwitch.tsx rename to src/components/ColorSchemeToggle/ColorSchemeSwitch.tsx diff --git a/components/ColorSchemeToggle/ColorSchemeToggle.tsx b/src/components/ColorSchemeToggle/ColorSchemeToggle.tsx similarity index 100% rename from components/ColorSchemeToggle/ColorSchemeToggle.tsx rename to src/components/ColorSchemeToggle/ColorSchemeToggle.tsx diff --git a/components/Config/ConfigChanger.tsx b/src/components/Config/ConfigChanger.tsx similarity index 100% rename from components/Config/ConfigChanger.tsx rename to src/components/Config/ConfigChanger.tsx diff --git a/components/Config/LoadConfig.tsx b/src/components/Config/LoadConfig.tsx similarity index 100% rename from components/Config/LoadConfig.tsx rename to src/components/Config/LoadConfig.tsx diff --git a/components/Config/SaveConfig.tsx b/src/components/Config/SaveConfig.tsx similarity index 100% rename from components/Config/SaveConfig.tsx rename to src/components/Config/SaveConfig.tsx diff --git a/components/Config/SelectConfig.tsx b/src/components/Config/SelectConfig.tsx similarity index 100% rename from components/Config/SelectConfig.tsx rename to src/components/Config/SelectConfig.tsx diff --git a/components/SearchBar/SearchBar.story.tsx b/src/components/SearchBar/SearchBar.story.tsx similarity index 100% rename from components/SearchBar/SearchBar.story.tsx rename to src/components/SearchBar/SearchBar.story.tsx diff --git a/components/SearchBar/SearchBar.tsx b/src/components/SearchBar/SearchBar.tsx similarity index 94% rename from components/SearchBar/SearchBar.tsx rename to src/components/SearchBar/SearchBar.tsx index fec0dffe4..7a40ea4c0 100644 --- a/components/SearchBar/SearchBar.tsx +++ b/src/components/SearchBar/SearchBar.tsx @@ -22,6 +22,7 @@ export default function SearchBar(props: any) { return ( - tip: You can prefix your querry with !yt or !t to research on youtube or - for a torrent + tip: Use the prefixes !yt and !t in front of your query to search on YouTube or for a Torrent respectively. diff --git a/components/Settings/ModuleEnabler.tsx b/src/components/Settings/ModuleEnabler.tsx similarity index 100% rename from components/Settings/ModuleEnabler.tsx rename to src/components/Settings/ModuleEnabler.tsx diff --git a/components/Settings/SettingsMenu.story.tsx b/src/components/Settings/SettingsMenu.story.tsx similarity index 100% rename from components/Settings/SettingsMenu.story.tsx rename to src/components/Settings/SettingsMenu.story.tsx diff --git a/components/Settings/SettingsMenu.tsx b/src/components/Settings/SettingsMenu.tsx similarity index 77% rename from components/Settings/SettingsMenu.tsx rename to src/components/Settings/SettingsMenu.tsx index b8fed02eb..74b5c1b93 100644 --- a/components/Settings/SettingsMenu.tsx +++ b/src/components/Settings/SettingsMenu.tsx @@ -9,11 +9,12 @@ import { SegmentedControl, Indicator, Alert, + TextInput, } from '@mantine/core'; import { useColorScheme } from '@mantine/hooks'; import { useEffect, useState } from 'react'; import { AlertCircle, Settings as SettingsIcon } from 'tabler-icons-react'; -import { CURRENT_VERSION, REPO_URL } from '../../data/constants'; +import { CURRENT_VERSION, REPO_URL } from '../../../data/constants'; import { useConfig } from '../../tools/state'; import { ColorSchemeSwitch } from '../ColorSchemeToggle/ColorSchemeSwitch'; import ConfigChanger from '../Config/ConfigChanger'; @@ -24,11 +25,19 @@ function SettingsMenu(props: any) { const { config, setConfig } = useConfig(); const colorScheme = useColorScheme(); const { current, latest } = props; + const matches = [ { label: 'Google', value: 'https://google.com/search?q=' }, { label: 'DuckDuckGo', value: 'https://duckduckgo.com/?q=' }, { label: 'Bing', value: 'https://bing.com/search?q=' }, + { label: 'Custom', value: 'Custom' }, ]; + + const [customSearchUrl, setCustomSearchUrl] = useState(config.settings.searchUrl); + const [searchUrl, setSearchUrl] = useState( + matches.find((match) => match.value === config.settings.searchUrl)?.value ?? 'Custom' + ); + return ( - + + Search engine match.value === config.settings.searchUrl)?.value ?? 'Google' + searchUrl } onChange={ // Set config.settings.searchUrl to the value of the selected item - (e) => + (e) => { + setSearchUrl(e); setConfig({ ...config, settings: { ...config.settings, searchUrl: e, }, - }) + }); + } } data={matches} /> - Search engine + {searchUrl === 'Custom' && ( + { + setCustomSearchUrl(event.currentTarget.value); + setConfig({ + ...config, + settings: { + ...config.settings, + searchUrl: event.currentTarget.value, + }, + }); + }} + /> + )} - - + - Made with โค๏ธ by @ - - ajnart - - - + {items} + + component="a" href="https://github.com/ajnart/homarr" size="lg"> + + + + + Made with โค๏ธ by @ + + ajnart + + + + ); } diff --git a/components/layout/Header.tsx b/src/components/layout/Header.tsx similarity index 57% rename from components/layout/Header.tsx rename to src/components/layout/Header.tsx index b8eb2a9ab..44185e28e 100644 --- a/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -1,18 +1,11 @@ -import React, { useState } from 'react'; -import { - createStyles, - Header as Head, - Container, - Group, - Burger, - Drawer, - Center, -} from '@mantine/core'; +import React from 'react'; +import { createStyles, Header as Head, Group, Drawer, Center } from '@mantine/core'; import { useBooleanToggle } from '@mantine/hooks'; import { NextLink } from '@mantine/next'; import { Logo } from './Logo'; -import { SettingsMenuButton } from '../Settings/SettingsMenu'; import CalendarComponent from '../modules/calendar/CalendarModule'; +import { SettingsMenuButton } from '../Settings/SettingsMenu'; +import { AddItemShelfButton } from '../AppShelf/AddAppShelfItem'; const HEADER_HEIGHT = 60; @@ -40,8 +33,6 @@ const useStyles = createStyles((theme) => ({ header: { display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', height: '100%', }, @@ -94,62 +85,33 @@ interface HeaderResponsiveProps { export function Header({ links }: HeaderResponsiveProps) { const [opened, toggleOpened] = useBooleanToggle(false); - const [active, setActive] = useState('/'); const { classes, cx } = useStyles(); - const items = ( - <> - {links.map((link) => ( - { - setActive(link.link); - toggleOpened(false); - }} - > - {link.label} - - ))} - - ); return ( - - - - - - - - - {items} - + + + + + - - toggleOpened()} - className={classes.burger} - size="sm" - /> + + - toggleOpened()} - position="right" - > - {opened ?? ( -
- -
- )} -
-
+ toggleOpened()} + position="right" + > + {opened ?? ( +
+ +
+ )} +
); } diff --git a/components/layout/Layout.tsx b/src/components/layout/Layout.tsx similarity index 97% rename from components/layout/Layout.tsx rename to src/components/layout/Layout.tsx index bfb1a2dc3..ab646803d 100644 --- a/components/layout/Layout.tsx +++ b/src/components/layout/Layout.tsx @@ -7,7 +7,7 @@ import Navbar from './Navbar'; const useStyles = createStyles((theme) => ({ main: { [theme.fn.largerThan('md')]: { - width: 1200, + maxWidth: 1500, }, }, })); diff --git a/src/components/layout/Logo.tsx b/src/components/layout/Logo.tsx new file mode 100644 index 000000000..92ea10606 --- /dev/null +++ b/src/components/layout/Logo.tsx @@ -0,0 +1,40 @@ +import { Group, Image, Text } from '@mantine/core'; +import * as React from 'react'; +import { CURRENT_VERSION } from '../../../data/constants'; + +export function Logo({ style }: any) { + return ( + + + + Homarr + + + {CURRENT_VERSION} + + + ); +} diff --git a/components/layout/Navbar.tsx b/src/components/layout/Navbar.tsx similarity index 52% rename from components/layout/Navbar.tsx rename to src/components/layout/Navbar.tsx index 2f9b26f0b..7bb7a8410 100644 --- a/components/layout/Navbar.tsx +++ b/src/components/layout/Navbar.tsx @@ -1,18 +1,22 @@ -import { Navbar as MantineNavbar } from '@mantine/core'; +import { Group, Navbar as MantineNavbar } from '@mantine/core'; import { DateModule } from '../modules/date/DateModule'; import ModuleWrapper from '../modules/moduleWrapper'; export default function Navbar() { return ( ); } diff --git a/components/modules/calendar/CalendarComponent.story.tsx b/src/components/modules/calendar/CalendarComponent.story.tsx similarity index 100% rename from components/modules/calendar/CalendarComponent.story.tsx rename to src/components/modules/calendar/CalendarComponent.story.tsx diff --git a/components/modules/calendar/CalendarModule.tsx b/src/components/modules/calendar/CalendarModule.tsx similarity index 98% rename from components/modules/calendar/CalendarModule.tsx rename to src/components/modules/calendar/CalendarModule.tsx index 0af7a9a92..dd84050fa 100644 --- a/components/modules/calendar/CalendarModule.tsx +++ b/src/components/modules/calendar/CalendarModule.tsx @@ -2,9 +2,8 @@ import { Popover, Box, ScrollArea, Divider, Indicator } from '@mantine/core'; import React, { useEffect, useState } from 'react'; import { Calendar } from '@mantine/dates'; -import { CalendarIcon } from '@modulz/radix-icons'; import { showNotification } from '@mantine/notifications'; -import { Check } from 'tabler-icons-react'; +import { Calendar as CalendarIcon, Check } from 'tabler-icons-react'; import { RadarrMediaDisplay, SonarrMediaDisplay } from './MediaDisplay'; import { useConfig } from '../../../tools/state'; import { IModule } from '../modules'; diff --git a/components/modules/calendar/MediaDisplay.story.tsx b/src/components/modules/calendar/MediaDisplay.story.tsx similarity index 100% rename from components/modules/calendar/MediaDisplay.story.tsx rename to src/components/modules/calendar/MediaDisplay.story.tsx diff --git a/components/modules/calendar/MediaDisplay.tsx b/src/components/modules/calendar/MediaDisplay.tsx similarity index 100% rename from components/modules/calendar/MediaDisplay.tsx rename to src/components/modules/calendar/MediaDisplay.tsx diff --git a/components/modules/calendar/index.ts b/src/components/modules/calendar/index.ts similarity index 100% rename from components/modules/calendar/index.ts rename to src/components/modules/calendar/index.ts diff --git a/components/modules/calendar/mediaExample.ts b/src/components/modules/calendar/mediaExample.ts similarity index 100% rename from components/modules/calendar/mediaExample.ts rename to src/components/modules/calendar/mediaExample.ts diff --git a/components/modules/date/DateModule.story.tsx b/src/components/modules/date/DateModule.story.tsx similarity index 100% rename from components/modules/date/DateModule.story.tsx rename to src/components/modules/date/DateModule.story.tsx diff --git a/components/modules/date/DateModule.tsx b/src/components/modules/date/DateModule.tsx similarity index 100% rename from components/modules/date/DateModule.tsx rename to src/components/modules/date/DateModule.tsx diff --git a/components/modules/date/index.ts b/src/components/modules/date/index.ts similarity index 100% rename from components/modules/date/index.ts rename to src/components/modules/date/index.ts diff --git a/components/modules/index.ts b/src/components/modules/index.ts similarity index 100% rename from components/modules/index.ts rename to src/components/modules/index.ts diff --git a/components/modules/moduleWrapper.tsx b/src/components/modules/moduleWrapper.tsx similarity index 100% rename from components/modules/moduleWrapper.tsx rename to src/components/modules/moduleWrapper.tsx diff --git a/components/modules/modules.tsx b/src/components/modules/modules.tsx similarity index 100% rename from components/modules/modules.tsx rename to src/components/modules/modules.tsx diff --git a/components/modules/readme.md b/src/components/modules/readme.md similarity index 100% rename from components/modules/readme.md rename to src/components/modules/readme.md diff --git a/pages/_app.tsx b/src/pages/_app.tsx similarity index 95% rename from pages/_app.tsx rename to src/pages/_app.tsx index 89887632d..3b2271307 100644 --- a/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,6 +5,7 @@ import { getCookie, setCookies } from 'cookies-next'; import Head from 'next/head'; import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core'; import { NotificationsProvider } from '@mantine/notifications'; +import { useHotkeys } from '@mantine/hooks'; import Layout from '../components/layout/Layout'; import { ConfigProvider } from '../tools/state'; import { theme } from '../tools/theme'; @@ -18,6 +19,7 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) { setColorScheme(nextColorScheme); setCookies('color-scheme', nextColorScheme, { maxAge: 60 * 60 * 24 * 30 }); }; + useHotkeys([['mod+J', () => toggleColorScheme()]]); return ( <> diff --git a/pages/_document.tsx b/src/pages/_document.tsx similarity index 100% rename from pages/_document.tsx rename to src/pages/_document.tsx diff --git a/pages/api/configs/[slug].ts b/src/pages/api/configs/[slug].ts similarity index 100% rename from pages/api/configs/[slug].ts rename to src/pages/api/configs/[slug].ts diff --git a/pages/api/configs/index.ts b/src/pages/api/configs/index.ts similarity index 100% rename from pages/api/configs/index.ts rename to src/pages/api/configs/index.ts diff --git a/pages/index.tsx b/src/pages/index.tsx similarity index 100% rename from pages/index.tsx rename to src/pages/index.tsx diff --git a/tools/state.tsx b/src/tools/state.tsx similarity index 100% rename from tools/state.tsx rename to src/tools/state.tsx diff --git a/tools/theme.ts b/src/tools/theme.ts similarity index 100% rename from tools/theme.ts rename to src/tools/theme.ts diff --git a/tools/types.ts b/src/tools/types.ts similarity index 100% rename from tools/types.ts rename to src/tools/types.ts diff --git a/tsconfig.json b/tsconfig.json index 99710e857..3ff0501fd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,6 +15,6 @@ "jsx": "preserve", "incremental": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js"], "exclude": ["node_modules"] }