forked from tsai/budibase
14 changed files with 344 additions and 12 deletions
@ -1,10 +1,31 @@ |
|||||
<script> |
<script> |
||||
import { getContext } from "svelte" |
import { getContext } from "svelte" |
||||
|
import ripple from "../Ripple.js" |
||||
|
|
||||
|
export let onClick = null |
||||
export let icon = "" |
export let icon = "" |
||||
export let context = "" |
export let context = "" |
||||
|
|
||||
let cls = !!context ? `material-icons mdc-${context}__icon` : "material-icons" |
let cls = !!context ? `material-icons mdc-${context}__icon` : "material-icons" |
||||
|
|
||||
|
$: useRipple = onClick !== null |
||||
</script> |
</script> |
||||
|
|
||||
<i class={cls}>{icon}</i> |
<i class={cls}>{icon}</i> |
||||
|
{#if useRipple} |
||||
|
<div use:ripple> |
||||
|
<i on:click={onClick} class={cls}>{icon}</i> |
||||
|
</div> |
||||
|
{:else} |
||||
|
<i class={cls}>{icon}</i> |
||||
|
{/if} |
||||
|
|
||||
|
<style> |
||||
|
div { |
||||
|
border-radius: 50%; |
||||
|
padding-top: 2px; |
||||
|
width: fit-content; |
||||
|
height: fit-content; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
</style> |
||||
|
|||||
@ -1,10 +1,185 @@ |
|||||
<script> |
<script> |
||||
import { Menu } from "../Menu" |
import { onMount } from "svelte"; |
||||
import { Textfield } from "../Textfield" |
import { |
||||
|
startOfMonth, |
||||
|
endOfMonth, |
||||
|
getDate, |
||||
|
getMonth, |
||||
|
getYear, |
||||
|
addMonths, |
||||
|
subMonths, |
||||
|
format |
||||
|
} from "date-fns"; |
||||
|
import { MDCMenu } from "@material/menu"; |
||||
|
import { Textfield } from "../Textfield"; |
||||
|
import Icon from "../Common/Icon.svelte"; |
||||
|
import ripple from "../Ripple.js"; |
||||
|
import { Body1, Body2, Caption } from "../Typography"; |
||||
|
|
||||
let open = false |
let textFieldHeight = null; |
||||
debugger |
let menu; |
||||
|
let instance; |
||||
|
|
||||
|
let daysArr = []; |
||||
|
let navDate = new Date(); |
||||
|
const weekdayMap = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; |
||||
|
|
||||
|
export let date = new Date(); |
||||
|
export let open = true; |
||||
|
|
||||
|
onMount(() => { |
||||
|
if (!!menu) { |
||||
|
instance = new MDCMenu(menu); |
||||
|
instance.open = true; |
||||
|
instance.setFixedPostion = true; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
function selectDate(dayOfMonth) { |
||||
|
let month = getMonth(navDate); |
||||
|
let year = getYear(navDate); |
||||
|
date = new Date(year, month, dayOfMonth); |
||||
|
} |
||||
|
|
||||
|
function addMonth() { |
||||
|
navDate = addMonths(navDate, 1); |
||||
|
} |
||||
|
|
||||
|
function subtractMonth() { |
||||
|
navDate = subMonths(navDate, 1); |
||||
|
} |
||||
|
|
||||
|
function openCalendar() { |
||||
|
instance.open = true; |
||||
|
} |
||||
|
|
||||
|
$: dateMonthEnds = endOfMonth(navDate).getDate(); |
||||
|
$: dateMonthBegins = startOfMonth(navDate).getDay(); |
||||
|
$: dayStart = dateMonthBegins + 1; //1 = sunday |
||||
|
$: monthAndYear = format(navDate, "MMMM y"); |
||||
|
$: selectedDate = format(date, "dd/MM/yyyy"); |
||||
|
$: dayOfSelectedDate = getDate(date); |
||||
|
$: for (let d = 1; d <= dateMonthEnds; d++) { |
||||
|
if (d === 1) { |
||||
|
daysArr = [d]; |
||||
|
} else { |
||||
|
daysArr = [...daysArr, d]; |
||||
|
} |
||||
|
} |
||||
|
$: rowRepeater = |
||||
|
dateMonthBegins > 5 && daysArr[daysArr.length - 1] > 30 ? 6 : 5; |
||||
|
$: sameMonthAndYear = |
||||
|
getMonth(date) === getMonth(navDate) && getYear(date) === getYear(navDate); |
||||
|
debugger; |
||||
</script> |
</script> |
||||
|
|
||||
<Textfield label="Select Date" /> |
<style> |
||||
<Menu {open} /> |
.bbmd-menu { |
||||
|
width: 310px; |
||||
|
height: auto; |
||||
|
padding: 5px; |
||||
|
} |
||||
|
|
||||
|
.month-picker { |
||||
|
display: grid; |
||||
|
grid-template-columns: 20px 1fr 20px; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.month-picker > span { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.calendar-container { |
||||
|
display: grid; |
||||
|
height: 100%; |
||||
|
grid-template-rows: repeat(3, auto); |
||||
|
grid-gap: 5px; |
||||
|
} |
||||
|
|
||||
|
.calendar-container > div { |
||||
|
/* border: 1px solid red; */ |
||||
|
} |
||||
|
|
||||
|
.week-days { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(7, 1fr); |
||||
|
} |
||||
|
|
||||
|
.day-picker { |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(7, 1fr); |
||||
|
} |
||||
|
|
||||
|
.centreText { |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
span { |
||||
|
margin: auto; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
<!-- |
||||
|
TODO: Add trailing icon button on textfield that is clickable |
||||
|
TODO: Add transition effects to toggling of calendar |
||||
|
TODO: Bug - August 2020 has too many rows. find out why |
||||
|
TODO: Bug - make out transition of date bg colour instantaneous |
||||
|
--> |
||||
|
<div class="mdc-menu-surface--anchor"> |
||||
|
<Textfield |
||||
|
bind:tfHeight={textFieldHeight} |
||||
|
value={selectedDate} |
||||
|
trailingIcon={true} |
||||
|
useIconButton={true} |
||||
|
iconButtonClick={openCalendar} |
||||
|
icon="calendar_today" |
||||
|
label="Select Date" /> |
||||
|
|
||||
|
<div |
||||
|
bind:this={menu} |
||||
|
class="mdc-menu mdc-menu-surface bbmd-menu" |
||||
|
style={`margin-top: ${textFieldHeight + 15}px`}> |
||||
|
<div class="calendar-container"> |
||||
|
<div class="month-picker"> |
||||
|
<span> |
||||
|
<Icon icon="chevron_left" onClick={subtractMonth} /> |
||||
|
</span> |
||||
|
<div class="centreText"> |
||||
|
<Body1 text={monthAndYear} /> |
||||
|
</div> |
||||
|
<span> |
||||
|
<Icon icon="chevron_right" onClick={addMonth} /> |
||||
|
</span> |
||||
|
</div> |
||||
|
<div class="week-days"> |
||||
|
{#each weekdayMap as day, i} |
||||
|
<div class="centreText"> |
||||
|
<Caption text={day} /> |
||||
|
</div> |
||||
|
{/each} |
||||
|
</div> |
||||
|
<div |
||||
|
class="day-picker" |
||||
|
style={`grid-template-rows: repeat(${rowRepeater}, 40px)`}> |
||||
|
{#each daysArr as day, i} |
||||
|
<div |
||||
|
use:ripple |
||||
|
on:click={() => selectDate(day)} |
||||
|
class={`bbmd-day ${dayOfSelectedDate === day && sameMonthAndYear ? 'selected' : ''}`}> |
||||
|
{#if i === 0} |
||||
|
<div style={`grid-column-start: ${dateMonthBegins}`}> |
||||
|
<Body2 text={day} /> |
||||
|
</div> |
||||
|
{:else} |
||||
|
<Body2 text={day} /> |
||||
|
{/if} |
||||
|
</div> |
||||
|
{/each} |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<ul class="mdc-list" role="menu" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
|||||
@ -0,0 +1,15 @@ |
|||||
|
@import "@material/ripple/mdc-ripple.scss"; |
||||
|
@import "@material/theme/mixins"; |
||||
|
|
||||
|
.bbmd-day { |
||||
|
transition: background-color 0.5s ease-in; |
||||
|
display: flex; |
||||
|
border-radius: 50%; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.selected { |
||||
|
@include mdc-theme-prop(background-color, primary); |
||||
|
@include mdc-theme-prop(color, on-primary); |
||||
|
} |
||||
@ -1 +1,2 @@ |
|||||
export { default as DatePicker } from "./DatePicker.svelte" |
import "./_style.scss"; |
||||
|
export { default as DatePicker } from "./DatePicker.svelte"; |
||||
|
|||||
@ -0,0 +1,40 @@ |
|||||
|
<script> |
||||
|
import ripple from "../Ripple.js"; |
||||
|
import ClassBuilder from "../ClassBuilder.js"; |
||||
|
|
||||
|
const cb = new ClassBuilder("icon-button"); |
||||
|
|
||||
|
export let onClick = () => {}; |
||||
|
export let disabled = false; |
||||
|
export let href = ""; |
||||
|
export let icon = ""; |
||||
|
export let onIcon = ""; //on state icon for toggle button |
||||
|
export let size = "medium"; |
||||
|
|
||||
|
$: isToggleButton = !!icon && !!onIcon; |
||||
|
$: useLinkButton = !!href; |
||||
|
|
||||
|
$: customs = { size }; |
||||
|
$: props = { customs, extras: ["material-icons"] }; |
||||
|
$: iconBtnClass = cb.build({ props }); |
||||
|
</script> |
||||
|
|
||||
|
{#if useLinkButton} |
||||
|
<a on:click={onClick} class={iconBtnClass} {href} {disabled}> |
||||
|
{#if isToggleButton} |
||||
|
<i class="material-icons mdc-icon-button__icon mdc-icon-button__icon--on"> |
||||
|
{onIcon} |
||||
|
</i> |
||||
|
<i class="material-icons mdc-icon-button__icon">{icon}</i> |
||||
|
{:else}{icon}{/if} |
||||
|
</a> |
||||
|
{:else} |
||||
|
<button on:click={onClick} use:ripple class={iconBtnClass} {disabled}> |
||||
|
{#if isToggleButton} |
||||
|
<i class="material-icons mdc-icon-button__icon mdc-icon-button__icon--on"> |
||||
|
{onIcon} |
||||
|
</i> |
||||
|
<i class="material-icons mdc-icon-button__icon">{icon}</i> |
||||
|
{:else}{icon}{/if} |
||||
|
</button> |
||||
|
{/if} |
||||
@ -0,0 +1,13 @@ |
|||||
|
@import "@material/icon-button/mdc-icon-button"; |
||||
|
|
||||
|
.bbmd-mdc-icon-button--size-large { |
||||
|
@include mdc-icon-button-icon-size(24px); |
||||
|
} |
||||
|
|
||||
|
.bbmd-mdc-icon-button--size-medium { |
||||
|
@include mdc-icon-button-icon-size(20px); |
||||
|
} |
||||
|
|
||||
|
.bbmd-mdc-icon-button--size-small { |
||||
|
@include mdc-icon-button-icon-size(16px); |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
import "./_style.scss"; |
||||
|
export { default as IconButton } from "./IconButton.svelte"; |
||||
Loading…
Reference in new issue