Clean Code

This commit is contained in:
schooltechx 2023-04-04 18:19:09 +07:00
parent 1c9b5877d6
commit 225bba1528
7 changed files with 0 additions and 588 deletions

View file

@ -1,131 +0,0 @@
<script lang="ts">
import {createEventDispatcher, onMount} from 'svelte'
let dispatch = createEventDispatcher();
import calendarize from './calendarize'
import Arrow from './CalendarArrow.svelte';
export let year = 2023;
export let month = 0; // Jan
export let offset = 0; // Sun
export let locale = "en" as (keyof typeof text_labels)|(keyof typeof text_months);
export let buddhist = false
const text_labels = {
en: ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'],
th: ['อา', 'จ', 'อ', 'พ', 'พฤ', 'ศ', 'ส'],
}
const text_months = {
en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
th: ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'],
}
const today = new Date
const labels = (locale in text_labels)? text_labels[locale]:text_labels.en
const months = (locale in text_months)? text_months[locale]:text_months.en
$: today_month = today.getMonth();
$: today_year = today.getFullYear();
$: today_day = today.getDate();
let prev = calendarize(new Date(year, month-1), offset);
let current = calendarize(new Date(year, month), offset);
let next = calendarize(new Date(year, month+1), offset);
function toPrev() {
[current, next] = [prev, current];
if (--month < 0) {
month = 11;
year--;
}
prev = calendarize(new Date(year, month-1), offset);
}
function toNext() {
[prev, current] = [current, next];
if (++month > 11) {
month = 0;
year++;
}
next = calendarize(new Date(year, month+1), offset);
}
function isToday(day:number ) {
return today && today_year === year && today_month === month && today_day === day;
}
</script>
<header>
<Arrow left on:click={toPrev} />
<h4>{months[month]} - {year+ (buddhist?543:0)}</h4>
<Arrow on:click={toNext} />
</header>
<div class="month">
{#each labels as txt, idx (txt)}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span class="label" on:click={()=>dispatch('headerClick',txt)} >{ labels[(idx + offset) % 7] }</span>
{/each}
{#each { length:6 } as w,idxw (idxw)}
{#if current[idxw]}
{#each { length:7 } as d,idxd (idxd)}
{#if current[idxw][idxd] != 0}
<span class="date" class:today={isToday(current[idxw][idxd])}>
{ current[idxw][idxd] }
</span>
{:else if (idxw < 1)}
<span class="date other">{ prev[prev.length - 1][idxd] }</span>
{:else}
<span class="date other">{ next[0][idxd] }</span>
{/if}
{/each}
{/if}
{/each}
</div>
<style>
header {
display: flex;
margin: 2rem auto;
align-items: center;
justify-content: center;
user-select: none;
}
h4 {
display: block;
text-align: center;
text-transform: uppercase;
font-size: 140%;
margin: 0 1rem;
}
.month {
display: grid;
grid-template-columns: repeat(7, 1fr);
text-align: right;
grid-gap: 4px;
}
.label {
font-weight: 300;
text-align: center;
text-transform: uppercase;
margin-bottom: 0.5rem;
opacity: 0.6;
}
.date {
height: 50px;
font-size: 16px;
letter-spacing: -1px;
border: 1px solid #e6e4e4;
padding-right: 4px;
font-weight: 700;
padding: 0.5rem;
}
.date.today {
color: #5286fa;
background: #c4d9fd;
border-color: currentColor;
}
.date.other {
opacity: 0.2;
}
</style>

View file

@ -1,22 +0,0 @@
<script lang="ts">
export let left = false;
</script>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<svg class:left on:click xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="#c4d9fd" d="M0 256c0 141.2 114.8 256 256 256V0A256.3 256.3 0 000 256z"/>
<path fill="#c4d9fd" d="M256 0v512c141.2 0 256-114.8 256-256S397.2 0 256 0z"/>
<path fill="#5286fa" d="M226 115.4a23.3 23.3 0 00-33 33L300.7 256 193 363.7a23.3 23.3 0 1033 32.9l124-124.1a23.3 23.3 0 000-33l-124-124z"/></svg>
<style>
svg {
width: 3rem;
height: 3rem;
padding: 12px;
cursor: pointer;
}
.left {
transform: rotateY(180deg);
}
</style>

View file

@ -1,22 +0,0 @@
//Modify by Oom
//code from https://www.npmjs.com/package/calendarize
export default function (target?: Date|string, offset=0) {
let i=0, j=0, week = Array(7)
const out=[], date = new Date(target || new Date);
const year = date.getFullYear(), month = date.getMonth();
// day index (of week) for 1st of month
let first = new Date(year, month, 1 - (offset | 0)).getDay();
// how many days there are in this month
const days = new Date(year, month+1, 0).getDate();
while (i < days) {
for (j=0, week=Array(7); j < 7;) {
while (j < first) week[j++] = 0;
week[j++] = ++i > days ? 0 : i;
first = 0;
}
out.push(week);
}
return out;
}

View file

@ -1,191 +0,0 @@
<script lang="ts">
import Calendar from "./CalendarContent.svelte";
export let locale = "en" as (keyof typeof text_labels)|(keyof typeof text_months);
export let buddhist = false
const text_labels = {
en: ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'],
th: ['อา', 'จ', 'อ', 'พ', 'พฤ', 'ศ', 'ส'],
}
const text_months = {
en: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'July', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
th: ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'],
}
const labels = (locale in text_labels)? text_labels[locale]:text_labels.en
const months = (locale in text_months)? text_months[locale]:text_months.en
let headers: string[] = [];
let now = new Date();
let year = now.getFullYear(); // this is the month & year displayed
let month = now.getMonth();
let eventText="Click an item or date";
var days: { name:string,enabled:boolean,date: Date }[] = []; // The days to display in each box
function randInt(max: number) {
return Math.floor(Math.random()*max)+1;
}
// The Calendar Component just displays stuff in a row & column. It has no knowledge of dates.
// The items[] below are placed (by you) in a specified row & column of the calendar.
// You need to call findRowCol() to calc the row/col based on each items start date. Each date box has a Date() property.
// And, if an item overlaps rows, then you need to add a 2nd item on the subsequent row.
var items: (
{ title: string; className: string; date: Date; len: number; isBottom?: boolean;
detailHeader?: string; detailContent?: string; vlen?: number; startCol?:number;startRow?:number}
)[] = [];
function initMonthItems() {
let y = year;
let m = month;
let d1=new Date(y,m,randInt(7)+7);
items=[
{title:"11:00 Task Early in month",className:"task--primary",date:new Date(y,m,randInt(6)),len:randInt(4)+1},
{title:"7:30 Wk 2 tasks",className:"task--warning",date:d1,len:randInt(4)+2},
{title:"Overlapping Stuff (isBottom:true)",date:d1,className:"task--info",len:4,isBottom:true},
{title:"10:00 More Stuff to do",date:new Date(y,m,randInt(7)+14),className:"task--info",len:randInt(4)+1,detailHeader:"Difficult",detailContent:"But not especially so"},
{title:"All day task",date:new Date(y,m,randInt(7)+21),className:"task--danger",len:1,vlen:2},
];
//This is where you calc the row/col to put each dated item
for (let i of items) {
let rc = findRowCol(i.date);
if (rc == null) {
console.log('didn`t find date for ',i);
console.log(i.date);
console.log(days);
i.startCol = i.startRow = 0;
} else {
i.startCol = rc.col;
i.startRow = rc.row;
}
}
}
$: month,year,initContent();
// choose what date/day gets displayed in each date box.
function initContent() {
headers = labels;
initMonth();
initMonthItems();
}
function initMonth() {
days = [];
let monthAbbrev = months[month].slice(0,3);
let nextMonthAbbrev = months[(month+1)%12].slice(0,3);
// find the last Monday of the previous month
var firstDay = new Date(year, month, 1).getDay();
//console.log('fd='+firstDay+' '+dayNames[firstDay]);
var daysInThisMonth = new Date(year, month+1, 0).getDate();
var daysInLastMonth = new Date(year, month, 0).getDate();
var prevMonth = month==0 ? 11 : month-1;
// show the days before the start of this month (disabled) - always less than 7
for (let i=daysInLastMonth-firstDay;i<daysInLastMonth;i++) {
let d = new Date(prevMonth==11?year-1:year,prevMonth,i+1);
days.push({name:''+(i+1),enabled:false,date:d,});
}
// show the days in this month (enabled) - always 28 - 31
for (let i=0;i<daysInThisMonth;i++) {
let d = new Date(year,month,i+1);
if (i==0) days.push({name:monthAbbrev+' '+(i+1),enabled:true,date:d,});
else days.push({name:''+(i+1),enabled:true,date:d,});
//console.log('i='+i+' dt is '+d+' date() is '+d.getDate());
}
// show any days to fill up the last row (disabled) - always less than 7
for (let i=0;days.length%7;i++) {
let d = new Date((month==11?year+1:year),(month+1)%12,i+1);
if (i==0) days.push({name:nextMonthAbbrev+' '+(i+1),enabled:false,date:d,});
else days.push({name:''+(i+1),enabled:false,date:d,});
}
}
function findRowCol(dt:Date) {
for (let i=0;i<days.length;i++) {
let d = days[i].date;
if (d.getFullYear() === dt.getFullYear()
&& d.getMonth() === dt.getMonth()
&& d.getDate() === dt.getDate())
return {row:Math.floor(i/7)+2,col:i%7+1};
}
return null;
}
function itemClick(e: { date: { toString: () => string; }; }) {
eventText='itemClick '+JSON.stringify(e) + ' localtime='+e.date.toString();
}
function dayClick(e: { date: { toString: () => string; }; }) {
eventText='onDayClick '+JSON.stringify(e) + ' localtime='+e.date.toString();
}
function headerClick(e: any) {
eventText='onHheaderClick '+JSON.stringify(e);
}
function next() {
month++;
if (month == 12) {
year++;
month=0;
}
}
function prev() {
if (month==0) {
month=11;
year--;
} else {
month--;
}
}
</script>
<div class="calendar-container">
<div class="calendar-header">
<h1>
<button on:click={()=>year--}>&Lt;</button>
<button on:click={()=>prev()}>&lt;</button>
{months[month]} {year+ (buddhist?543:0)}
<button on:click={()=>next()}>&gt;</button>
<button on:click={()=>year++}>&Gt;</button>
</h1>
{eventText}
</div>
<Calendar
{headers}
{days}
{items}
on:dayClick={(e)=>dayClick(e.detail)}
on:itemClick={(e)=>itemClick(e.detail)}
on:headerClick={(e)=>headerClick(e.detail)}
/>
</div>
<style>
.calendar-container {
width: 100%;
margin: auto;
overflow: hidden;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1);
border-radius: 10px;
background: #fff;
max-width: 1200px;
}
.calendar-header {
text-align: center;
padding: 20px 0;
background: #eef;
border-bottom: 1px solid rgba(166, 168, 179, 0.12);
}
.calendar-header h1 {
margin: 0;
font-size: 18px;
}
.calendar-header button {
background: #eef;
border: 1px ;
padding: 6;
color: rgba(81, 86, 93, 0.7);
cursor: pointer;
outline: 0;
}
</style>

View file

@ -1,222 +0,0 @@
<div class="calendar">
{#each headers as header}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span class="day-name" on:click={()=>dispatch('headerClick',header)}>{header}</span>
{/each}
{#each days as day}
{#if day.enabled}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span class="day" on:click={()=>dispatch('dayClick',day)}>{day.name}</span>
{:else}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<span class="day day-disabled" on:click={()=>dispatch('dayClick',day)}>{day.name}</span>
{/if}
{/each}
{#each items as item}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<section
on:click={()=>dispatch('itemClick',item)}
class="task {item.className}"
style="grid-column: {item.startCol} / span {item.len};
grid-row: {item.startRow};
align-self: {item.isBottom?'end':'center'};"
>
{item.title}
{#if item.detailHeader}
<div class="task-detail">
<h2>{item.detailHeader}</h2>
<p>{item.detailContent}</p>
</div>
{/if}
</section>
{/each}
</div>
<script>
import {createEventDispatcher, onMount} from 'svelte';
/**
* @type {any[]}
*/
export var headers = [];
/**
* @type {any[]}
*/
export let days = [];
/**
* @type {any[]}
*/
export let items = [];
let dispatch = createEventDispatcher();
</script>
<style>
.calendar {
display: grid;
width: 100%;
grid-template-columns: repeat(7, minmax(120px, 1fr));
grid-template-rows: 50px;
grid-auto-rows: 120px;
overflow: auto;
}
.day {
border-bottom: 1px solid rgba(166, 168, 179, 0.12);
border-right: 1px solid rgba(166, 168, 179, 0.12);
text-align: right;
padding: 14px 20px;
letter-spacing: 1px;
font-size: 14px;
box-sizing: border-box;
color: #98a0a6;
position: relative;
z-index: 1;
}
.day:nth-of-type(7n + 7) {
border-right: 0;
}
.day:nth-of-type(n + 1):nth-of-type(-n + 7) {
grid-row: 1;
}
.day:nth-of-type(n + 8):nth-of-type(-n + 14) {
grid-row: 2;
}
.day:nth-of-type(n + 15):nth-of-type(-n + 21) {
grid-row: 3;
}
.day:nth-of-type(n + 22):nth-of-type(-n + 28) {
grid-row: 4;
}
.day:nth-of-type(n + 29):nth-of-type(-n + 35) {
grid-row: 5;
}
.day:nth-of-type(n + 36):nth-of-type(-n + 42) {
grid-row: 6;
}
.day:nth-of-type(7n + 1) {
grid-column: 1/1;
}
.day:nth-of-type(7n + 2) {
grid-column: 2/2;
}
.day:nth-of-type(7n + 3) {
grid-column: 3/3;
}
.day:nth-of-type(7n + 4) {
grid-column: 4/4;
}
.day:nth-of-type(7n + 5) {
grid-column: 5/5;
}
.day:nth-of-type(7n + 6) {
grid-column: 6/6;
}
.day:nth-of-type(7n + 7) {
grid-column: 7/7;
}
.day-name {
font-size: 12px;
text-transform: uppercase;
color: #e9a1a7;
text-align: center;
border-bottom: 1px solid rgba(166, 168, 179, 0.12);
line-height: 50px;
font-weight: 500;
}
.day-disabled {
color: rgba(152, 160, 166, 0.5);
background-color: #ffffff;
background-image: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23fdf9ff' fill-opacity='1' fill-rule='evenodd'%3E%3Cpath d='M0 40L40 0H20L0 20M40 40V20L20 40'/%3E%3C/g%3E%3C/svg%3E");
cursor: not-allowed;
}
.task {
border-left-width: 3px;
padding: 8px 12px;
margin: 10px;
border-left-style: solid;
font-size: 14px;
position: relative;
align-self: center;
z-index:2;
border-radius: 15px;
}
.task--warning {
border-left-color: #fdb44d;
background: #fef0db;
color: #fc9b10;
margin-top: -5px;
}
.task--danger {
border-left-color: #fa607e;
grid-column: 2 / span 3;
grid-row: 3;
margin-top: 15px;
background: rgba(253, 197, 208, 0.7);
color: #f8254e;
}
.task--info {
border-left-color: #4786ff;
margin-top: 15px;
background: rgba(218, 231, 255, 0.7);
color: #0a5eff;
}
.task--primary {
background: #4786ff;
border: 0;
border-radius: 14px;
color: #f00;
box-shadow: 0 10px 14px rgba(71, 134, 255, 0.4);
}
.task-detail {
position: absolute;
left: 0;
top: calc(100% + 8px);
background: #efe;
border: 1px solid rgba(166, 168, 179, 0.2);
color: #100;
padding: 20px;
box-sizing: border-box;
border-radius: 14px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08);
z-index: 2;
}
.task-detail:after, .task-detail:before {
bottom: 100%;
left: 30%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.task-detail:before {
border-bottom-color: rgba(166, 168, 179, 0.2);
border-width: 8px;
margin-left: -8px;
}
.task-detail:after {
border-bottom-color: #fff;
border-width: 6px;
margin-left: -6px;
}
.task-detail h2 {
font-size: 15px;
margin: 0;
color: #91565d;
}
.task-detail p {
margin-top: 4px;
font-size: 12px;
margin-bottom: 0;
font-weight: 500;
color: rgba(81, 86, 93, 0.7);
}
</style>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB