diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.gitignore b/.gitignore index 087a183..1042d71 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,38 @@ target/ pom.xml.tag pom.xml.releaseBackup pom.xml.versionsBackup -release.properties \ No newline at end of file +release.properties + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +dist-ssr +coverage +*.local + +/cypress/videos/ +/cypress/screenshots/ + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +*.tsbuildinfo + +test-results/ +playwright-report/ diff --git a/src/frontend/.editorconfig b/src/frontend/.editorconfig new file mode 100644 index 0000000..5a5809d --- /dev/null +++ b/src/frontend/.editorconfig @@ -0,0 +1,9 @@ +[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}] +charset = utf-8 +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +end_of_line = lf +max_line_length = 100 diff --git a/src/frontend/README.md b/src/frontend/README.md new file mode 100644 index 0000000..b926770 --- /dev/null +++ b/src/frontend/README.md @@ -0,0 +1,64 @@ +# organizajogos-frontend + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). + +## Type Support for `.vue` Imports in TS + +TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types. + +## Customize configuration + +See [Vite Configuration Reference](https://vite.dev/config/). + +## Project Setup + +```sh +pnpm install +``` + +### Compile and Hot-Reload for Development + +```sh +pnpm dev +``` + +### Type-Check, Compile and Minify for Production + +```sh +pnpm build +``` + +### Run Unit Tests with [Vitest](https://vitest.dev/) + +```sh +pnpm test:unit +``` + +### Run End-to-End Tests with [Playwright](https://playwright.dev) + +```sh +# Install browsers for the first run +npx playwright install + +# When testing on CI, must build the project first +pnpm build + +# Runs the end-to-end tests +pnpm test:e2e +# Runs the tests only on Chromium +pnpm test:e2e --project=chromium +# Runs the tests of a specific file +pnpm test:e2e tests/example.spec.ts +# Runs the tests in debug mode +pnpm test:e2e --debug +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +pnpm lint +``` diff --git a/src/frontend/e2e/tsconfig.json b/src/frontend/e2e/tsconfig.json new file mode 100644 index 0000000..f31fe71 --- /dev/null +++ b/src/frontend/e2e/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": ["./**/*"] +} diff --git a/src/frontend/e2e/vue.spec.ts b/src/frontend/e2e/vue.spec.ts new file mode 100644 index 0000000..fc116a9 --- /dev/null +++ b/src/frontend/e2e/vue.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test'; + +// See here how to get started: +// https://playwright.dev/docs/intro +test('visits the app root url', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('h1')).toHaveText('You did it!'); +}) diff --git a/src/frontend/env.d.ts b/src/frontend/env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/frontend/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/frontend/eslint.config.ts b/src/frontend/eslint.config.ts new file mode 100644 index 0000000..8bd27d9 --- /dev/null +++ b/src/frontend/eslint.config.ts @@ -0,0 +1,32 @@ +import { globalIgnores } from 'eslint/config' +import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript' +import pluginVue from 'eslint-plugin-vue' +import pluginVitest from '@vitest/eslint-plugin' +import pluginPlaywright from 'eslint-plugin-playwright' + +// To allow more languages other than `ts` in `.vue` files, uncomment the following lines: +// import { configureVueProject } from '@vue/eslint-config-typescript' +// configureVueProject({ scriptLangs: ['ts', 'tsx'] }) +// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup + +export default defineConfigWithVueTs( + { + name: 'app/files-to-lint', + files: ['**/*.{ts,mts,tsx,vue}'], + }, + + globalIgnores(['**/dist/**', '**/dist-ssr/**', '**/coverage/**']), + + pluginVue.configs['flat/essential'], + vueTsConfigs.recommended, + + { + ...pluginVitest.configs.recommended, + files: ['src/**/__tests__/*'], + }, + + { + ...pluginPlaywright.configs['flat/recommended'], + files: ['e2e/**/*.{test,spec}.{js,ts,jsx,tsx}'], + }, +) diff --git a/src/frontend/index.html b/src/frontend/index.html new file mode 100644 index 0000000..9e5fc8f --- /dev/null +++ b/src/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/src/frontend/package.json b/src/frontend/package.json new file mode 100644 index 0000000..7f3d041 --- /dev/null +++ b/src/frontend/package.json @@ -0,0 +1,42 @@ +{ + "name": "organizajogos-frontend", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "test:unit": "vitest", + "test:e2e": "playwright test", + "build-only": "vite build", + "type-check": "vue-tsc --build", + "lint": "eslint . --fix" + }, + "dependencies": { + "vue": "^3.5.17" + }, + "devDependencies": { + "@playwright/test": "^1.53.1", + "@tsconfig/node22": "^22.0.2", + "@types/jsdom": "^21.1.7", + "@types/node": "^22.15.32", + "@vitejs/plugin-vue": "^6.0.0", + "@vitejs/plugin-vue-jsx": "^5.0.0", + "@vitest/eslint-plugin": "^1.2.7", + "@vue/eslint-config-typescript": "^14.5.1", + "@vue/test-utils": "^2.4.6", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.29.0", + "eslint-plugin-playwright": "^2.2.0", + "eslint-plugin-vue": "~10.2.0", + "jiti": "^2.4.2", + "jsdom": "^26.1.0", + "npm-run-all2": "^8.0.4", + "typescript": "~5.8.0", + "vite": "^7.0.0", + "vite-plugin-vue-devtools": "^7.7.7", + "vitest": "^3.2.4", + "vue-tsc": "^2.2.10" + } +} diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts new file mode 100644 index 0000000..5ece956 --- /dev/null +++ b/src/frontend/playwright.config.ts @@ -0,0 +1,110 @@ +import process from 'node:process' +import { defineConfig, devices } from '@playwright/test' + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './e2e', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: process.env.CI ? 'http://localhost:4173' : 'http://localhost:5173', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + + /* Only on CI systems run the tests headless */ + headless: !!process.env.CI, + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'], + }, + }, + { + name: 'webkit', + use: { + ...devices['Desktop Safari'], + }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + webServer: { + /** + * Use the dev server by default for faster feedback loop. + * Use the preview server on CI for more realistic testing. + * Playwright will re-use the local server if there is already a dev-server running. + */ + command: process.env.CI ? 'npm run preview' : 'npm run dev', + port: process.env.CI ? 4173 : 5173, + reuseExistingServer: !process.env.CI, + }, +}) diff --git a/src/frontend/public/favicon.ico b/src/frontend/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/src/frontend/public/favicon.ico differ diff --git a/src/frontend/src/App.vue b/src/frontend/src/App.vue new file mode 100644 index 0000000..d05208d --- /dev/null +++ b/src/frontend/src/App.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/frontend/src/assets/base.css b/src/frontend/src/assets/base.css new file mode 100644 index 0000000..8816868 --- /dev/null +++ b/src/frontend/src/assets/base.css @@ -0,0 +1,86 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-indigo); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-white); + --color-background-soft: var(--vt-c-white-soft); + --color-background-mute: var(--vt-c-white-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/src/frontend/src/assets/logo.svg b/src/frontend/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/frontend/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/src/frontend/src/assets/main.css b/src/frontend/src/assets/main.css new file mode 100644 index 0000000..36fb845 --- /dev/null +++ b/src/frontend/src/assets/main.css @@ -0,0 +1,35 @@ +@import './base.css'; + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; + padding: 3px; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} diff --git a/src/frontend/src/components/HelloWorld.vue b/src/frontend/src/components/HelloWorld.vue new file mode 100644 index 0000000..a2eabd1 --- /dev/null +++ b/src/frontend/src/components/HelloWorld.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/frontend/src/components/TheWelcome.vue b/src/frontend/src/components/TheWelcome.vue new file mode 100644 index 0000000..6092dff --- /dev/null +++ b/src/frontend/src/components/TheWelcome.vue @@ -0,0 +1,94 @@ + + + diff --git a/src/frontend/src/components/WelcomeItem.vue b/src/frontend/src/components/WelcomeItem.vue new file mode 100644 index 0000000..6d7086a --- /dev/null +++ b/src/frontend/src/components/WelcomeItem.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/frontend/src/components/__tests__/HelloWorld.spec.ts b/src/frontend/src/components/__tests__/HelloWorld.spec.ts new file mode 100644 index 0000000..2533202 --- /dev/null +++ b/src/frontend/src/components/__tests__/HelloWorld.spec.ts @@ -0,0 +1,11 @@ +import { describe, it, expect } from 'vitest' + +import { mount } from '@vue/test-utils' +import HelloWorld from '../HelloWorld.vue' + +describe('HelloWorld', () => { + it('renders properly', () => { + const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } }) + expect(wrapper.text()).toContain('Hello Vitest') + }) +}) diff --git a/src/frontend/src/components/icons/IconCommunity.vue b/src/frontend/src/components/icons/IconCommunity.vue new file mode 100644 index 0000000..2dc8b05 --- /dev/null +++ b/src/frontend/src/components/icons/IconCommunity.vue @@ -0,0 +1,7 @@ + diff --git a/src/frontend/src/components/icons/IconDocumentation.vue b/src/frontend/src/components/icons/IconDocumentation.vue new file mode 100644 index 0000000..6d4791c --- /dev/null +++ b/src/frontend/src/components/icons/IconDocumentation.vue @@ -0,0 +1,7 @@ + diff --git a/src/frontend/src/components/icons/IconEcosystem.vue b/src/frontend/src/components/icons/IconEcosystem.vue new file mode 100644 index 0000000..c3a4f07 --- /dev/null +++ b/src/frontend/src/components/icons/IconEcosystem.vue @@ -0,0 +1,7 @@ + diff --git a/src/frontend/src/components/icons/IconSupport.vue b/src/frontend/src/components/icons/IconSupport.vue new file mode 100644 index 0000000..7452834 --- /dev/null +++ b/src/frontend/src/components/icons/IconSupport.vue @@ -0,0 +1,7 @@ + diff --git a/src/frontend/src/components/icons/IconTooling.vue b/src/frontend/src/components/icons/IconTooling.vue new file mode 100644 index 0000000..660598d --- /dev/null +++ b/src/frontend/src/components/icons/IconTooling.vue @@ -0,0 +1,19 @@ + + diff --git a/src/frontend/src/main.ts b/src/frontend/src/main.ts new file mode 100644 index 0000000..0ac3a5f --- /dev/null +++ b/src/frontend/src/main.ts @@ -0,0 +1,6 @@ +import './assets/main.css' + +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/src/frontend/tsconfig.app.json b/src/frontend/tsconfig.app.json new file mode 100644 index 0000000..913b8f2 --- /dev/null +++ b/src/frontend/tsconfig.app.json @@ -0,0 +1,12 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/src/frontend/tsconfig.json b/src/frontend/tsconfig.json new file mode 100644 index 0000000..100cf6a --- /dev/null +++ b/src/frontend/tsconfig.json @@ -0,0 +1,14 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.vitest.json" + } + ] +} diff --git a/src/frontend/tsconfig.node.json b/src/frontend/tsconfig.node.json new file mode 100644 index 0000000..a83dfc9 --- /dev/null +++ b/src/frontend/tsconfig.node.json @@ -0,0 +1,19 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "nightwatch.conf.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + "noEmit": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + + "module": "ESNext", + "moduleResolution": "Bundler", + "types": ["node"] + } +} diff --git a/src/frontend/tsconfig.vitest.json b/src/frontend/tsconfig.vitest.json new file mode 100644 index 0000000..7d1d8ce --- /dev/null +++ b/src/frontend/tsconfig.vitest.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.app.json", + "include": ["src/**/__tests__/*", "env.d.ts"], + "exclude": [], + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo", + + "lib": [], + "types": ["node", "jsdom"] + } +} diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts new file mode 100644 index 0000000..d49d708 --- /dev/null +++ b/src/frontend/vite.config.ts @@ -0,0 +1,20 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + }, + }, +}) diff --git a/src/frontend/vitest.config.ts b/src/frontend/vitest.config.ts new file mode 100644 index 0000000..c328717 --- /dev/null +++ b/src/frontend/vitest.config.ts @@ -0,0 +1,14 @@ +import { fileURLToPath } from 'node:url' +import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' +import viteConfig from './vite.config' + +export default mergeConfig( + viteConfig, + defineConfig({ + test: { + environment: 'jsdom', + exclude: [...configDefaults.exclude, 'e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)), + }, + }), +)