Merge pull request #11 from aldy505/client/docs

Updating docs on client web
This commit is contained in:
Reinaldy Rafli 2022-10-01 18:45:39 +07:00 committed by GitHub
commit 58605e6af3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 8098 additions and 2706 deletions

View File

@ -93,17 +93,17 @@ jobs:
uses: actions/checkout@v2
- name: Installling dependencies
run: yarn install
run: npm install
- name: Lint
run: yarn lint
run: npm run lint
- name: Build
run: yarn build
run: npm run build
env:
VITE_SENTRY_DSN: https://examplePublicKey@o0.ingest.sentry.io/0
VITE_NODE_ENV: development
VITE_API_ENDPOINT: https://jokesbapak2.herokuapp.com/v1
VITE_API_ENDPOINT: https://jokesbapak2.reinaldyrafli.com/api/v1
- name: Initialize CodeQL
uses: github/codeql-action/init@v1

View File

@ -19,7 +19,7 @@ jobs:
uses: actions/checkout@v2
- name: Installling dependencies
run: yarn install
run: npm install
- name: Lint
run: npx eslint --ext .svelte,.js,.ts --ignore-path .gitignore .
@ -28,11 +28,11 @@ jobs:
run: npx prettier --check --ignore-path .gitignore --plugin-search-dir=. "./**/*.(ts|json|js|svelte)"
- name: Build
run: yarn build
run: npm run build
env:
VITE_SENTRY_DSN: https://examplePublicKey@o0.ingest.sentry.io/0
VITE_NODE_ENV: development
VITE_API_ENDPOINT: https://jokesbapak2.herokuapp.com/v1
VITE_API_ENDPOINT: https://jokesbapak2.reinaldyrafli.com/api/v1
- name: Initialize CodeQL
uses: github/codeql-action/init@v1

12
.gitignore vendored
View File

@ -1,5 +1,5 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,goland,webstorm,datagrip
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,goland,webstorm,datagrip
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,goland,webstorm
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,goland,webstorm
### GoLand ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
@ -214,6 +214,10 @@ fabric.properties
# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,goland,webstorm,datagrip
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,goland,webstorm
data
docker-compose.override.yml
data/
.env.*
.env
!.env.example

View File

