├── .dockerignore ├── .env.exemple ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── .nvmrc ├── Dockerfile ├── LICENSE ├── README.md ├── app.config.ts ├── app.vue ├── assets └── style │ ├── animation.scss │ ├── main.scss │ └── themes.scss ├── components ├── Avatar.vue ├── ButtonPrimary.vue ├── EnvChecker.vue ├── Loader.vue ├── Logo.vue ├── Movie │ ├── BackdropCard.vue │ ├── MainCarousel.vue │ └── PosterCard.vue ├── Movies.vue ├── ProfilTool.vue ├── TrailerPreview.vue ├── UsersTable.vue ├── layout │ ├── CommandConsole.vue │ ├── Footer.vue │ └── Navbar.vue ├── settings │ └── LanguageSelector.vue └── upload │ ├── AvatarUpload.vue │ └── CoverUpload.vue ├── composables ├── useAuth.ts ├── useClipboard.ts ├── useMovie.ts ├── useNavigation.ts ├── useStorage.ts └── useToasts.ts ├── cypress ├── e2e │ ├── contact.cy.ts │ ├── login.cy.ts │ ├── navigation.cy.ts │ └── register.cy.ts ├── fixtures │ └── example.json └── support │ ├── commands.ts │ └── e2e.ts ├── docker-compose.yml ├── docs ├── about.md └── readme.md ├── error.vue ├── layouts ├── default.vue └── detail.vue ├── locales ├── en.json └── fr.json ├── middleware ├── already-auth.ts └── auth.ts ├── nuxt.config.ts ├── package.json ├── pages ├── admin │ └── dashboard.vue ├── auth │ ├── login.vue │ └── signup.vue ├── contact.vue ├── films.vue ├── home.vue ├── movie │ └── [id].vue ├── password │ ├── forgot.vue │ └── reset-[token].vue ├── profile │ ├── account.vue │ └── settings.vue ├── search.vue ├── series.vue └── verify │ └── user.vue ├── plugins └── sweetalert.ts ├── pnpm-lock.yaml ├── public ├── favicon.ico └── nuxi-preview.png ├── retype.yml ├── server ├── api │ ├── admin │ │ ├── [userId].delete.ts │ │ └── users.get.ts │ ├── auth │ │ ├── login.post.ts │ │ ├── logout.post.ts │ │ ├── password │ │ │ ├── [email].post.ts │ │ │ └── reset.post.ts │ │ ├── signup.post.ts │ │ ├── user.ts │ │ └── verify │ │ │ ├── [email].post.ts │ │ │ └── sendVerification.post.ts │ ├── mailer │ │ ├── sendMailToSupport.post.ts │ │ └── templates │ │ │ ├── baseEmail.ts │ │ │ ├── new-user.ts │ │ │ └── reset-password.ts │ ├── support.post.ts │ └── user │ │ ├── [userId].delete.ts │ │ └── [userId].put.ts ├── app │ ├── authService.ts │ ├── mailerService.ts │ └── userService.ts ├── database │ ├── client.ts │ └── schema.prisma └── middleware │ ├── serverAdmin.ts │ └── serverAuth.ts ├── store ├── globalStore.ts ├── movieStore.ts └── userStore.ts ├── tailwind.config.js ├── tsconfig.json └── types ├── Role.ts ├── movie.ts └── user.ts /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | node_modules 3 | Dockerfile 4 | pnpm-lock.yaml 5 | .gitignore 6 | .eslintrc.json 7 | README.md -------------------------------------------------------------------------------- /.env.exemple: -------------------------------------------------------------------------------- 1 | APP_ENV=development 2 | APP_URL=http://localhost:8081 3 | PORT=8081 4 | 5 | MAILER_HOST=smtp.gmail.com 6 | MAILER_PORT=587 7 | MAILER_USER=your_email 8 | MAILER_PASSWORD=your_password 9 | 10 | AUTH_TOKEN_SECRET=secret 11 | AUTH_TOKEN_EXPIRATION=1h 12 | 13 | DATABASE_URL=postgres://postgres:postgres@localhost:5432/maisonhochard 14 | 15 | SUPABASE_URL=your_url 16 | SUPABASE_KEY=your_key 17 | 18 | TMDB_API_KEY=your_api_key 19 | TMDB_ACCESS_TOKEN=your_access_token 20 | 21 | LINEAR_API_KEY=your_api_key 22 | 23 | ## Exemple request https://api.themoviedb.org/3/movie/550?api_key=1c23f126a0966 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:vue/vue3-essential", 9 | "plugin:@typescript-eslint/recommended", 10 | "plugin:prettier/recommended" 11 | ], 12 | "overrides": [ 13 | ], 14 | "parser": "vue-eslint-parser", 15 | "parserOptions": { 16 | "parser": "@typescript-eslint/parser", 17 | "ecmaVersion": "latest", 18 | "sourceType": "module" 19 | }, 20 | "plugins": [ 21 | "prettier", 22 | "vue", 23 | "@typescript-eslint" 24 | ], 25 | "rules": { 26 | "prettier/prettier": [ 27 | "error", 28 | { 29 | "singleQuote": false, 30 | "tabWidth": 2, 31 | "indent": 2, 32 | "trailingComma": "all", 33 | "semi": true, 34 | "printWidth": 120 35 | } 36 | ], 37 | "func-name-matching": "error", 38 | "no-empty-function": "off", 39 | "prefer-const": "error", 40 | "no-undef": "off", 41 | "vue/multi-word-component-names": "off", 42 | "linebreak-style": [ 43 | "error", 44 | "unix" 45 | ], 46 | "quotes": [ 47 | "error", 48 | "double" 49 | ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | .idea 10 | .vscode -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.13 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18-alpine as nuxi-app 2 | 3 | ARG DATABASE_URL 4 | 5 | ARG MAILER_HOST 6 | ARG MAILER_PORT 7 | ARG MAILER_USER 8 | ARG MAILER_PASSWORD 9 | 10 | ARG AUTH_TOKEN_SECRET 11 | ARG AUTH_TOKEN_EXPIRATION 12 | 13 | ARG APP_URL 14 | ARG APP_ENV 15 | 16 | ARG TMDB_API_KEY 17 | ARG TMDB_ACCESS_TOKEN 18 | 19 | ARG SUPABASE_URL 20 | ARG SUPABASE_KEY 21 | 22 | ARG LINEAR_API_KEY 23 | 24 | WORKDIR /app 25 | 26 | COPY . . 27 | 28 | RUN apk add --update --no-cache python3 build-base gcc && ln -sf /usr/bin/python3 /usr/bin/python 29 | 30 | RUN npm install --force 31 | 32 | RUN npx prisma generate 33 | 34 | RUN npx nuxi build 35 | 36 | CMD ["node", ".output/server/index.mjs"] 37 | 38 | EXPOSE 3000 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Hugo Richard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxi 2 | 3 | [![nuxi preview](public/nuxi-preview.png)](https://hugorcd.github.io/nuxi/) 4 | 5 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/96ef5ef23a4442c2bf73762f46e52749)](https://www.codacy.com/gh/hugoRCD/nuxtjs-boilerplate/dashboard?utm_source=github.com&utm_medium=referral&utm_content=hugoRCD/nuxtjs-boilerplate&utm_campaign=Badge_Grade) 6 | 7 | ## Features 8 | 9 | ### Authentication 10 | - OAuth authentication with multiple providers such as Google, GitHub, etc... 11 | - Working forgot password feature 12 | 13 | ### UI/UX 14 | - Translation with I18n for multiple languages support 15 | - Dark and light theme switchable by the user 16 | - Fully responsive design using SCSS 17 | - Admin Dashboard 18 | 19 | ### API 20 | - Use [Supabase](https://supabase.io/) for real-time and powerful API 21 | - Easy and secure way to connect your frontend to your database 22 | - There is also a self api inside using the Nitro server built-in Nuxt 23 | 24 | ### Deployment 25 | - Include [Docker](https://www.docker.com/) configuration using a Dockerfile and Docker-compose 26 | - Easily deploy the application in a container running on port 8080 27 | - simply run `docker-compose up` to start the application 28 | 29 | ### Documentation 30 | - Use [Retype](https://retype.js.org/) for documentation 31 | - Automatic generation of documentation from your code 32 | 33 | ### Lint 34 | - Eslint is configure on the boilerplate (configure for Typescript, with Prettier) 35 | 36 | ## Console 37 | 38 | This application includes a powerful console that can be launched 39 | by using the shortcut `cmd + k`. This console can provide various 40 | features to facilitate development and management of the application but you 41 | will need to develop your own commands. the console in the boilerplate 42 | is just an example of what you can do with it. 43 | 44 | ## Contact 45 | 46 | The contact page is connect with a linear team to track ticket 47 | 48 | ## Mailer 49 | 50 | A Nodemailer is connected to send every kind of mail (forgot-password, new-user, etc...) 51 | 52 | ## Getting Started 53 | 54 | ### Clone the repository: 55 | ``` 56 | git clone git@github.com:hugoRCD/nuxi 57 | ``` 58 | 59 | ### Install dependencies: 60 | ``` 61 | pnpm install 62 | ``` 63 | There is no need to use the --shamefully-hoist flag here 64 | because the dependencies the flag is set to true by default in the .npmrc file. 65 | 66 | ### Start the development server: 67 | ``` 68 | pnpm dev 69 | ``` 70 | 71 | Now you can open the app in your browser at http://localhost:3000 if you do not override the default port. 72 | 73 | ### Start the documentation 74 | ``` 75 | retype watch 76 | ``` 77 | 78 | You can access the live documentation at https://hugorcd.github.io/nuxi/ 79 | 80 | ## Built With 81 | 82 | - [Nuxt.js](https://nuxtjs.org/) - The Progressive JavaScript Framework 83 | - [Supabase](https://supabase.io/) - Open-Source Firebase alternative 84 | - [Retype](https://retype.js.org/) - The documentation engine 85 | - [pnpm](https://pnpm.js.org/) - Fast and disk space efficient package manager 86 | 87 | ## License 88 | 89 | This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details 90 | -------------------------------------------------------------------------------- /app.config.ts: -------------------------------------------------------------------------------- 1 | export default defineAppConfig({ 2 | appName: "Nuxi", 3 | appTitle: "Nuxi", 4 | appDescription: "Nuxi", 5 | appVersion: "1.0.0", 6 | }); 7 | -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 50 | -------------------------------------------------------------------------------- /assets/style/animation.scss: -------------------------------------------------------------------------------- 1 | .fade-enter-active, 2 | .fade-leave-active { 3 | transition: opacity .2s; 4 | } 5 | 6 | .fade-enter, .fade-leave-to { 7 | opacity: 0; 8 | } 9 | 10 | html { 11 | scroll-behavior: smooth; 12 | } -------------------------------------------------------------------------------- /assets/style/main.scss: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @import "animation"; 6 | @import "themes.scss"; 7 | 8 | html,body, #__nuxt, #__layout{ 9 | @apply bg-primary; 10 | height:100%!important; 11 | width: 100%!important; 12 | } 13 | 14 | ::-webkit-scrollbar { 15 | width: 0; 16 | background: transparent; 17 | } 18 | 19 | @layer components { 20 | .input { 21 | @apply bg-secondary; 22 | @apply text-primary placeholder:text-placeholder; 23 | @apply border-sm border-primary hover:border-primary-hover; 24 | @apply focus:outline-none; 25 | @apply px-4 py-2 rounded-md; 26 | @apply transition-colors duration-300 ease-in-out; 27 | } 28 | 29 | .btn-primary { 30 | @apply bg-accent hover:bg-accent-hover; 31 | @apply text-inverted; 32 | @apply rounded-md; 33 | @apply px-4 py-2 flex justify-center; 34 | @apply cursor-pointer; 35 | 36 | &:disabled { 37 | @apply bg-accent; 38 | @apply cursor-not-allowed; 39 | } 40 | } 41 | 42 | .btn-secondary { 43 | @apply bg-primary; 44 | @apply text-muted; 45 | @apply border-sm rounded-md border-primary hover:border-primary-hover; 46 | @apply px-4 py-2 flex justify-center; 47 | @apply cursor-pointer; 48 | } 49 | 50 | .card { 51 | @apply bg-secondary flex flex-col gap-4 mx-2 my-4 sm:mx-8 sm:my-8; 52 | @apply rounded-md; 53 | @apply shadow-md; 54 | @apply p-4; 55 | } 56 | 57 | .glass-button { 58 | @apply flex items-center justify-center rounded-md px-6 py-1; 59 | @apply text-white bg-white backdrop-blur-sm bg-opacity-10 opacity-70; 60 | @apply cursor-pointer hover:bg-opacity-20 hover:opacity-100; 61 | @apply transition duration-300 ease-in-out; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /assets/style/themes.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --bg-primary: #000000; 3 | --bg-primary-opacity: 12, 12, 13; 4 | --bg-secondary: #18181B; 5 | --bg-secondary-opacity: 24, 24, 27; 6 | --font-color: #FFFFFF; 7 | 8 | --font-primary: #FFFFFF; 9 | --font-muted: #66646A; 10 | --font-inverted: #FFFFFF; 11 | 12 | --border-primary: #2c282e; 13 | --border-primary-hover: #66646A; 14 | --border-muted: #1C1822; 15 | 16 | --accent-color: 70, 191, 239; 17 | --accent-color-hover: 45, 152, 195; 18 | --accent-color-faded: rgba(70, 191, 239, 0.2); 19 | 20 | --accent: #46BFEF; // Just to see the color only the -accent-color use in the app 21 | --accent-hover: #2d98c3; // Just to see the color only the -accent-color use in the app 22 | 23 | --font-placeholder: #403D46; 24 | } -------------------------------------------------------------------------------- /components/Avatar.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | -------------------------------------------------------------------------------- /components/ButtonPrimary.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 34 | -------------------------------------------------------------------------------- /components/EnvChecker.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /components/Loader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /components/Logo.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 34 | -------------------------------------------------------------------------------- /components/Movie/BackdropCard.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 54 | -------------------------------------------------------------------------------- /components/Movie/MainCarousel.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 44 | -------------------------------------------------------------------------------- /components/Movie/PosterCard.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 76 | 77 | 92 | -------------------------------------------------------------------------------- /components/Movies.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /components/ProfilTool.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 65 | -------------------------------------------------------------------------------- /components/TrailerPreview.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 |