Split code into frontend/backend maybe?

This commit is contained in:
William Brawner 2023-12-08 22:57:40 -07:00
parent ae3eef0622
commit 2a183497b3
Signed by: wbrawner
GPG key ID: 8FF12381C6C90D35
68 changed files with 8129 additions and 36 deletions

25
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,25 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/java/.devcontainer/base.Dockerfile
# [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 11, 17, 11-bullseye, 17-bullseye, 11-buster, 17-buster
ARG VARIANT="17-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
# [Option] Install Maven
ARG INSTALL_MAVEN="false"
ARG MAVEN_VERSION=""
# [Option] Install Gradle
ARG INSTALL_GRADLE="false"
ARG GRADLE_VERSION=""
RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
&& if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
# [Choice] Node.js version: none, lts/*, 16, 14, 12, 10
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

View file

@ -0,0 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/java
{
"name": "Recipes",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Set *default* container specific settings.json values on container create.
"settings": {
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"vscjava.vscode-java-pack",
"PWABuilder.pwa-studio"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [8080],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "java -version",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"workspaceFolder": "/workspace"
}

View file

@ -0,0 +1,24 @@
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
VARIANT: 17-bullseye
NODE_VERSION: "lts/*"
environment:
RECIPES_DB_HOST: 'db'
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"
network_mode: service:db
user: vscode
db:
image: mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: recipes
MONGO_INITDB_ROOT_PASSWORD: recipes

1
backend/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
src/main/resources/static

36
backend/build.gradle Normal file
View file

@ -0,0 +1,36 @@
plugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.wbrawner'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.session:spring-session-core'
compileOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
task copyPublicResources(type: Copy) {
from '../frontend/dist'
into 'src/main/resources/static'
}
copyPublicResources.dependsOn(':frontend:build')
processResources.dependsOn(copyPublicResources)

View file

@ -1,4 +1,4 @@
spring.data.mongodb.host=localhost
spring.data.mongodb.host=${RECIPES_DB_HOST:localhost}
spring.data.mongodb.database=recipes
spring.data.mongodb.password=recipes
spring.data.mongodb.username=recipes

View file

@ -1,29 +1,9 @@
plugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
buildscript {
}
group = 'com.wbrawner'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
allprojects {
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springframework.session:spring-session-core'
compileOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
testImplementation 'io.projectreactor:reactor-test'
testImplementation 'org.springframework.security:spring-security-test'
}
tasks.named('test') {
useJUnitPlatform()
}
}

View file

@ -1,9 +0,0 @@
version: '3.8'
services:
db:
image: mongo
ports:
- "27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: recipes
MONGO_INITDB_ROOT_PASSWORD: recipes

8
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.DS_Store
node_modules
dist
dev-dist
build
types
.idea
.github

13
frontend/LICENSE.txt Normal file
View file

@ -0,0 +1,13 @@
ManifoldJS
Copyright (c) Microsoft Corporation
All rights reserved.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

37
frontend/README.md Normal file
View file

