Skip to content

Commit

Permalink
Merge branch 'master' into history
Browse files Browse the repository at this point in the history
  • Loading branch information
prokawsar committed Jul 14, 2024
2 parents 45ffa99 + 4d26c17 commit fd0eca4
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 72 deletions.
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# dashboard-starter
# Determine Paper Cost

This is starter repo for frontend project. With stack of Svelte, Tailwind, TypeScript, Charts.js, Fontawesome

## Tech Stack

Expand All @@ -14,16 +13,11 @@ This is starter repo for frontend project. With stack of Svelte, Tailwind, TypeS
Tools

```bash
-> Posthog (For track)
-> Chart.js (For chart)
-> Tippy.js (For tooltip)
-> @inlang/sdk-js (For language support)
-> svelte-fa (fontawesome icons)
```

## After Cloning this project

If you're seeing this, you've probably already done this step. Congrats!
You will need to install dependency!

```bash
# install all dependency
Expand Down
13 changes: 13 additions & 0 deletions src/lib/elements/Button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
export let disabled = false
export let text = ''
export let classNames = ''
</script>

<button
{disabled}
class="border border-gray-400 rounded-md text-teal-600 font-semibold px-3 py-1 w-fit disabled:text-opacity-60 {classNames}"
on:click
>
{text}
</button>
15 changes: 13 additions & 2 deletions src/lib/elements/Input.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
<script lang="ts">
import { focusedInputStore } from '$lib/stores'
import { makeid } from '$lib/utils/tools'
export let id: string = makeid(3)
export let value: string
export let placeholder: string = ''
export let disabled: boolean = false
let inputRef: HTMLInputElement
</script>

<input
bind:this={inputRef}
{id}
{disabled}
class="input-field focus:outline-dashed focus:outline-gray-600"
class="input-field focus:!border-[1.5px] focus:!border-teal-500 focus:outline-none"
type="number"
{placeholder}
bind:value
on:keydown
on:focus
on:focus={() => ($focusedInputStore = inputRef)}
/>

<style lang="postcss">
.input-field {
@apply border border-dashed border-gray-200 p-1 rounded w-full outline-offset-1;
@apply border border-gray-400 w-14 p-1 rounded;
}
</style>
3 changes: 2 additions & 1 deletion src/lib/stores/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Paper } from '$lib/utils/services'
import { persisted } from 'svelte-persisted-store'
import type { Writable } from 'svelte/store'
import { writable, type Writable } from 'svelte/store'

export type PaperHistory = {
id: string
Expand All @@ -13,3 +13,4 @@ function getPaperStore(): Writable<{ history: PaperHistory[] }> {
}

export const paperHistoryStore = getPaperStore()
export const focusedInputStore: Writable<HTMLInputElement | null> = writable(null)
2 changes: 1 addition & 1 deletion src/lib/utils/services.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export type Paper = {
id: string
height: string
length: string
width: string
thickness: string
rate: string
Expand Down
9 changes: 4 additions & 5 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import { page } from '$app/stores'
import { PUBLIC_MIX_TOKEN } from '$env/static/public'
import '$lib/app.css'
import '@fontsource/jost'
Expand All @@ -16,26 +15,26 @@
<main class="h-[100svh] flex flex-col">
<nav>
<div class="flex justify-center py-2">
<p class="text-center text-3xl font-semibold">Molla Printing & Packaging</p>
<p class="text-center text-2xl text-red-600 font-semibold">Molla Printing & Packaging</p>
</div>
<div
class="w-full max-w-6xl mx-auto bg-gradient-to-r from-transparent via-orange-800/40 to-transparent p-[1px]"
/>
<div class="px-4 flex w-full mt-2">
<!-- <div class="px-4 flex w-full mt-2">
<div
class="flex w-full flex-row gap-3 bg-slate-100 py-1 px-2 rounded border-dashed border border-orange-400"
>
<a href="/" class:hidden={$page.url.pathname == '/'} class="h-full">Back</a>
<a href="/history" class:hidden={$page.url.pathname == '/history'} class="h-full">History</a
>
</div>
</div>
</div> -->
</nav>
<slot />

<div class="absolute bottom-0 w-full">
<p class="text-center text-gray-400">
&#x1F4BB;Developed by <a href="https://github.com/prokawsar" target="_blank">Kawsar</a
&#x1F4BB;Developed by <a href="https://github.com/prokawsar" target="_blank">ProKawsar</a
>&#x1F60E;
</p>
</div>
Expand Down
144 changes: 94 additions & 50 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
<script lang="ts">
import Button from '$lib/elements/Button.svelte'
import Input from '$lib/elements/Input.svelte'
import Result from '$lib/elements/Result.svelte'
import { paperHistoryStore } from '$lib/stores'
import { focusedInputStore, paperHistoryStore } from '$lib/stores'
import { MAX_PAPER, PAPER_FIXED, type Paper } from '$lib/utils/services'
import { makeid } from '$lib/utils/tools'
import Icon from '@iconify/svelte'
import mixpanel from 'mixpanel-browser'
import { onMount, tick } from 'svelte'
const paperFields = {
id: '',
height: '',
length: '',
width: '',
thickness: '',
rate: ''
}
const placeholders: { [key: string]: string } = {
length: 'L',
width: 'W',
thickness: 'GSM',
rate: 'R'
}
const fields = Object.keys(paperFields).filter((key) => key !== 'id')
let paperCount: Paper[] = [{ ...paperFields, id: makeid(5) }]
let perPaperResult: Map<string, number> = new Map()
let finalPrice: number = 0
let inputs: NodeListOf<HTMLInputElement> | null
let inputGroupRef: HTMLDivElement
let focusedIndex = 0
const addPaper = () => {
const addPaper = async () => {
paperCount.push({ ...paperFields, id: makeid(5) })
paperCount = paperCount
getAllInputs()
}
const removePaper = (idx: string) => {
const removePaper = async (idx: string) => {
paperCount = paperCount.filter((field) => field.id != idx)
getAllInputs()
}
const calculatePaperCost = () => {
Expand All @@ -34,7 +48,7 @@
finalPrice = 0
paperCount.forEach((paper) => {
const paperSize =
parseFloat(paper.height) * parseFloat(paper.width) * parseFloat(paper.thickness)
parseFloat(paper.length) * parseFloat(paper.width) * parseFloat(paper.thickness)
const result = paperSize / PAPER_FIXED
const totalPerPaper = result * parseFloat(paper.rate)
Expand Down Expand Up @@ -66,79 +80,109 @@
const clearAll = () => {
paperCount = [{ ...paperFields, id: makeid(5) }]
finalPrice = 0
focusedIndex = 0
perPaperResult.clear()
getAllInputs()
setFocus()
}
const fields = Object.keys(paperFields).filter((key) => key !== 'id')
const getAllInputs = async () => {
await tick()
inputs = inputGroupRef.querySelectorAll('input')
}
const setFocus = (element?: HTMLInputElement) => {
if (inputs) {
$focusedInputStore = element || inputs[0]
$focusedInputStore.focus()
}
}
$: hasNullValue =
paperCount &&
paperCount.find((paper) => {
return !paper.height || !paper.width || !paper.thickness || !paper.rate
return !paper.length || !paper.width || !paper.thickness || !paper.rate
})
$: paperCount.length == 0 ? clearAll() : ''
// Handling and maintaining focused input index
$: inputsArray = inputs && Array.from(inputs)
$: focusedInputID = $focusedInputStore && $focusedInputStore.getAttribute('id')
$: if (focusedInputID && inputsArray && inputsArray.length) {
focusedIndex = inputsArray
.map((input) => input.getAttribute('id'))
.findIndex((id) => focusedInputID == id)
}
function handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Enter' && inputs) {
focusedIndex++
event.preventDefault()
const nextInput = inputs[focusedIndex]
if (nextInput) {
setFocus(nextInput)
}
}
}
onMount(() => {
inputs = inputGroupRef.querySelectorAll('input')
setFocus()
})
</script>

<svelte:head>
<title>Paper Cost Calculator</title>
</svelte:head>

<section class="max-w-6xl mx-auto flex w-full max-h-[85%] flex-col gap-4 px-4 py-5">
<h1 class="text-xl text-center">Paper Cost</h1>
<h1 class="text-xl text-center text-teal-500 font-semibold">Paper Cost</h1>
<div class="w-full bg-gradient-to-r from-transparent via-slate-600/10 to-transparent p-[1px]" />
<div class="flex flex-col w-full justify-between gap-4 h-[90%] items-center">
<div class="flex flex-col gap-4 overflow-y-auto max-w-3xl max-h-[85%] py-2">
<div
class="flex flex-col gap-[1px] overflow-y-auto max-w-3xl max-h-[85%] py-2 w-full"
bind:this={inputGroupRef}
>
{#each paperCount as paper, i}
<div class="flex flex-col gap-1 items-center p-1 border border-dashed rounded shadow-md">
<div class="flex flex-row items-center pl-1 justify-between w-full">
<p class="w-fit">
Paper {i + 1}
</p>

<div class="flex flex-row items-center justify-between rounded">
<div class="flex flex-row gap-[3px] items-center overflow-x-auto">
<button
disabled={paperCount.length == 1 && i == 0}
class="border border-gray-200 rounded-md p-1 text-red-600 w-fit disabled:cursor-not-allowed disabled:text-opacity-45"
class="border border-gray-400 rounded-md text-red-600 p-1 w-fit disabled:border-gray-200 disabled:cursor-not-allowed disabled:text-opacity-45"
on:click={() => removePaper(paper.id)}
>
<Icon icon="ph:trash-light" width="16px" />
</button>
</div>
<div class="grid grid-cols-5 w-full gap-1 items-center overflow-x-auto p-1">
{#each fields as field}
<Input bind:value={paper[field]} placeholder={field} />
<Input
bind:value={paper[field]}
placeholder={placeholders[field]}
on:keydown={(event) => handleKeyDown(event)}
/>
{/each}
<div class="flex justify-start">
<p
class={perPaperResult.get(paper.id) ? 'font-semibold' : 'font-light text-gray-400'}
>
= {perPaperResult.get(paper.id)?.toFixed(2) || 'total'}
</p>
</div>
</div>
<div class="flex flex-grow justify-center px-1">
<p
class="{perPaperResult.get(paper.id)
? 'font-semibold'
: 'font-light text-gray-400'} pr-[2px]"
>
= {perPaperResult.get(paper.id)?.toFixed(2) || 'total'}
</p>
</div>
</div>
{/each}
</div>

<!-- Button and result section -->
<div class="flex flex-col justify-center max-w-3xl w-full gap-4">
<!-- result section -->
<div class="font-bold text-lg flex w-full">
{#if finalPrice}
<Result total={finalPrice} />
{/if}
</div>
<!-- button section -->
<div
class:justify-between={paperCount.length}
class="flex flex-row justify-center w-full mt-3"
>
<button
disabled={paperCount.length == MAX_PAPER}
class="border border-slate-300 rounded-md text-sm text-gray-600 px-3 py-1 w-fit disabled:text-slate-400"
<div class="flex flex-row justify-between w-full mt-3">
<Button
classNames="text-sm"
on:click={addPaper}
>
Add paper
</button>
disabled={paperCount.length == MAX_PAPER}
text="Add paper"
/>
{#if finalPrice}
<button
class="border border-red-200 rounded-md px-3 py-1 text-red-400 w-fit"
Expand All @@ -148,13 +192,13 @@
</button>
{/if}
{#if paperCount.length}
<button
disabled={!!hasNullValue}
class="border font-semibold border-gray-200 rounded-md px-3 py-1 text-teal-600 w-fit disabled:cursor-not-allowed disabled:text-opacity-60"
on:click={calculatePaperCost}
>
Calculate
</button>
<Button on:click={calculatePaperCost} disabled={!!hasNullValue} text="Calculate" />
{/if}
</div>
<!-- result section -->
<div class="font-bold text-lg flex w-full">
{#if finalPrice}
<Result total={finalPrice} />
{/if}
</div>
</div>
Expand Down
1 change: 0 additions & 1 deletion src/routes/history/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { paperHistoryStore } from '$lib/stores'
import days from 'dayjs'
import Icon from '@iconify/svelte'
</script>

<section class="max-w-6xl mx-auto flex w-full max-h-[90%] flex-col gap-4 px-4 py-5">
Expand Down
Binary file added static/logo.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions static/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"start_url": "/",
"icons": [
{
"src": "logo.png",
"type": "image/png",
"src": "logo.jpeg",
"type": "image/jpeg",
"sizes": "512x512",
"purpose": "any maskable"
}
],
"background_color": "#3367D6",
"background_color": "#000",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6",
"theme_color": "#000",
"description": "Paper Cost Calculator"
}

0 comments on commit fd0eca4

Please sign in to comment.