@ -7,9 +7,9 @@
<br>
</h1>
👋 Hey there! Still a work in progress, if you'd like to contribute this while this repo is still growing, that would be so great!
👋 Hey there! Always a work in progress, if you'd like to contribute this while this repo is still growing, that would be so great!
It's on alpha phase now. You can access the front facing web on [jokesbapak2.pages.dev](http://jokesbapak2.pages.dev/).
ou can access the front facing web on [jokesbapak2.reinaldyrafli.com](http://jokesbapak2.reinaldyrafli.com/).
## Brief explanation of what is this

View File

@ -1,7 +1,11 @@
ENV=development
PORT=5000
HOSTNAME=127.0.0.1
DATABASE_URL=postgres://postgres:password@localhost:5432/jokesbapak2
REDIS_URL=redis://@localhost:6379
MINIO_HOST=
MINIO_ACCESS_ID=
MINIO_SECRET_KEY=
MINIO_TOKEN=
SENTRY_DSN=

View File

@ -10,6 +10,10 @@ FROM debian:bullseye AS runtime
WORKDIR /app
RUN apt-get update && apt-get upgrade --no-install-recommends -y \
&& apt-get install -y --no-install-recommends curl \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/main .
ENV PORT=5000

View File

@ -16,11 +16,11 @@
},
"servers": [
{
"url": "https://jokesbapak2.herokuapp.com/v1",
"url": "https://jokesbapak2.reinaldyrafli.com/api/v1",
"description": "Production"
},
{
"url": "https://jokesbapak2.herokuapp.com",
"url": "https://jokesbapak2.reinaldyrafli.com/api",
"description": "Production"
},
{

View File

@ -14,9 +14,9 @@ info:
name: GNU General Public License v3.0
url: https://github.com/aldy505/jokes-bapak2/blob/master/LICENSE
servers:
- url: "https://jokesbapak2.herokuapp.com/v1"
- url: "https://jokesbapak2.reinaldyrafli.com/api/v1"
description: Production
- url: "https://jokesbapak2.herokuapp.com"
- url: "https://jokesbapak2.reinaldyrafli.com/api"
description: Production
- url: "http://localhost:5000"
description: Development
@ -31,9 +31,9 @@ paths:
200:
description: Image data
content:
'image/gif': {}
'image/png': {}
'image/jpeg': {}
"image/gif": {}
"image/png": {}
"image/jpeg": {}
put:
summary: Add a new joke into database
description: asd
@ -46,15 +46,15 @@ paths:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/request.auth'
- $ref: '#/components/schemas/request.joke'
- $ref: "#/components/schemas/request.auth"
- $ref: "#/components/schemas/request.joke"
responses:
201:
description: Image has been added
content:
application/json:
schema:
$ref: '#/components/schemas/request.joke'
$ref: "#/components/schemas/request.joke"
example:
link: https://link.to/image.jpg
400:
@ -62,7 +62,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
example:
error: URL provided is not a valid image
403:
@ -70,7 +70,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
/id/{id}:
parameters:
- in: path
@ -88,17 +88,16 @@ paths:
200:
description: Image data
content:
'image/jpeg': {}
'image/png': {}
'image/gif': {}
"image/jpeg": {}
"image/png": {}
"image/gif": {}
404:
description: Provided image ID was not found
content:
text/plain:
schema:
type: string
example:
Requested ID was not found.
example: Requested ID was not found.
patch:
summary: Update a Joke with certain image ID
description: Returns consistent image for every call.
@ -111,26 +110,26 @@ paths:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/response.confirmation'
- $ref: '#/components/schemas/request.joke'
- $ref: "#/components/schemas/response.confirmation"
- $ref: "#/components/schemas/request.joke"
400:
description: Link provided is not a valid image
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
403:
description: Must be authenticated to submit a joke
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
406:
description: If the Joke ID does not exists
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
delete:
summary: Delete a Joke with certain image ID
description: hi
@ -142,19 +141,19 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/response.confirmation'
$ref: "#/components/schemas/response.confirmation"
403:
description: Must be authenticated to submit a joke
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
406:
description: If the Joke ID does not exists
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
/today:
get:
summary: Get the joke of the day
@ -165,9 +164,9 @@ paths:
200:
description: Image data
content:
'image/jpeg': {}
'image/png': {}
'image/gif': {}
"image/jpeg": {}
"image/png": {}
"image/gif": {}
/total:
get:
summary: Get total amount of jokes in database
@ -179,7 +178,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/response.confirmation'
$ref: "#/components/schemas/response.confirmation"
example:
message: "154"
/submit:
@ -223,7 +222,7 @@ paths:
jokes:
type: array
items:
$ref: '#/components/schemas/response.submission'
$ref: "#/components/schemas/response.submission"
post:
summary: Submit a joke
description: >
@ -256,17 +255,17 @@ paths:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/response.confirmation'
- $ref: "#/components/schemas/response.confirmation"
- type: object
properties:
data:
$ref: '#/components/schemas/response.submission'
$ref: "#/components/schemas/response.submission"
400:
description: Invalid data was sent
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
/health:
get:
summary: Health check
@ -281,7 +280,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/response.error'
$ref: "#/components/schemas/response.error"
components:
schemas:

View File

@ -16,6 +16,7 @@ require (
require (
github.com/go-chi/chi/v5 v5.0.7
github.com/minio/minio-go/v7 v7.0.35
github.com/rs/cors v1.8.2
)
require (

View File

@ -238,6 +238,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U=
github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=

View File

@ -3,6 +3,7 @@ package main
import (
"errors"
"log"
"net"
"net/http"
"os"
"os/signal"
@ -20,6 +21,7 @@ import (
"github.com/allegro/bigcache/v3"
"github.com/getsentry/sentry-go"
"github.com/go-chi/chi/v5"
"github.com/rs/cors"
)
func main() {
@ -69,7 +71,7 @@ func main() {
}
// Setup In Memory
memory, err := bigcache.NewBigCache(bigcache.DefaultConfig(6 * time.Hour))
memory, err := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))
if err != nil {
log.Panicln(err)
}
@ -127,12 +129,19 @@ func main() {
router := chi.NewRouter()
router.Use(cors.New(cors.Options{
AllowedMethods: []string{http.MethodGet},
AllowCredentials: false,
MaxAge: int(60 * 60 * 24 * 365),
Debug: false,
}).Handler)
router.Mount("/health", healthRouter)
router.Mount("/", jokeRouter)
server := &http.Server{
Handler: router,
Addr: hostname + ":" + port,
Addr: net.JoinHostPort(hostname, port),
ReadTimeout: time.Minute,
WriteTimeout: time.Minute,
IdleTimeout: time.Second * 30,

View File

@ -14,9 +14,9 @@
"type": "module",
"scripts": {
"start": "yarn run b:random && yarn run b:today && yarn run b:byid",
"b:random": "autocannon --title \"GET /v1/ - Random Jokes\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.herokuapp.com/v1/",
"b:today": "autocannon --title \"GET /v1/today - Today's Jokes\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.herokuapp.com/v1/today",
"b:byid": "autocannon --title \"GET /v1/id/5 - Joke by ID\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.herokuapp.com/v1/id/5"
"b:random": "autocannon --title \"GET /v1/ - Random Jokes\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.reinaldyrafli.com/api/v1/",
"b:today": "autocannon --title \"GET /v1/today - Today's Jokes\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.reinaldyrafli.com/api/v1/today",
"b:byid": "autocannon --title \"GET /v1/id/5 - Joke by ID\" --method GET --amount 100 --bailout 3 --headers user-agent=benchmark https://jokesbapak2.reinaldyrafli.com/api/v1/id/5"
},
"dependencies": {
"autocannon": "^7.4.0"

View File

@ -1 +1 @@
v14.17.3
v16.13

View File

@ -1,14 +1,15 @@
FROM node:14.17.3-buster
FROM node:16.17.0-bullseye
RUN apt-get update && apt-get upgrade --no-install-recommends -y \
&& apt-get install -y --no-install-recommends curl \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . .
RUN npm install -g yarn
RUN yarn install
RUN yarn build
RUN yarn cache clean
RUN npm ci && npm run build && rm -rf node_modules && npm ci --omit=dev
EXPOSE ${PORT}
CMD ["yarn", "preview"]
CMD ["node", "dist/index.js"]

View File

@ -1,35 +1,35 @@
# Jokes Bapak2 Client
Still work in progress
The frontend.
## Development
```bash
# Install modules
$ yarn install
$ npm install
# Run local server
$ yarn dev
$ npm run dev
# build everything
$ yarn build
$ npm run build
```
> You can preview the built app with `yarn preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production.
> You can preview the built app with `npm run preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production.
## Used packages
| Name | Version | Type |
| --- | --- | --- |
| @sveltejs/kit | `1.0.0-next.129` | Framework |
| svelte | `3.38.3` | Framework |
| typescript | `4.3.5` | Static type language |
| svelte-i18n | `3.3.9` | i18n Library |
| svelte-windicss-preprocess | `4.0.12` | CSS Library |
| @fontsource/fira-mono | `4.5.0` | Webfont |
| @fontsource/rubik | `4.5.0` | Webfont |
| dotenv | `10.0.0` | Utils |
| @sentry/browser | `6.9.0` | Logging |
| -------------------------- | ---------------- | -------------------- |
| @sveltejs/kit | `1.0.0-next.480` | Framework |
| svelte | `3.50.1` | Framework |
| typescript | `4.8.3` | Static type language |
| svelte-i18n | `3.4.0` | i18n Library |
| svelte-windicss-preprocess | `4.2.8` | CSS Library |
| @fontsource/fira-mono | `4.5.9` | Webfont |
| @fontsource/rubik | `4.5.11` | Webfont |
| dotenv | `16.0.2` | Utils |
| @sentry/browser | `7.12.1` | Logging |
## Directory structure
@ -48,8 +48,8 @@ $ yarn build
├── static - Static/public directory
├── svelte.config.js - Svelte configuration file
├── tsconfig.json - Typescript configuration file
├── windi.config.js - WindiCSS configuration file
└── yarn.lock - Packages lock file
├── windi.config.ts - WindiCSS configuration file
└── package-lock.json - Packages lock file
```
## `.env` configuration

7418
client/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,38 +11,39 @@
],
"type": "module",
"scripts": {
"dev": "svelte-kit dev",
"build": "svelte-kit build",
"preview": "svelte-kit preview",
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "eslint --fix --ext .svelte,.js,.ts --ignore-path .gitignore .",
"format": "prettier --write --ignore-path .gitignore --plugin-search-dir=. \"./**/*.(ts|json|js|svelte)\""
},
"devDependencies": {
"@sveltejs/adapter-static": "1.0.0-next.13",
"@sveltejs/kit": "1.0.0-next.129",
"@typescript-eslint/eslint-plugin": "4.28.3",
"@typescript-eslint/parser": "4.28.3",
"cssnano": "5.0.6",
"eslint": "7.30.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-svelte3": "3.2.0",
"prettier": "2.3.2",
"prettier-plugin-svelte": "2.3.1",
"svelte": "3.38.3",
"svelte-check": "2.2.2",
"svelte-preprocess": "4.7.4",
"svelte-windicss-preprocess": "4.0.12",
"tslib": "2.3.0",
"typescript": "4.3.5"
"@sveltejs/adapter-node": "^1.0.0-next.89",
"@sveltejs/kit": "1.0.0-next.480",
"@typescript-eslint/eslint-plugin": "5.36.2",
"@typescript-eslint/parser": "5.36.2",
"cssnano": "5.1.13",
"eslint": "8.23.0",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-svelte3": "4.0.0",
"prettier": "2.7.1",
"prettier-plugin-svelte": "2.7.0",
"svelte": "3.50.1",
"svelte-check": "2.9.0",
"svelte-preprocess": "4.10.7",
"svelte-windicss-preprocess": "4.2.8",
"tslib": "2.4.0",
"typescript": "4.8.3",
"vite": "^3.1.0"
},
"dependencies": {
"@fontsource/fira-mono": "4.5.0",
"@fontsource/rubik": "4.5.0",
"@sentry/browser": "6.9.0",
"dotenv": "10.0.0",
"ohmyfetch": "^0.2.0",
"svelte-i18n": "3.3.9"
"@fontsource/fira-mono": "4.5.9",
"@fontsource/rubik": "4.5.11",
"@sentry/browser": "7.12.1",
"dotenv": "16.0.2",
"ohmyfetch": "0.4.18",
"svelte-i18n": "3.4.0"
}
}

View File

@ -1,30 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<html lang="%lang%">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.png" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="keywords" content="jokesbapak2, jokes, bapak2, indonesian, dad, jokes, api, rest" />
<meta name="author" content="Reinaldy Rafli" />
<meta name="theme-color" content="#f4a9f5" />
<meta name="publisher" content="https://jokesbapak2.pages.dev/" />
<meta property="og:image" content="https://jokesbapak2.pages.dev/social.jpg" />
<meta name="publisher" content="https://jokesbapak2.reinaldyrafli.com/" />
<meta property="og:image" content="%sveltekit.assets%/social.jpg" />
<meta property="og:image:alt" content="Jokesbapak2 - Largest collection of Indonesian dad jokes" />
<meta property="og:image:secure_url" content="https://jokesbapak2.pages.dev/social.jpg" />
<meta property="og:image:secure_url" content="%sveltekit.assets%/social.jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:locale" content="en_US" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image:src" content="https://jokesbapak2.pages.dev/social.jpg" />
<meta name="twitter:image" content="https://jokesbapak2.pages.dev/social.jpg" />
<meta name="twitter:image:src" content="%sveltekit.assets%/social.jpg" />
<meta name="twitter:image" content="%sveltekit.assets%/social.jpg" />
<meta name="twitter:creator" content="Reinaldy Rafli" />
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="icon" type="image/svg" href="/favicon.svg">
<script async defer data-website-id="82725fd7-2542-4828-b313-349f68d84894" src="https://jokesbapak2-analytics.herokuapp.com/umami.js" data-do-not-track="true" data-domains="jokesbapak2.pages.dev"></script>
%svelte.head%
%sveltekit.head%
</head>
<body>
<div id="svelte">%svelte.body%</div>
<div id="svelte">%sveltekit.body%</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = ({ event, resolve }) => {
return resolve(event, {
transformPageChunk: ({ html }) => html.replace('%lang%', 'en'),
});
};

View File

@ -71,7 +71,7 @@
}
},
"api": {
"limit": "We limit the request to be 30 request/minute.",
"limit": "We limit the request to be 120 request/minute.",
"get": {
"title": "Get Jokes",
"random": {
@ -105,7 +105,7 @@
"fetch": {
"1": "Using fetch API",
"2": "You can use it, but I personally don't recommend it.",
"3": "data is a base64 string"
"3": "Do some error handling if the request fails"
}
}
}

View File

@ -71,7 +71,7 @@
}
},
"api": {
"limit": "Kami membatasi request menjadi 30 request/menit.",
"limit": "Kami membatasi request menjadi 120 request/menit.",
"get": {
"title": "Dapatkan Jokes",
"random": {
@ -105,7 +105,7 @@
"fetch": {
"1": "Menggunakan fetch API",
"2": "Bapak bisa menggunakannya, tapi saya secara personal tidak merekomendasikannya.",
"3": "data adalah string dengan isi base64"
"3": "Periksa dan jangan abaikan errornya jika request gagal"
}
}
}

View File

@ -42,20 +42,14 @@
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
{$_('footer.language')}
<a href="?lang=en" target="_top" class="hover:underline">{$_('footer.english')}</a>
|
<a href="?lang=id" target="_top" class="hover:underline">{$_('footer.indonesian')}</a>.
</p>
</div>
<div class="flex-initial pr-3">
<p class="text-sm opacity-50 hover:opacity-90 transition duration-300 ease-in-out inline-block">
<a href="https://jokesbapak2-analytics.herokuapp.com/share/1xYuVSyl/Jokes%20Bapak2" class="hover:underline"
>Analytics</a
>.
</p>
</div>
</div>
</footer>
</div>
</div>
<style windi:preflights:global windi:safelist:global>
<style windi:global windi:preflights:global windi:safelist:global>
</style>

View File

@ -0,0 +1,19 @@
import { $fetch } from 'ohmyfetch';
import env from '../lib/env';
interface TotalResponse {
message: number;
}
/** @type {import('./$types').PageServerLoad} */
export async function load() {
const response = await $fetch<TotalResponse>('total', {
method: 'GET',
baseURL: env.API_ENDPOINT,
parseResponse: JSON.parse,
});
return {
total: response.message,
};
}

View File

@ -1,25 +1,13 @@
<script lang="ts">
import { onMount } from 'svelte';
import { _ } from 'svelte-i18n';
import { $fetch as omf } from 'ohmyfetch';
import { goto } from '$app/navigation';
import env from '$lib/env';
import Codeblock from '../components/codeblock.svelte';
interface TotalResponse {
message: string;
}
/** @type {import('./$types').PageData} */
export let data;
let total;
onMount(async () => {
const totalJokes = async (): Promise<string> => {
const response = await omf<TotalResponse>(`${env.API_ENDPOINT}/total`);
return response.message;
};
total = await totalJokes();
});
let total = data.total;
</script>
<svelte:head>
@ -27,7 +15,7 @@
<meta name="title" content={$_('meta.title') + '-' + $_('meta.tagline')} />
<meta name="twitter:title" content={$_('meta.title') + '-' + $_('meta.tagline')} />
<meta property="og:title" content={$_('meta.title') + '-' + $_('meta.tagline')} />
<link rel="canonical" href="https://jokesbapak2.pages.dev/" />
<link rel="canonical" href="https://jokesbapak2.reinaldyrafli.com/" />
<meta name="description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta name="twitter:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta property="og:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
@ -43,17 +31,13 @@
<div class="max-w-xs mx-auto">
<img src={env.API_ENDPOINT + `/today`} alt="Sample joke" class="py-6 shadow-2xl" />
</div>
<Codeblock>$ curl -XGET 'https://jokesbapak2.herokuapp.com/v1/'</Codeblock>
<Codeblock>$ curl -XGET 'https://jokesbapak2.reinaldyrafli.com/api/'</Codeblock>
<p class="text-sm text-center py-4 opacity-70 hover:opacity-100 transition duration-300 ease-in-out">
{$_('home.more.1')} <span on:click={() => goto('/guide')}>{$_('navigation.guide')}</span>
{$_('home.more.2')} <span on:click={() => goto('/api')}>{$_('navigation.api')}</span>
{$_('home.more.1')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/guide')}>{$_('navigation.guide')}</span>
{$_('home.more.2')}
<span class="hover:underline cursor-pointer" on:click={() => goto('/api')}>{$_('navigation.api')}</span>
</p>
</div>
</div>
</section>
<style>
span {
@apply 'hover:underline' cursor-pointer;
}
</style>

View File

@ -0,0 +1 @@
export const ssr = true;

View File

@ -4,8 +4,8 @@
import { _ } from 'svelte-i18n';
import env from '$lib/env';
import { $fetch as omf } from 'ohmyfetch';
import Codeblock from '../components/codeblock.svelte';
import Notice from '../components/notice.svelte';
import Codeblock from '../../components/codeblock.svelte';
import Notice from '../../components/notice.svelte';
interface TotalResponse {
message: string;
@ -28,7 +28,7 @@
<meta name="title" content={$_('navigation.api') + '-' + $_('meta.title')} />
<meta name="twitter:title" content={$_('navigation.api') + '-' + $_('meta.title')} />
<meta property="og:title" content={$_('navigation.api') + '-' + $_('meta.title')} />
<link rel="canonical" href="https://jokesbapak2.pages.dev/api" />
<link rel="canonical" href="https://jokesbapak2.reinaldyrafli.com/api" />
<meta name="description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta name="twitter:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta property="og:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
@ -40,7 +40,7 @@
</Notice>
</section>
<section>
<section class="api_page">
<h1>{$_('api.get.title')}</h1>
<h2>{$_('api.get.random.title')}</h2>
<p>{$_('api.get.random.body')}</p>
@ -66,12 +66,19 @@
<style>
h1 {
@apply text-4xl font-bold py-4;
@apply text-4xl;
@apply font-bold;
@apply py-4;
}
h2 {
@apply text-2xl font-bold pt-6 pb-1;
@apply text-2xl;
@apply font-bold;
@apply pt-6;
@apply pb-1;
}
p {
@apply text-base opacity-80 py-2;
@apply text-base;
@apply opacity-80;
@apply py-2;
}
</style>

View File

@ -1,5 +1,5 @@
<script lang="ts">
import Codeblock from '../components/codeblock.svelte';
import Codeblock from '../../components/codeblock.svelte';
import { _ } from 'svelte-i18n';
// This page is meant to guide people on how to use the API.
</script>
@ -9,13 +9,13 @@
<meta name="title" content={$_('navigation.guide') + '-' + $_('meta.title')} />
<meta name="twitter:title" content={$_('navigation.guide') + '-' + $_('meta.title')} />
<meta property="og:title" content={$_('navigation.guide') + '-' + $_('meta.title')} />
<link rel="canonical" href="https://jokesbapak2.pages.dev/guide" />
<link rel="canonical" href="https://jokesbapak2.reinaldyrafli.com/guide" />
<meta name="description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta name="twitter:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta property="og:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
</svelte:head>
<section>
<section class="guide_page">
<h1>{$_('navigation.guide')}</h1>
<p>
{$_('guide.introduction.1')}
@ -23,38 +23,52 @@
</p>
</section>
<section>
<section class="guide_page">
<h2>{$_('guide.direct.1')} <code>&lt;img&gt;</code> {$_('guide.direct.2')}</h2>
<Codeblock>&lt;img src="https://jokesbapak2.herokuapp.com/v1/" /&gt;</Codeblock>
<Codeblock>&lt;img src="https://jokesbapak2.reinaldyrafli.com/api/" /&gt;</Codeblock>
</section>
<section>
<section class="guide_page">
<h2>{$_('guide.fetch.1')}</h2>
<p>{$_('guide.fetch.2')}</p>
<Codeblock>
fetch("https://jokesbapak2.herokuapp.com/v1/")<br />
&nbsp;&nbsp;.then(response => response.text())<br />
&nbsp;&nbsp;.then(data => console.log(data))<br />
const response = await fetch(&quot;https://jokesbapak2.reinaldyrafli.com/api/&quot;);<br />
<br />
// {$_('guide.fetch.3')}<br />
if (!response.ok) &#123;<br />
&nbsp;&nbsp;// {$_('guide.fetch.3')}<br />
&#125;<br />
<br />
&lt;img src="data:image/jpeg;base64, &lcub; data &rcub;" /&gt;
const blob = await response.blob();<br />
<br />
const objectURL = URL.createObjectURL(blob);<br />
<br />
&lt;img src=&quot;&#123; objectURL &#125;&quot; /&gt;
</Codeblock>
</section>
<style>
p {
@apply text-base py-2 'lg:w-2/3';
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-4xl font-bold py-2;
@apply text-4xl;
@apply font-bold;
@apply py-2;
}
h2 {
@apply text-2xl font-bold py-2;
@apply text-2xl;
@apply font-bold;
@apply py-2;
}
a {
/* This would probably be an error if you installed WindiCSS extension on VSCode */
@apply 'hover:underline' 'dark:text-dodger-200' text-dodger-700;
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;

View File

@ -7,18 +7,18 @@
<meta name="title" content={$_('navigation.why') + '-' + $_('meta.title')} />
<meta name="twitter:title" content={$_('navigation.why') + '-' + $_('meta.title')} />
<meta property="og:title" content={$_('navigation.why') + '-' + $_('meta.title')} />
<link rel="canonical" href="https://jokesbapak2.pages.dev/why" />
<link rel="canonical" href="https://jokesbapak2.reinaldyrafli.com/why" />
<meta name="description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta name="twitter:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
<meta property="og:description" content="Largest collection of Indonesian dad jokes as a consumable API" />
</svelte:head>
<section>
<section class="why_page">
<h1 id="why-does-this-project-exists">{$_('why.exists.title')}</h1>
<p>{$_('why.exists.body.1')} {$_('why.exists.body.2')} {$_('why.exists.body.3')} {$_('why.exists.body.4')}</p>
<p>{$_('why.exists.body.5')} {$_('why.exists.body.6')}</p>
</section>
<section>
<section class="why_page">
<h1 id="can-i-submit-my-dad-joke">{$_('why.submit.title')}</h1>
<p>
{$_('why.submit.body.1')}
@ -29,7 +29,7 @@
{$_('why.submit.body.6')}
</p>
</section>
<section>
<section class="why_page">
<h1 id="can-i-contribute">{$_('why.contribute.title')}</h1>
<p>
{$_('why.contribute.body.1')}
@ -38,7 +38,7 @@
{$_('why.contribute.body.4')}
</p>
</section>
<section>
<section class="why_page">
<h1 id="other-inquiries">{$_('why.inquiries.title')}</h1>
<p>
{$_('why.inquiries.body.1')}
@ -48,15 +48,23 @@
<style>
p {
@apply text-base py-2 'lg:w-2/3';
@apply text-base;
@apply py-2;
@apply lg\:w-2\/3;
}
h1 {
@apply text-3xl font-bold py-2;
@apply text-3xl;
@apply font-bold;
@apply py-2;
}
a {
/* This would probably be an error if you installed WindiCSS extension on VSCode */
@apply 'hover:underline' 'dark:text-dodger-200' text-dodger-700;
@apply hover\:underline;
@apply dark\:text-dodger-200;
@apply text-dodger-700;
}
section {
@apply pt-6;
}

View File

@ -1,5 +1,5 @@
import preprocess from 'svelte-preprocess';
import adapter from '@sveltejs/adapter-static';
import adapter from '@sveltejs/adapter-node';
import { windi } from 'svelte-windicss-preprocess';
/** @type {import('@sveltejs/kit').Config} */
@ -8,25 +8,26 @@ const config = {
// for more information about preprocessors
preprocess: [
windi({
configPath: './windi.config.js',
configPath: './windi.config.ts',
preflights: false,
}),
preprocess({ postcss: false }),
],
kit: {
// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte',
trailingSlash: 'never',
files: {
routes: './src/routes',
assets: './static',
hooks: './src',
hooks: {
server: './src',
client: './src',
},
lib: './src/lib',
},
adapter: adapter({
// default options are shown
pages: 'dist',
assets: 'dist',
out: 'dist',
}),
},
};

View File

@ -1,4 +1,5 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"moduleResolution": "node",
"module": "es2020",
@ -23,6 +24,7 @@
"allowJs": true,
"checkJs": true,
"paths": {
"$lib": ["src/lib"],
"$lib/*": ["src/lib/*"]
}
},

6
client/vite.config.ts Normal file
View File

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
});

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,35 @@
services:
api:
build: ./api/
restart: always
env_file: ./api/.env
ports:
- 5000:5000
healthcheck:
test: "curl -f http://api:5000/health/"
interval: 15s
timeout: 12s
retries: 10
start_period: 30s
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 30s
max_attempts: 20
window: 60s
resources:
limits:
memory: 1GB
cpus: '1'
reservations:
memory: 50MB
cpus: '0.1'
depends_on:
- db
- cache
# Uncomment these if you want to have it on
# volumes:
# ./api:/app
bucket:
condition: service_healthy
cache:
condition: service_healthy
client:
build: ./client/
@ -18,38 +37,33 @@ services:
env_file: ./client/.env
ports:
- 3000:3000
depends_on:
- api
# Uncomment these if you want to have it on
# volumes:
# ./client:/app
db:
build: ./database/postgres/
command: >
-c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key
restart: unless-stopped
ports:
- 5432:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: jokesbapak2
PGDATA: /data/postgres
# I got this key from somewhere. It works when you run it locally.
POSTGRES_SSL_CA_CERT: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURjekNDQWx1Z0F3SUJBZ0lVR3lDaElvR3g0
healthcheck:
test: pg_isready -U postgres
interval: 10s
timeout: 5s
retries: 5
test: "curl -f http://client:3000/"
interval: 15s
timeout: 12s
retries: 10
start_period: 30s
volumes:
- ./database/postgres/data:/data/postgres
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 30s
max_attempts: 20
window: 60s
resources:
limits:
memory: 500MB
cpus: '1'
reservations:
memory: 50MB
cpus: '0.1'
depends_on:
api:
condition: service_healthy
cache:
image: redis:6.2.4-alpine
restart: unless-stopped
image: redis:6.2.7-alpine
ports:
- 6379:6379
healthcheck:
@ -58,12 +72,27 @@ services:
timeout: 5s
retries: 5
start_period: 30s
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 30s
max_attempts: 20
window: 60s
resources:
limits:
memory: 2GB
cpus: '1'
reservations:
memory: 100MB
cpus: '0.1'
volumes:
- ./database/redis/etc:/usr/local/etc/redis
- ./database/redis/data:/data
- ./data/redis/etc:/usr/local/etc/redis
- ./data/redis/data:/data
bucket:
image: quay.io/minio/minio:RELEASE.2022-02-05T04-40-59Z
image: quay.io/minio/minio:RELEASE.2022-09-07T22-25-02Z
command: server /data --console-address ":9001"
restart: unless-stopped
ports:
@ -80,28 +109,20 @@ services:
timeout: 10s
retries: 5
start_period: 60s
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 30s
max_attempts: 20
window: 60s
resources:
limits:
memory: 4GB
cpus: '2'
reservations:
memory: 50MB
cpus: '0.1'
volumes:
- ./data/minio:/data
cache-admin:
image: rediscommander/redis-commander:latest
restart: always
environment:
REDIS_PORT: 6379
REDIS_HOST: redis
ports:
- 2084:8081
depends_on:
- cache
db-admin:
image: sosedoff/pgweb:0.11.8
restart: always
ports:
- 2086:8081
links:
- postgres:postgres
environment:
DATABASE_URL: postgres://postgres:password@db/jokesbapak2
depends_on:
- db