@ -0,0 +1,37 @@
# pwa-starter
Please use our [main repository for any issues/bugs/features suggestion](https://github.com/pwa-builder/PWABuilder/issues/new/choose).
[Documentation](https://docs.pwabuilder.com/#/starter/quick-start)
The PWABuilder pwa-starter is our opinionated, best practices, production tested starter that we use to build all of our PWAs, including [PWABuilder itself](https://blog.pwabuilder.com/posts/introducing-the-brand-new-pwa-builder/)! The pwa-starter is a starter codebase, just like create-react-app or the Angular CLI can generate, that uses the PWABuilder team&#39;s preferred front-end tech stack.
[![Get started with the pwa-starter!](https://img.youtube.com/vi/u3pWKpmic_k/0.jpg)](https://www.youtube.com/watch?v=u3pWKpmic_k)
With it you get an app that:
- Has no build system to set up and no boilerplate code to add. Everything is included out of the box.
- Has a Service Worker system using [Workbox](https://developers.google.com/web/tools/workbox/)
- Scores close to 100 on Lighthouse out of the box
- Has everything needed to be installable in the browser
- Is ready to be package for the app stores using [PWABuilder](https://www.pwabuilder.com)
- Uses the [Azure Static Web Apps CLI](https://azure.github.io/static-web-apps-cli) which enables emulating your production environment locally, and gets you ready for deploying to Azure Static Web Apps!
and all with just a few button clicks 😊.
[Get Started!](https://docs.pwabuilder.com/#/starter/quick-start)
## Sample PWAs built with the starter!
- SimpleEdit: Simple Image editing and collage making app!
- Github: https://github.com/jgw96/simple-edit-2
- Web: https://gray-pond-01ccec410.azurestaticapps.net/
- Microsoft Store: https://www.microsoft.com/store/productId/9P53Q9BF3MV6
- Google Play: https://play.google.com/store/apps/details?id=net.azurestaticapps.thankful_tree_07da4921e.twa&hl=en&gl=US
- Mail GO: Full featured email client. This app aims to show the power of the web by integrating many of the advanced APIs now avilable to PWAs, such as [receiving content shared from another app](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/share#receiving-shared-content), [a custom titlebar](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay), [sycing data in the background](https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/background-syncs) and more!
- Github: https://github.com/jgw96/graph-app
- Web: https://www.memosapp.app
- Microsoft Store: https://www.microsoft.com/store/productId/9NQW566N4866
## More Resources
- [The pwa-starter docs](https://docs.pwabuilder.com/#/starter/quick-start)

21
frontend/build.gradle Normal file
View file

@ -0,0 +1,21 @@
plugins {
id "com.github.node-gradle.node" version "3.5.0"
}
repositories {
mavenCentral()
}
task build(type: NpmTask) {
args = ['run', 'build']
inputs.files(fileTree('node_modules'))
inputs.files(fileTree('public'))
inputs.files(fileTree('src'))
inputs.file('package.json')
inputs.file('vite.config.ts')
outputs.dir('dist')
dependsOn npm_install
args = ['run', 'build']
}
// build.dependsOn(npmBuild)

52
frontend/index.html Normal file
View file

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>PWA Starter</title>
<base href="/" />
<!-- This meta viewport ensures the webpage's dimensions change according to the device it's on. This is called Responsive Web Design.-->
<meta name="viewport"
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
<meta name="description" content="This is a PWA Starter app" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#181818" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f3f3f3" />
<!-- These meta tags are Apple-specific, and set the web application to run in full-screen mode with a black status bar. Learn more at https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html-->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="PWA Starter" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<!-- Imports an icon to represent the document. -->
<link rel="icon" href="/assets/icons/icon_24.png" type="image/x-icon" />
<!-- Imports the manifest to represent the web application. A web app must have a manifest to be a PWA. -->
<link rel="manifest" href="/manifest.json" />
<!-- light mode and dark mode CSS -->
<link rel="stylesheet" media="(prefers-color-scheme:light)"
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.73/dist/themes/light.css">
<link rel="stylesheet" media="(prefers-color-scheme:dark)"
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.73/dist/themes/dark.css"
onload="document.documentElement.classList.add('sl-theme-dark');">
<script type="module" src="/src/app-index.ts"></script>
</head>
<body>
<!-- Our app-index web component. This component is defined in src/pages/app-index.ts-->
<app-index></app-index>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(
'/sw.js'
);
}
</script>
</body>
</html>

7274
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

41
frontend/package.json Normal file
View file

@ -0,0 +1,41 @@
{
"name": "pwa-starter",
"version": "0.0.1",
"description": "A starter kit for building PWAs!",
"main": "index.js",
"scripts": {
"dev-server": "vite --open",
"dev": "npm run dev-server",
"dev-task": "vite",
"deploy": " npx @azure/static-web-apps-cli login --no-use-keychain && npx @azure/static-web-apps-cli deploy",
"build": "tsc && vite build",
"start": "npm run dev",
"start-remote": "vite --host"
},
"author": "",
"license": "ISC",
"dependencies": {
"@pwabuilder/pwainstall": "^1.6.7",
"@shoelace-style/shoelace": "^2.0.0-beta.82",
"@vaadin/router": "^1.7.4",
"lit": "^2.3.1",
"workbox-build": "^6.5.2",
"workbox-core": "^6.5.2",
"workbox-precaching": "^6.5.2"
},
"devDependencies": {
"typescript": "^4.6.3",
"vite": "^2.9.0",
"vite-plugin-pwa": "^0.11.13"
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "consistent",
"trailingComma": "es5",
"endOfLine": "crlf",
"bracketSpacing": true
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -0,0 +1,61 @@
{
"id": "/",
"scope": "/",
"name": "PWA Starter",
"display": "standalone",
"start_url": "/",
"short_name": "starter",
"theme_color": "#E1477E",
"description": "This is a PWA Starter app",
"orientation": "any",
"background_color": "#E1477E",
"related_applications": [],
"prefer_related_applications": false,
"display_override": ["window-controls-overlay"],
"icons": [
{
"src": "assets/icons/icon_512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "assets/icons/icon_192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/icons/icon_48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "assets/icons/icon_24.png",
"sizes": "24x24",
"type": "image/png"
}
],
"screenshots": [
{
"src": "assets/screenshots/screen.png",
"sizes": "1617x1012",
"type": "image/png"
}
],
"features": [
"Cross Platform",
"fast",
"simple"
],
"categories": [
"utility"
],
"shortcuts": [
{
"name": "Open About",
"short_name": "About",
"description": "Open the about page",
"url": "/about",
"icons": [{ "src": "assets/icons/icon_192.png", "sizes": "192x192" }]
}
]
}

8
frontend/public/sw.js Normal file
View file

@ -0,0 +1,8 @@
importScripts(
'https://storage.googleapis.com/workbox-cdn/releases/6.5.4/workbox-sw.js'
);
// This is your Service Worker, you can put any of your custom Service Worker
// code in this file, above the `precacheAndRoute` line.
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST || []);

91
frontend/src/app-index.ts Normal file
View file

@ -0,0 +1,91 @@
import { LitElement, css, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { Router } from '@vaadin/router';
import './pages/app-home';
import './components/header';
import './styles/global.css';
@customElement('app-index')
export class AppIndex extends LitElement {
static get styles() {
return css`
main {
padding-left: 16px;
padding-right: 16px;
padding-bottom: 16px;
}
#routerOutlet > * {
width: 100% !important;
}
#routerOutlet > .leaving {
animation: 160ms fadeOut ease-in-out;
}
#routerOutlet > .entering {
animation: 160ms fadeIn linear;
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fadeIn {
from {
opacity: 0.2;
}
to {
opacity: 1;
}
}
`;
}
constructor() {
super();
}
firstUpdated() {
// this method is a lifecycle even in lit
// for more info check out the lit docs https://lit.dev/docs/components/lifecycle/
// For more info on using the @vaadin/router check here https://vaadin.com/router
const router = new Router(this.shadowRoot?.querySelector('#routerOutlet'));
router.setRoutes([
// temporarily cast to any because of a Type bug with the router
{
path: (import.meta as any).env.BASE_URL,
animate: true,
children: [
{ path: '', component: 'app-home' },
{
path: 'about',
component: 'app-about',
action: async () => {
await import('./pages/app-about/app-about.js');
},
}
],
} as any,
]);
}
render() {
return html`
<div>
<main>
<div id="routerOutlet"></div>
</main>
</div>
`;
}
}

View file

@ -0,0 +1,79 @@
import { LitElement, css, html } from 'lit';
import { property, customElement } from 'lit/decorators.js';
import '@shoelace-style/shoelace/dist/components/button/button.js';
@customElement('app-header')
export class AppHeader extends LitElement {
@property({ type: String }) title = 'PWA Starter';
@property({ type: Boolean}) enableBack: boolean = false;
static get styles() {
return css`
header {
display: flex;
justify-content: space-between;
align-items: center;
background: var(--app-color-primary);
color: white;
height: 4em;
padding-left: 16px;
padding-top: 12px;
position: fixed;
left: env(titlebar-area-x, 0);
top: env(titlebar-area-y, 0);
height: env(titlebar-area-height, 50px);
width: env(titlebar-area-width, 100%);
-webkit-app-region: drag;
}
header h1 {
margin-top: 0;
margin-bottom: 0;
font-size: 20px;
font-weight: bold;
}
nav a {
margin-left: 10px;
}
#back-button-block {
display: flex;
justify-content: space-between;
align-items: center;
width: 12em;
}
@media(prefers-color-scheme: light) {
header {
color: black;
}
nav a {
color: initial;
}
}
`;
}
constructor() {
super();
}
render() {
return html`
<header>
<div id="back-button-block">
${this.enableBack ? html`<sl-button href="${(import.meta as any).env.BASE_URL}">
Back
</sl-button>` : null}
<h1>${this.title}</h1>
</div>
</header>
`;
}
}

View file

@ -0,0 +1,11 @@
import { css } from 'lit';
// these styles can be imported from any component
// for an example of how to use this, check /pages/about-about.ts
export const styles = css`
@media(min-width: 1000px) {
sl-card {
max-width: 70vw;
}
}
`;

View file

@ -0,0 +1,45 @@
import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
// You can also import styles from another file
// if you prefer to keep your CSS seperate from your component
import { styles } from './about-styles';
import { styles as sharedStyles } from '../../styles/shared-styles'
import '@shoelace-style/shoelace/dist/components/card/card.js';
@customElement('app-about')
export class AppAbout extends LitElement {
static styles = [
sharedStyles,
styles
]
constructor() {
super();
}
render() {
return html`
<app-header ?enableBack="${true}"></app-header>
<main>
<h2>About Page</h2>
<sl-card>
<h2>Did you know?</h2>
<p>PWAs have access to many useful APIs in modern browsers! These
APIs have enabled many new types of apps that can be built as PWAs, such as advanced graphics editing apps, games,
apps that use machine learning and more!
</p>
<p>Check out <a
href="https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/handle-files">these
docs</a> to learn more about the advanced features that you can use in your PWA</p>
</sl-card>
</main>
`;
}
}

View file

@ -0,0 +1,149 @@
import { LitElement, css, html } from 'lit';
import { property, customElement } from 'lit/decorators.js';
// For more info on the @pwabuilder/pwainstall component click here https://github.com/pwa-builder/pwa-install
import '@pwabuilder/pwainstall';
import '@shoelace-style/shoelace/dist/components/card/card.js';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import { styles } from '../styles/shared-styles';
@customElement('app-home')
export class AppHome extends LitElement {
// For more information on using properties and state in lit
// check out this link https://lit.dev/docs/components/properties/
@property() message = 'Welcome!';
static get styles() {
return [
styles,
css`
#welcomeBar {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
#welcomeCard,
#infoCard {
padding: 18px;
padding-top: 0px;
}
pwa-install {
position: absolute;
bottom: 16px;
right: 16px;
}
sl-card::part(footer) {
display: flex;
justify-content: flex-end;
}
@media(min-width: 750px) {
sl-card {
width: 70vw;
}
}
@media (horizontal-viewport-segments: 2) {
#welcomeBar {
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
}
#welcomeCard {
margin-right: 64px;
}
}
`];
}
constructor() {
super();
}
async firstUpdated() {
// this method is a lifecycle even in lit
// for more info check out the lit docs https://lit.dev/docs/components/lifecycle/
console.log('This is your home page');
}
share() {
if ((navigator as any).share) {
(navigator as any).share({
title: 'PWABuilder pwa-starter',
text: 'Check out the PWABuilder pwa-starter!',
url: 'https://github.com/pwa-builder/pwa-starter',
});
}
}
render() {
return html`
<app-header></app-header>
<main>
<div id="welcomeBar">
<sl-card id="welcomeCard">
<div slot="header">
<h2>${this.message}</h2>
</div>
<p>
For more information on the PWABuilder pwa-starter, check out the
<a href="https://github.com/pwa-builder/pwa-starter/wiki/Getting-Started">
Documentation on Github</a>.
</p>
<p id="mainInfo">
Welcome to the
<a href="https://pwabuilder.com">PWABuilder</a>
pwa-starter! Be sure to head back to
<a href="https://pwabuilder.com">PWABuilder</a>
when you are ready to ship this PWA to the Microsoft Store, Google Play
and the Apple App Store!
</p>
${'share' in navigator
? html`<sl-button slot="footer" variant="primary" @click="${this.share}">Share this Starter!</sl-button>`
: null}
</sl-card>
<sl-card id="infoCard">
<h2>Technology Used</h2>
<ul>
<li>
<a href="https://www.typescriptlang.org/">TypeScript</a>
</li>
<li>
<a href="https://lit.dev">lit</a>
</li>
<li>
<a href="https://shoelace.style/">Shoelace</a>
</li>
<li>
<a href="https://vaadin.github.io/vaadin-router/vaadin-router/demo/#vaadin-router-getting-started-demos"
>Vaadin Router</a>
</li>
</ul>
</sl-card>
<sl-button href="${(import.meta as any).env.BASE_URL}about" variant="primary">Navigate to About</sl-button>
</div>
<pwa-install>Install PWA Starter</pwa-install>
</main>
`;
}
}

View file

@ -0,0 +1,32 @@
/*
This file is used for all of your global styles and CSS variables.
Check here https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties for more info on using CSS variables.
*/
:root {
--font-family: sans-serif;
}
html, body {
font-family: var(--font-family);
padding: 0;
margin: 0;
}
@media (prefers-color-scheme: dark) {
html,
body {
background-color: #181818;
color: white;
}
}
@media (prefers-color-scheme: light) {
html,
body {
background-color: white;
color: black;
}
}

View file

@ -0,0 +1,15 @@
import { css } from 'lit';
// these styles can be imported from any component
// for an example of how to use this, check /pages/about-about.ts
export const styles = css`
@media(min-width: 1000px) {
sl-card {
max-width: 70vw;
}
}
main {
margin-top: 80px;
}
`;

View file

@ -0,0 +1,12 @@
{
"$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
"configurations": {
"pwa-starter": {
"appLocation": ".",
"outputLocation": "dist",
"appBuildCommand": "npm run build --if-present",
"run": "npm start",
"appDevserverUrl": "http://localhost:3000"
}
}
}

26
frontend/tsconfig.json Normal file
View file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"module": "esnext",
"target": "esnext",
"lib": ["es2017", "esnext", "dom", "dom.iterable"],
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "./types",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"useDefineForClassFields": false,
"isolatedModules": true,
"types": [
"vite-plugin-pwa/client"
]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}

27
frontend/vite.config.ts Normal file
View file

@ -0,0 +1,27 @@
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
// https://vitejs.dev/config/
export default defineConfig({
base: "/",
build: {
sourcemap: true,
assetsDir: "code",
},
plugins: [
VitePWA({
strategies: "injectManifest",
injectManifest: {
swSrc: 'public/sw.js',
swDest: 'dist/sw.js',
globDirectory: 'dist',
globPatterns: [
'**/*.{html,js,css,json, png}',
],
},
devOptions: {
enabled: true
}
})
]
})

0
gradlew vendored Normal file → Executable file
View file

View file

@ -1 +1,3 @@
rootProject.name = 'recipes'
include 'backend'
include 'frontend'