Init project
This commit is contained in:
parent
050fdb4f64
commit
e5d6c890a8
46 changed files with 7856 additions and 0 deletions
55
.github/workflows/build.yaml
vendored
Normal file
55
.github/workflows/build.yaml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
name: build-docker
|
||||
run-name: build-docker ${{ github.actor }}
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v1.**
|
||||
branches:
|
||||
- 'main'
|
||||
# Allow run workflow manually from Action tab
|
||||
workflow_dispatch:
|
||||
env:
|
||||
REGISTRY: docker.frappet.com
|
||||
CMS_IMAGE_NAME: demo/qualifying-exam-cms
|
||||
CMS_IMAGE_TAG: 0.1.0
|
||||
jobs:
|
||||
# act --workflows .github/workflows/build.yaml --job remote-image -s DOCKER_USER -s DOCKER_PASS
|
||||
# act -W .github/workflows/build.yaml -j remote-image -s DOCKER_USER -s DOCKER_PASS
|
||||
remote-image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# skip Set up QEMU because it fail on act and container
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login in to registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{env.REGISTRY}}
|
||||
username: ${{secrets.DOCKER_USER}}
|
||||
password: ${{secrets.DOCKER_PASS}}
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Build and push docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: cms
|
||||
# platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{env.REGISTRY}}/${{env.CMS_IMAGE_NAME}}:${{env.CMS_IMAGE_TAG}},${{env.REGISTRY}}/${{env.CMS_IMAGE_NAME}}:latest
|
||||
# act -W .github/workflows/build.yaml -j local-image
|
||||
local-image:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Check out code"
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Build and push docker image
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: cms
|
||||
load: true
|
||||
tags: ${{env.REGISTRY}}/${{env.CMS_IMAGE_NAME}}:${{env.CMS_IMAGE_TAG}},${{env.REGISTRY}}/${{env.CMS_IMAGE_NAME}}:latest
|
||||
34
README.md
Normal file
34
README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# ระบบสรรคหา
|
||||
แบ่งออกเป็นสามส่วน
|
||||
- ส่วนจัดการการสอบแข่งขัน BE .NET,FE Vue.js อยู่ในระบบหลัก อยู่ในเน็ตเวิร์กของ BKK
|
||||
- ส่วนรับสมัครสอบคัดเลือก FE/BE จะใช้คนละ Realms แยกจากระบบหบัก ผู้สมัครจะใช้ email ในการ login อยู่นอกเน็ตเวิร์กของ BKK
|
||||
- เวปประกาศข่าว FE/BE Sveltekit ควรใช้การดึงข้อมูลจาก สอบแข่งขัน สอบคัดเลือก ผ่าน API ไม่ต้อง Authentication เพราะเป็นสาธารณะอยู่แล้ว อยู่นอกเน็ตเวิร์กของ BKK
|
||||
|
||||
## ส่วนจัดการการสอบแข่งขัน
|
||||
ทำส่วนนำเข้าข้อมูลไปบ้างแล้ว อยู่ที่ [BMA-EHR-RECRUIT-SERVICE](https://github.com/Frappet/BMA-EHR-RECRUIT-SERVICE)
|
||||
ต้องมี API สำหรับดึงข้อมูลไปเวปประกาศข่าว
|
||||
|
||||
## ส่วนรับสมัครสอบคัดเลือก
|
||||
การรับสมัครสอบคัดเลือกจำเป็นต้องมี
|
||||
- Backoffice เจ้าหน้าที่ใน eHR สำหรับหน่วยงานสร้างรอบ, เจ้าหน้าที่นำเข้าข้อมูล, ก.ก. อนุมัติ
|
||||
- Frontend หน้าเวปสำหรับผู้ใช้งานมาสมัคร
|
||||
- API สำหรับดึงข้อมูลไปเวปประกาศข่าว
|
||||
|
||||
## เวปประกาศข่าว
|
||||
หน้าเวปสำหรับผู้สมัครมาอ่านข่าวประกาศ
|
||||
- Frontend ดึงข้อมูลจาก สอบแข่งขัน สอบคัดเลือก มาแสดง และข้อมูลทั่วไปของเวปเองจาก Backoffice
|
||||
- Backoffice แบบหนึ่ง มี Admin control panel และฐานข้อมูลในตัวเอง login ในตัวเอง แยกจากระบบหลักเลย ใช้เข้าไปจัดการข้อมูลข่าวอื่นๆ และข้อมูลเวปได้ แบบนี้น่าจะงานหนักหน่อยเพราะต้องทำ authen เอง
|
||||
- Backoffice แบบสอง ตัวจัดการข้อมูลอยู่ใน eHR ดึงข้อมูลผ่าน API มาแสดง ถ้าเลือกทำแบบนี้ CMS จะเป็นแบบอ่านอย่างเดียว ปลอดภัย Stateless อาจจะมองเรื่อง cache API ร่วมด้วย
|
||||
|
||||
## Info
|
||||
ข้อมูลเพิ่มเติมนอกจาก TOR สามารถดูได้ที่เวป [กองสรรหาบุคคล (Bangkok careers) ](https://webportal.bangkok.go.th/KSB) มีหลัการ
|
||||
[การสรรหาและเลือกสรร](https://webportal.bangkok.go.th/KSB/page/sub/19478/%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%AA%E0%B8%A3%E0%B8%A3%E0%B8%AB%E0%B8%B2%E0%B9%81%E0%B8%A5%E0%B8%B0%E0%B9%80%E0%B8%A5%E0%B8%B7%E0%B8%AD%E0%B8%81%E0%B8%AA%E0%B8%A3%E0%B8%A3)
|
||||
|
||||
## BKK CMS
|
||||
ทางกรุงเทพมหานครมี [Web Portal](https://webportal.bangkok.go.th/) เป็นของตัวเองอยู่แล้ว ข้อมูลเยอะและซับซ้อน ควรเลือกดูเท่าที่จำเป็น ยังไม่แน่ใจว่าใครรับผิดชอบในการอัปเดตข่าวสาร มี่ข้อมูลจากหลายหน่วยงานอาจจะมี login ไปทำกันเอง มีลิงค์บางส่วนใช้งานไม่ได้ (อาจจะเป็นเวปภายใน)
|
||||
- [โครงสร้างองค์กร](https://webportal.bangkok.go.th/KSB/page/sub/10761/%E0%B9%82%E0%B8%84%E0%B8%A3%E0%B8%87%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87%E0%B8%AD%E0%B8%87%E0%B8%84%E0%B9%8C%E0%B8%81%E0%B8%A3) สามารถหาข้อมูลเพิ่มเติมของแต่ละสำนัก หน่วยงานเขต และ โรงพยาบาลในสังกัด สนพ. ได้ เมื่อเข้าไปดูโครงสร้่างในแต่ละสำนักเป็นภาพไม่ได้สร้างจากฐานข้อมูล
|
||||
- [เวปหนังสือเวียน](https://circular.bangkok.go.th/)ดูแลโดย สำนักยุทธศาสตร์และประเมินผล. เอกสาร PDF บางอันมาจากที่นี้แล้วเอาลิงค์ไปแปะใน Portal ทำหลายอย่าง หนังสือเวียน, มีการขอใช้อีเมลล์(Zimbra), Linkage, จองห้องประชุม, ขอ IP Address ทางบริษัทเราน่าจะต้องติดต่อหน่วยงาน
|
||||
เอกสารเป็น client paging โหลดค่อนข้างช้าข้อมูลมีแนวโน้มจะเพิ่มขึ้นเรื่อยๆ(9000+)
|
||||
- [สถาบันพัฒนาข้าราชการกรุงเทพมหานคร](https://webportal.bangkok.go.th/training)
|
||||
- [กองสรรหาบุคคล (Bangkok careers) ](https://webportal.bangkok.go.th/KSB)
|
||||
|
||||
13
cms/.eslintignore
Normal file
13
cms/.eslintignore
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
20
cms/.eslintrc.cjs
Normal file
20
cms/.eslintrc.cjs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
|
||||
plugins: ['svelte3', '@typescript-eslint'],
|
||||
ignorePatterns: ['*.cjs'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
settings: {
|
||||
'svelte3/typescript': () => require('typescript')
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
}
|
||||
};
|
||||
10
cms/.gitignore
vendored
Normal file
10
cms/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
1
cms/.npmrc
Normal file
1
cms/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
||||
13
cms/.prettierignore
Normal file
13
cms/.prettierignore
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
9
cms/.prettierrc
Normal file
9
cms/.prettierrc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"pluginSearchDirs": ["."],
|
||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||
}
|
||||
12
cms/Dockerfile
Normal file
12
cms/Dockerfile
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# docker build . -t registry.home.lan/demo/be2:latest
|
||||
FROM node:18 as build
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm ci
|
||||
RUN npm run build
|
||||
FROM node:18-alpine
|
||||
WORKDIR /app
|
||||
COPY --from=build /app .
|
||||
EXPOSE 80
|
||||
ENV PORT=80
|
||||
CMD ["node", "./build/index.js"]
|
||||
85
cms/README.md
Normal file
85
cms/README.md
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# เวปประกาศข่าว (CMS)
|
||||
การพัฒนาแบบที่เป็นอยู่ Vue(SPA)+dotnet(Web API) ของบริษัทไม่ได้รองรับ SEO เท่าใดนัก จำเป็นต้องใช้ Meta Framework ที่รองรับ SSR เช่น Nuxt.js เนื่องจากไม่ขึ้นกับส่วนอื่นมากนัก จะทดลองใช้เทคโนโลยีแบบใหม่ๆในการพัฒนา ที่ง่ายในการพัฒนากว่าเดิมจะ SvelteKit เป็นฐาน Daisy UI และ Daisy UI สำหรับการทำ Frontend และจะนำเครื่องมือในการ Automate ต่างๆมาร่วมด้วย
|
||||
- [Sveltekit](https://www.youtube.com/watch?v=uEJ-Rnm2yOE) Meta JS Framework รองรับ SSR เขียนง่าย
|
||||
- [TailWindCSS]() ติดตั้งด้วย [svelte-add](https://github.com/svelte-add/tailwindcss)
|
||||
- [Daisy UI ](https://daisyui.com/)
|
||||
- [PWA](https://web.dev/progressive-web-apps/) ทำให้ Web App เหมือนแอปมือถือ
|
||||
- [Playwright](https://playwright.dev/) เขียนโค้ดทำการทดสอบเวปแอปบน Browser
|
||||
- [Vitest](https://vitest.dev/) ทำ Unit test สำหรับ Vite
|
||||
- [GitHub Actions](https://github.com/features/actions) ทำ CI/CD ในระบบทดสอบ
|
||||
- [nektos/act](https://github.com/nektos/act) ใช้ GitHub Actions บนเครื่องของเราเอง
|
||||
- [Argo CD](https://argo-cd.readthedocs.io/en/stable/) deploy ขึ้นระบบ Production (K8s)
|
||||
- [Keycloak](https://www.keycloak.org/) ใช้สำหรับทำระบบ Login
|
||||
|
||||
## Install
|
||||
คำสั่งสำหรับเริ่มต้นสร้างโปรเจ็กเปล่าๆ จนใช้งาน
|
||||
``` bash
|
||||
# เลือก Skeleton project,Typescript แล้ว ติดตั้งทั้งหมด
|
||||
npm create svelte@latest cms-recruit
|
||||
cd cms-recruit
|
||||
npm install
|
||||
# ติดตั้ง Tailwindcss พร้อมเซ็ตค่าให้เรียบร้อย
|
||||
npx svelte-add@latest tailwindcss
|
||||
# เมื่อติดตั้ง daisyui ให้ดูวิธีการตั้งค่าเพิ่มจากในเวป
|
||||
npm i daisyui
|
||||
# ใช้สำหรับทำเป็น Node.js ทำ Docker Image
|
||||
npm i -D @sveltejs/adapter-node
|
||||
# Keycloak สำหรับ frontend และ backend
|
||||
npm i -D keycloak-js keycloak-backend
|
||||
# ช่วยทำ seo ให้ง่ายขึ้น
|
||||
npm install -D svelte-seo
|
||||
```
|
||||
|
||||
## Sveltekit
|
||||
คำสั่งที่ใช้
|
||||
``` bash
|
||||
npm run dev -- --port=4000 --host=0.0.0.0
|
||||
npm run build
|
||||
npm run preview -- --port=4000 --host=0.0.0.0
|
||||
# หรือ
|
||||
npx vite --port=4000 --host=0.0.0.0
|
||||
npm vite build
|
||||
npx vite preview --port=4000 --host=0.0.0.0
|
||||
```
|
||||
โครงสร้างโค้ด
|
||||
- หน้าเวปอยู่ใน [src/routes/](src/routes/) โครงหน้าหลัก +layout.svelte,หน้าต่างๆ +page.svelte
|
||||
- library/component ที่ใช้ร่วมกัน [src/lib/](src/lib/)
|
||||
ตัวอย่างการใช้ API โค้ดอยู่ใน [src/routes/api/users](./src/routes/api/users/)
|
||||
- http://localhost:4000/api/users
|
||||
- http://localhost:4000/api/users/1
|
||||
|
||||
## Browser Testing
|
||||
ใช้ Playwright มีคอนฟิกไฟล์ [playwright.config.ts](./playwright.config.ts) โค้ดสำหรับการทดสอบจะอยู่ใน โฟลเดอร์ [tests](./tests/) ใน VS Code จะติดตั้ง Playwright Extension รูปเป็นเหมือนโหลรูปชมพู่สำหรับทดลองวิทยาศาสตร์ ให้กดปุ่มเล่นเพื่อทำการทดสอบ
|
||||
```bash
|
||||
# ติดตั้ง embeded broser ของ playwright
|
||||
npx playwright install chromium
|
||||
# รันเทสที่อยู่ในโฟลเดอร์ tests
|
||||
npm run test
|
||||
```
|
||||
### ดูเพิ่มเติมได้ที่
|
||||
- [การทำ Browser Automation ด้วย Playwright](https://www.youtube.com/watch?v=Bc6dz4hs_r0)
|
||||
|
||||
## Unit Testing
|
||||
ใช้ Vitest ทำ [Unit test](https://www.youtube.com/watch?v=5bQD3dCoyHA) คอนฟิกจะอยู่ที่ [vite.config.ts](./vite.config.ts) แนะนำให้ใส่ไว้ใน lib ในรูปแบบ src/lib/*.test.ts
|
||||
แนะนำให้เขียนโค้ดใน
|
||||
``` bash
|
||||
npm run test:unit
|
||||
```
|
||||
# CI Github Action
|
||||
ให้ดูโค้ดที่ ../.github/workflow
|
||||
- [ตัวอย่างการใช้งานในบริษัท](https://youtu.be/k1w_cCzCd0o)
|
||||
|
||||
# CD Argo CD
|
||||
TODO
|
||||
|
||||
# Note
|
||||
## PWA
|
||||
ใน [app.html](./src/app.html) จะเรียกใช้ [manifest.json](./src/static/manifest.json)
|
||||
ไฟล์ [service-worker.ts](./src/service-worker.ts) จะถูก SvelteKit นำไปทำเป็น Service Worker ให้
|
||||
- [ตอนนี้ใช้แบบง่ายตามนี้](https://thecodingchannel.hashnode.dev/turn-your-sveltekit-app-into-a-pwa-in-3-simple-steps)
|
||||
|
||||
# Keycloak
|
||||
ยังไม่แน่ใจว่าการ Authen จำเป็นสำหรับ CMS หรือเปล่า เพราะใช้แค่แสดงข้อมูล อาจจะใช้หน้า Frontend ของ eHR ในการใส่ข้อมูลทั้งหมดก็น่าจะดีกว่า ตอนนี้ใช้ Repository pattern ไปก่อน
|
||||
- Frontend ใช้ [Keycloak JS](https://www.npmjs.com/package/keycloak-js)
|
||||
- API จะไม่ใช้ keycloak-connect เพราะมันรองรับเฉพาะ Express จะใช้ [keycloak-backend](https://www.npmjs.com/package/keycloak-backend) หรือตัวอื่นๆแทน
|
||||
- ควรใช้การก็อปปี้ public key มาเก็บไว้ แทนการ verify token แบบ online จะเร็วกว่า [How to verify a JWT token in JavaScript and Node.js?](https://www.youtube.com/watch?v=gm2PBHyjQmM)
|
||||
6932
cms/package-lock.json
generated
Normal file
6932
cms/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
47
cms/package.json
Normal file
47
cms/package.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"name": "cms",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "playwright test",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"test:unit": "vitest",
|
||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||
"format": "prettier --plugin-search-dir . --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.28.1",
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/adapter-node": "^1.2.2",
|
||||
"@sveltejs/kit": "^1.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.45.0",
|
||||
"@typescript-eslint/parser": "^5.45.0",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"keycloak-backend": "^4.0.1",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.0",
|
||||
"prettier-plugin-svelte": "^2.8.1",
|
||||
"sass": "^1.58.3",
|
||||
"svelte": "^3.54.0",
|
||||
"svelte-check": "^3.0.1",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"svelte-seo": "^1.5.3",
|
||||
"tailwindcss": "^3.1.5",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.3",
|
||||
"vite": "^4.0.0",
|
||||
"vitest": "^0.25.3"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"daisyui": "^2.51.3"
|
||||
}
|
||||
}
|
||||
11
cms/playwright.config.ts
Normal file
11
cms/playwright.config.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests'
|
||||
};
|
||||
|
||||
export default config;
|
||||
13
cms/postcss.config.cjs
Normal file
13
cms/postcss.config.cjs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const tailwindcss = require('tailwindcss');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
|
||||
tailwindcss(),
|
||||
//But others, like autoprefixer, need to run after,
|
||||
autoprefixer
|
||||
]
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
12
cms/src/app.d.ts
vendored
Normal file
12
cms/src/app.d.ts
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
13
cms/src/app.html
Normal file
13
cms/src/app.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
4
cms/src/app.postcss
Normal file
4
cms/src/app.postcss
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/* Write your global styles here, in PostCSS syntax */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
7
cms/src/index.test.ts
Normal file
7
cms/src/index.test.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('sum test', () => {
|
||||
it('adds 1 + 2 to equal 3', () => {
|
||||
expect(1 + 2).toBe(3);
|
||||
});
|
||||
});
|
||||
33
cms/src/lib/components/Header.svelte
Normal file
33
cms/src/lib/components/Header.svelte
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<div class="navbar bg-base-100">
|
||||
<div class="navbar-start">
|
||||
<div class="dropdown">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<label tabindex="0" class="btn btn-ghost lg:hidden">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h8m-8 6h16" /></svg>
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
|
||||
<ul tabindex="0" class="menu menu-compact dropdown-content mt-3 p-2 shadow bg-base-100 rounded-box w-52">
|
||||
<li><a href="/">หน้าหลัก</a></li>
|
||||
<li><a href="/qualifying">การสอบคัดเลือก</a></li>
|
||||
<li><a href="/competitive">การสอบแข่งขัน</a></li>
|
||||
<li><a href="/about">เกี่ยวกับเรา</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a class="btn btn-ghost normal-case text-xl"
|
||||
href="https://webportal.bangkok.go.th/KSB/page/top/1119/%E0%B8%81%E0%B8%AD%E0%B8%87%E0%B8%AA%E0%B8%A3%E0%B8%A3%E0%B8%AB%E0%B8%B2%E0%B8%9A%E0%B8%B8%E0%B8%84%E0%B8%84%E0%B8%A5">
|
||||
กองสรรหา
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-center hidden lg:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><a href="/">หน้าหลัก</a></li>
|
||||
<li><a href="/qualifying">การสอบคัดเลือก</a></li>
|
||||
<li><a href="/competitive">การสอบแข่งขัน</a></li>
|
||||
<li><a href="/about">เกี่ยวกับเรา</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<a class="btn" href="/">เข้าสู่ระบบ</a>
|
||||
</div>
|
||||
</div>
|
||||
13
cms/src/lib/data/info.json
Normal file
13
cms/src/lib/data/info.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"contact":{
|
||||
"company_name": "กองสรรหาบุคคล",
|
||||
"description":
|
||||
"มีหน้าที่รับผิดชอบเกี่ยวกับการสรรหาและเลือกสรรบุคคลเข้ารับราบการเป็นข้าราขการกรุงเทพมหานคร สามัญและข้าราชการครูกรุงเทพมหานครเฉพาะสังกัดสำนักพัฒนาชุมชน ....",
|
||||
"contact_email_address": "sale@frappet.com",
|
||||
"phone": "(662) xxx xxx",
|
||||
"address": "123 Example Street, xxx, 9876, yyy",
|
||||
"zip": "10510",
|
||||
"Country": "Thailand"
|
||||
}
|
||||
|
||||
}
|
||||
8
cms/src/lib/data/info.test.ts
Normal file
8
cms/src/lib/data/info.test.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//TDD
|
||||
import {it,expect } from 'vitest'
|
||||
import {getContact} from './info'
|
||||
it('test getContact() ',async ()=>{
|
||||
const result = await getContact()
|
||||
expect(result.company_name).toBe("กองสรรหาบุคคล")
|
||||
expect(result.Country).toBe("Thailand")
|
||||
})
|
||||
4
cms/src/lib/data/info.ts
Normal file
4
cms/src/lib/data/info.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import info from "./info.json"
|
||||
export async function getContact(){
|
||||
return info.contact
|
||||
}
|
||||
72
cms/src/lib/data/users.json
Normal file
72
cms/src/lib/data/users.json
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Leanne Graham",
|
||||
"username": "Bret",
|
||||
"email": "Sincere@april.biz",
|
||||
"phone": "1-770-736-8031 x56442"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Ervin Howell",
|
||||
"username": "Antonette",
|
||||
"email": "Shanna@melissa.tv",
|
||||
"phone": "010-692-6593 x09125"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Clementine Bauch",
|
||||
"username": "Samantha",
|
||||
"email": "Nathan@yesenia.net",
|
||||
"phone": "1-463-123-4447"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Patricia Lebsack",
|
||||
"username": "Karianne",
|
||||
"email": "Julianne.OConner@kory.org",
|
||||
"phone": "493-170-9623 x156"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Chelsey Dietrich",
|
||||
"username": "Kamren",
|
||||
"email": "Lucio_Hettinger@annie.ca",
|
||||
"phone": "(254)954-1289"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Mrs. Dennis Schulist",
|
||||
"username": "Leopoldo_Corkery",
|
||||
"email": "Karley_Dach@jasper.info",
|
||||
"phone": "1-477-935-8478 x6430"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Kurtis Weissnat",
|
||||
"username": "Elwyn.Skiles",
|
||||
"email": "Telly.Hoeger@billy.biz",
|
||||
"phone": "210.067.6132"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Nicholas Runolfsdottir V",
|
||||
"username": "Maxime_Nienow",
|
||||
"email": "Sherwood@rosamond.me",
|
||||
"phone": "586.493.6943 x140"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Glenna Reichert",
|
||||
"username": "Delphine",
|
||||
"email": "Chaim_McDermott@dana.io",
|
||||
"phone": "(775)976-6794 x41206"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Clementina DuBuque",
|
||||
"username": "Moriah.Stanton",
|
||||
"email": "Rey.Padberg@karina.biz",
|
||||
"phone": "024-648-3804"
|
||||
}
|
||||
]
|
||||
28
cms/src/lib/data/users.ts
Normal file
28
cms/src/lib/data/users.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import users from "./users.json"
|
||||
let userid =100
|
||||
|
||||
export interface User {
|
||||
id: number;
|
||||
email: string;
|
||||
username: string;
|
||||
name:string;
|
||||
last_name: string;
|
||||
phone:string
|
||||
}
|
||||
export async function getUser(id:number){
|
||||
return users.find(u=>u.id===id)
|
||||
}
|
||||
export async function getUsers(){
|
||||
return users
|
||||
}
|
||||
export async function createUser(u:User){
|
||||
u.id= userid++
|
||||
return users.push(u)
|
||||
}
|
||||
export async function updateUser(u:User){
|
||||
const user = await getUser(u.id)
|
||||
if(!user)
|
||||
return user
|
||||
user.phone = u.phone
|
||||
return user
|
||||
}
|
||||
9
cms/src/routes/+error.svelte
Normal file
9
cms/src/routes/+error.svelte
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import { page } from '$app/stores';
|
||||
</script>
|
||||
|
||||
<h1>{$page.error?.message}</h1>
|
||||
|
||||
<div>
|
||||
มีบางอย่างไม่ถูกต้องกรุณาติดต่อ 02-xxxxxxxx
|
||||
</div>
|
||||
11
cms/src/routes/+layout.svelte
Normal file
11
cms/src/routes/+layout.svelte
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<script>
|
||||
import '../app.postcss';
|
||||
import Header from '$lib/components/Header.svelte';
|
||||
</script>
|
||||
|
||||
<Header />
|
||||
<div class="p-10 max-w-4xl place-content-center ">
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
14
cms/src/routes/+page.svelte
Normal file
14
cms/src/routes/+page.svelte
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<h1 class="text-4xl">กองสรรหาบุคคล (Recruitment Division)</h1>
|
||||
|
||||
|
||||
|
||||
<h2 class="text-2xl">ประกาศเกี่ยวกับการคัดเลือกบุคลากรกทม</h2>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
<h2 class="text-2xl">ประกาศเกี่ยวกับการสอบแข่งขัน</h2>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
<div>xxxx</div>
|
||||
12
cms/src/routes/about/+page.server.ts
Normal file
12
cms/src/routes/about/+page.server.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
import {getContact} from "$lib/data/info"
|
||||
|
||||
import type { PageServerLoad } from './$types'
|
||||
/*
|
||||
export const load: PageServerLoad = async () => {
|
||||
return getContact()
|
||||
}*/
|
||||
|
||||
export const load = (async () => {
|
||||
return getContact()
|
||||
}) satisfies PageServerLoad
|
||||
10
cms/src/routes/about/+page.svelte
Normal file
10
cms/src/routes/about/+page.svelte
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import type { PageData } from './$types'
|
||||
export let data: PageData;
|
||||
</script>
|
||||
|
||||
<h1 class="text-4xl">{data.company_name}</h1>
|
||||
|
||||
<div>{data.description}</div>
|
||||
|
||||
|
||||
12
cms/src/routes/api/users/+server.ts
Normal file
12
cms/src/routes/api/users/+server.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import type { RequestEvent, RequestHandler } from './$types'
|
||||
import {json} from '@sveltejs/kit'
|
||||
import { createUser, getUsers } from '$lib/data/users'
|
||||
|
||||
//api/users
|
||||
export const POST: RequestHandler = async ({ request }: RequestEvent) => {
|
||||
const data = await request.json()
|
||||
return json(await createUser( data))
|
||||
}
|
||||
export const GET: RequestHandler = async () => {
|
||||
return json(await getUsers())
|
||||
}
|
||||
19
cms/src/routes/api/users/[id]/+server.ts
Normal file
19
cms/src/routes/api/users/[id]/+server.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import type { RequestEvent, RequestHandler } from './$types'
|
||||
import {json} from '@sveltejs/kit'
|
||||
import { getUser, updateUser } from '$lib/data/users'
|
||||
|
||||
//api/users/1
|
||||
export const PUT: RequestHandler = async ({ request }: RequestEvent) => {
|
||||
const o = await request.json()
|
||||
if(!updateUser(o))
|
||||
return json({message:"call updateUser fail "},{status:400})
|
||||
return json({message:"Update Success"})
|
||||
}
|
||||
export const GET: RequestHandler = async ({params}: RequestEvent) => {
|
||||
const id = Number(params.id)
|
||||
const u = await getUser(id)
|
||||
if(!u)
|
||||
return json({message:`User ${id} not found`},{status:404})
|
||||
return json(u)
|
||||
}
|
||||
|
||||
7
cms/src/routes/competitive/+page.svelte
Normal file
7
cms/src/routes/competitive/+page.svelte
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<h1 class="text-4xl">การสอบแข่งขัน</h1>
|
||||
|
||||
fdsafda
|
||||
fdsafda sdaf
|
||||
sdaffsdasaf rfffffffffffffffff fffffffffffffffffffffffff ffffffffffff fgedfgfdgfdsg
|
||||
fedsddddddddddddd ddddddddddddddd ddddddddd d d d d d d d d d d d d xxxx
|
||||
|
||||
6
cms/src/routes/qualifying/+page.svelte
Normal file
6
cms/src/routes/qualifying/+page.svelte
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<h1 class="text-4xl">การสอบคัดเลือก</h1>
|
||||
|
||||
<button class="btn btn-outline">Button</button>
|
||||
<button class="btn btn-outline btn-primary">Button</button>
|
||||
<button class="btn btn-outline btn-secondary">Button</button>
|
||||
|
||||
66
cms/src/service-worker.ts
Normal file
66
cms/src/service-worker.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
||||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="esnext" />
|
||||
/// <reference lib="webworker" />
|
||||
|
||||
import { build, files, version } from '$service-worker';
|
||||
|
||||
// Create a unique cache name for this deployment
|
||||
const CACHE = `cache-${version}`;
|
||||
|
||||
const ASSETS = [
|
||||
...build, // the app itself
|
||||
...files // everything in `static`
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
// Create a new cache and add all files to it
|
||||
async function addFilesToCache() {
|
||||
const cache = await caches.open(CACHE);
|
||||
await cache.addAll(ASSETS);
|
||||
}
|
||||
|
||||
event.waitUntil(addFilesToCache());
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
// Remove previous cached data from disk
|
||||
async function deleteOldCaches() {
|
||||
for (const key of await caches.keys()) {
|
||||
if (key !== CACHE) await caches.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
event.waitUntil(deleteOldCaches());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
// ignore POST requests etc
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
async function respond() {
|
||||
const url = new URL(event.request.url);
|
||||
const cache = await caches.open(CACHE);
|
||||
|
||||
// `build`/`files` can always be served from the cache
|
||||
if (ASSETS.includes(url.pathname)) {
|
||||
return cache.match(event.request);
|
||||
}
|
||||
|
||||
// for everything else, try the network first, but
|
||||
// fall back to the cache if we're offline
|
||||
try {
|
||||
const response = await fetch(event.request);
|
||||
|
||||
if (response.status === 200) {
|
||||
cache.put(event.request, response.clone());
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch {
|
||||
return cache.match(event.request);
|
||||
}
|
||||
}
|
||||
|
||||
event.respondWith(respond());
|
||||
});
|
||||
BIN
cms/static/favicon.ico
Normal file
BIN
cms/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
cms/static/favicon.png
Normal file
BIN
cms/static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
cms/static/images/favicon.ico
Normal file
BIN
cms/static/images/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
130
cms/static/images/favicon.svg
Normal file
130
cms/static/images/favicon.svg
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="410"
|
||||
height="404"
|
||||
viewBox="0 0 410 404"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg20"
|
||||
sodipodi:docname="favicon.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata24">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1001"
|
||||
id="namedview22"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.51361386"
|
||||
inkscape:cx="-374.79518"
|
||||
inkscape:cy="145.0506"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g8"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<path
|
||||
d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z"
|
||||
fill="url(#paint0_linear)"
|
||||
id="path2" />
|
||||
<defs
|
||||
id="defs18">
|
||||
<linearGradient
|
||||
id="paint0_linear"
|
||||
x1="6.00017"
|
||||
y1="32.9999"
|
||||
x2="235"
|
||||
y2="344"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#41D1FF"
|
||||
id="stop6" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#BD34FE"
|
||||
id="stop8" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear"
|
||||
x1="194.651"
|
||||
y1="8.81818"
|
||||
x2="236.076"
|
||||
y2="292.989"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#FFEA83"
|
||||
id="stop11" />
|
||||
<stop
|
||||
offset="0.0833333"
|
||||
stop-color="#FFDD35"
|
||||
id="stop13" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FFA800"
|
||||
id="stop15" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path
|
||||
d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z"
|
||||
fill="url(#paint1_linear)"
|
||||
id="path4" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="PWA">
|
||||
<g
|
||||
id="g8"
|
||||
transform="matrix(0.15789659,0,0,0.15890333,54.892928,275.21638)">
|
||||
<path
|
||||
fill="#3d3d3d"
|
||||
fill-opacity="1"
|
||||
stroke-width="0.2"
|
||||
stroke-linejoin="round"
|
||||
d="m 1436.62,603.304 56.39,-142.599 h 162.82 L 1578.56,244.39 1675.2,5.28336e-4 1952,734.933 h -204.13 l -47.3,-131.629 z"
|
||||
id="path2-1"
|
||||
style="fill:#3e3e3e;fill-opacity:1" />
|
||||
<path
|
||||
fill="#5a0fc8"
|
||||
fill-opacity="1"
|
||||
stroke-width="0.2"
|
||||
stroke-linejoin="round"
|
||||
d="M 1262.47,734.935 1558.79,0.00156593 1362.34,0.0025425 1159.64,474.933 1015.5,0.00351906 H 864.499 L 709.731,474.933 600.585,258.517 501.812,562.819 602.096,734.935 h 193.331 l 139.857,-425.91 133.346,425.91 z"
|
||||
id="path4-4"
|
||||
style="fill:#2e859c;fill-opacity:1" />
|
||||
<path
|
||||
fill="#3d3d3d"
|
||||
fill-opacity="1"
|
||||
stroke-width="0.2"
|
||||
stroke-linejoin="round"
|
||||
d="m 186.476,482.643 h 121.003 c 36.654,0 69.293,-4.091 97.917,-12.273 l 31.293,-96.408 87.459,-269.446 C 517.484,93.9535 509.876,83.9667 501.324,74.5569 456.419,24.852 390.719,4.06265e-4 304.222,4.06265e-4 H -3.8147e-6 V 734.933 H 186.476 Z M 346.642,169.079 c 17.54,17.653 26.309,41.276 26.309,70.871 0,29.822 -7.713,53.474 -23.138,70.956 -16.91,19.425 -48.047,29.137 -93.409,29.137 H 186.476 V 142.598 h 70.442 c 42.277,0 72.185,8.827 89.724,26.481 z"
|
||||
id="path6"
|
||||
style="fill:#3e3e3e;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
BIN
cms/static/images/pwa-192x192.png
Normal file
BIN
cms/static/images/pwa-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
cms/static/images/pwa-512x512.png
Normal file
BIN
cms/static/images/pwa-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
28
cms/static/manifest.json
Normal file
28
cms/static/manifest.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/web-manifest-combined.json",
|
||||
"name": "BKK Recrute",
|
||||
"short_name": "BKK Recrute",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#fff",
|
||||
"description": "A readable Hacker News app.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/pwa-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/pwa-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
25
cms/svelte.config.js
Normal file
25
cms/svelte.config.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//import adapter from '@sveltejs/adapter-auto';
|
||||
import adapter from '@sveltejs/adapter-node';
|
||||
import preprocess from 'svelte-preprocess';
|
||||
import { vitePreprocess } from '@sveltejs/kit/vite';
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||
// for more information about preprocessors
|
||||
preprocess: [
|
||||
vitePreprocess(),
|
||||
preprocess({
|
||||
postcss: true
|
||||
})
|
||||
],
|
||||
|
||||
kit: {
|
||||
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
|
||||
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
||||
21
cms/tailwind.config.cjs
Normal file
21
cms/tailwind.config.cjs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const config = {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
|
||||
plugins: [require("daisyui")],
|
||||
daisyui: {
|
||||
styled: true,
|
||||
themes: ["cupcake","cmyk"],
|
||||
base: true,
|
||||
utils: true,
|
||||
logs: true,
|
||||
rtl: false,
|
||||
prefix: "",
|
||||
darkTheme: "dark",
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
11
cms/tests/test.ts
Normal file
11
cms/tests/test.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('Index page has expected h1', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('heading', { name: 'กองสรรหาบุคคล (Recruitment Division)' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('About page has expected h1', async ({ page }) => {
|
||||
await page.goto('/about');
|
||||
await expect(page.getByRole('heading', { name: 'กองสรรหาบุคคล' })).toBeVisible();
|
||||
});
|
||||
17
cms/tsconfig.json
Normal file
17
cms/tsconfig.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
9
cms/vite.config.ts
Normal file
9
cms/vite.config.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue