diff --git a/.env.example b/.env.example deleted file mode 100644 index f21daf3..0000000 --- a/.env.example +++ /dev/null @@ -1,5 +0,0 @@ -# API base URL for the backend that wraps the abra CLI -VITE_API_URL=http://localhost:3000/api - -# Set to 'true' to use mock data -VITE_MOCK_AUTH=true \ No newline at end of file diff --git a/README.md b/README.md index 1978622..de431f2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,52 @@ -# Coop Cloud Front +# Coop Cloud Front -This is the frontend of a web wrapper for Coop Clouds abra CLI, letting users set up and manage VPSs and docker images through a web UI. +Frontend for Coop Cloud — a web UI wrapper around the `abra` CLI for +managing VPSs, containers and application deployments. -## Still a work in progess! +This repository contains a Vite + React + TypeScript app styled +with SCSS. -## This is built with react, typescript, scss, and vite \ No newline at end of file +## Quick start + +- Install dependencies (pnpm is recommended): + +pnpm install +pnpm dev + +``` + +The app uses Vite; start the dev server with `pnpm dev`. + +## Environment + +- The app reads runtime flags from Vite env variables. The default build uses mocked api data. +-To deploy on a real API without mocking, run: +pnpm start:prod + +Modify `.env` file at the project root if you need to override values for +development (see Vite docs for env var conventions). + +## Scripts + +- `pnpm dev` — start dev server +- `pnpm build` — run TypeScript and build production assets +- `pnpm preview` — preview production build locally +- `pnpm lint` — run ESLint +- `pnpm lint:scss` — run Stylelint +- `pnpm format` — format with Prettier + +## Notes about local development + +- The repo contains mock JSON and a `mockApi` service to develop UI without + a backend. Toggle mock mode with `VITE_MOCK_AUTH=true`. +- Routes are client-side using `react-router-dom`. + +## Next steps / suggested work items + +- Add form validation and better UX for `RecipeForm`. +- Improve accessibility. +- Add unit tests. +- Improve responsive layouts and card grid behaviour on narrow screens. +- Add deployment docs and production environment variables. + +--- \ No newline at end of file diff --git a/package.json b/package.json index 242d961..8a6d0ec 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "start": "vite", "dev": "vite", + "start:prod": "VITE_MOCK_AUTH=false pnpm start", "build": "tsc && vite build", "preview": "vite preview", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", diff --git a/src/routes/Apps/App.tsx b/src/routes/Apps/App.tsx index c67cbf8..424df52 100644 --- a/src/routes/Apps/App.tsx +++ b/src/routes/Apps/App.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { useParams, useNavigate, Link } from 'react-router-dom'; +import { Link, useNavigate, useParams } from 'react-router-dom'; import { Header } from '../../components/Header/Header'; import { Terminal } from '../../components/Terminal/Terminal'; import { apiService } from '../../services/api'; diff --git a/src/routes/Recipes/RecipeForm.scss b/src/routes/Recipes/RecipeForm.scss index e69de29..a22ea0a 100644 --- a/src/routes/Recipes/RecipeForm.scss +++ b/src/routes/Recipes/RecipeForm.scss @@ -0,0 +1,100 @@ +@use '../../assets/scss/variables' as *; +@use '../../assets/scss/mixins' as *; +@use '../../assets/scss/global' as *; + +.recipe-form { + @include card; + max-width: 680px; + margin: 0 auto; + display: flex; + flex-direction: column; + gap: $spacing-lg; + padding: $spacing-lg; + + h2 { + margin: 0; + font-size: $font-size-xl; + color: $text-primary; + } + + .field { + display: flex; + flex-direction: column; + gap: $spacing-xs; + + &.field-inline { + flex-direction: row; + align-items: center; + gap: $spacing-md; + } + + label { + color: $text-secondary; + font-size: $font-size-sm; + display: flex; + flex-direction: column; + gap: $spacing-xs; + + input[type="text"], + input[type="email"], + input:not([type]), + select { + padding: $spacing-sm $spacing-md; + border: 2px solid $border-color; + border-radius: $radius-md; + font-size: $font-size-base; + background: $bg-primary; + color: $text-primary; + transition: border-color $transition-base, box-shadow $transition-base; + } + + input:focus, + select:focus { + outline: none; + border-color: $primary; + box-shadow: 0 0 0 4px rgba($primary, 0.06); + } + } + + .checkbox-label { + display: inline-flex; + align-items: center; + gap: $spacing-sm; + font-size: $font-size-base; + color: $text-primary; + + input[type="checkbox"] { + width: 18px; + height: 18px; + } + } + } + + .form-actions { + display: flex; + gap: $spacing-sm; + justify-content: flex-end; + + .action-btn { + @include action-btn(2px, $radius-md, $spacing-sm $spacing-lg, $font-size-sm); + } + } +} + +.form-subtitle { + margin: 0; + color: $text-secondary; + font-size: $font-size-sm; +} + +.form-error { + background: rgba($error, 0.08); + color: $error; + padding: $spacing-sm $spacing-md; + border-radius: $radius-sm; +} + +.select-input { + width: 100%; +} + diff --git a/src/routes/Recipes/RecipeForm.tsx b/src/routes/Recipes/RecipeForm.tsx index dc3c7f9..61be1ab 100644 --- a/src/routes/Recipes/RecipeForm.tsx +++ b/src/routes/Recipes/RecipeForm.tsx @@ -1,6 +1,7 @@ -import { useState, useEffect } from "react"; +import { useEffect, useState } from "react"; import { apiService } from '../../services/api'; import type { AbraServer } from '../../types'; +import './RecipeForm.scss'; @@ -50,14 +51,19 @@ function RecipeForm({ recipe, onClose }) { }; return ( -
+

{recipe.name}

- { loading ? (

Loading servers...

+

Configure and deploy this recipe.

+ {error &&
{error}
} + + { loading ? ( +

Loading servers...

) : ( -
- +
)} -
+ +
-
-