diff options
author | polwex <polwex@sortug.com> | 2025-06-27 22:53:52 +0700 |
---|---|---|
committer | polwex <polwex@sortug.com> | 2025-06-27 22:53:52 +0700 |
commit | 328ebe85135912678bdacd3381126ffd66ef2761 (patch) | |
tree | 365962bf45302f2a440f766a4f3c9e0a962dbe47 /desk/web/calendar |
init
Diffstat (limited to 'desk/web/calendar')
-rw-r--r-- | desk/web/calendar/cal/day.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/cal/event.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/cal/month.hoon | 321 | ||||
-rw-r--r-- | desk/web/calendar/cal/new.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/cal/week.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/cal/year.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/day.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/event.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/main.hoon | 77 | ||||
-rw-r--r-- | desk/web/calendar/month.hoon | 326 | ||||
-rw-r--r-- | desk/web/calendar/new.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/notes.hoon | 100 | ||||
-rw-r--r-- | desk/web/calendar/router.hoon | 66 | ||||
-rw-r--r-- | desk/web/calendar/todo.hoon | 6 | ||||
-rw-r--r-- | desk/web/calendar/week.hoon | 0 | ||||
-rw-r--r-- | desk/web/calendar/year.hoon | 0 |
16 files changed, 896 insertions, 0 deletions
diff --git a/desk/web/calendar/cal/day.hoon b/desk/web/calendar/cal/day.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/day.hoon diff --git a/desk/web/calendar/cal/event.hoon b/desk/web/calendar/cal/event.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/event.hoon diff --git a/desk/web/calendar/cal/month.hoon b/desk/web/calendar/cal/month.hoon new file mode 100644 index 0000000..1a6ec3f --- /dev/null +++ b/desk/web/calendar/cal/month.hoon @@ -0,0 +1,321 @@ +/+ sr=sortug +|_ =bowl:gall +++ css ^~ %- trip +''' +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; + margin: 10vh auto; + max-width: 120ch; + background: #fffff4; + color: #140; +} + +h1 { + font-size: 1.2rem; + font-weight: bold; +} + +input, +button { + border: none; + color: inherit; + font: inherit; +} +input { + background: none; +} +input:focus-visible { + outline: solid 1px #140; +} +button { + background: #261; + color: white; + font-weight: bold; + border-radius: 0.25rem; +} +button:hover, +button:focus-visible { + background: #483; +} + +.month-control { + display: flex; +} +.month-control h2 { + font-size: 1rem; + font-weight: bold; + margin: 0; + margin-inline-end: auto; +} +.month-control a { + flex: 0 1 6ch; + text-align: end; + font-weight: bold; + color: inherit; +} + +table { + padding: 0; + width: 100%; + height: 100%; + & th{ + opacity: 0.6; + text-align: center; + padding: 0.5rem 0; + } + & td{ + border-top: solid 1px currentColor; + min-width: 0; + min-height: 8rem; + height: 4rem; + + } +} + + +.day-weekend { + color: #c88; +} +.day-past { + color: #2423; +} + +.date { + height: 100%; + display: flex; + flex-direction: column; +} +.date ul { + padding: 0; + list-style: none; +} + +.date-num { + aspect-ratio: 1; + border-radius: 100rem; + background: #fffff4; + position: absolute; + z-index: 1; +} +.day-today .date-num { + padding: 0 0.125em; + background: #220; + color: white; +} + +.create-event-form { + flex: 1 1 auto; + margin: 0; +} +.create-event { + background: none; + color: transparent; + width: 100%; + height: 100%; + cursor: crosshair; +} +.create-event:hover, +.create-event:focus-visible { + background: #efe4; +} +.create-event:focus-visible { + color: #140; +} + +.event { + margin: 0.25rem 0.5rem; +} +.event:first-child { + margin-top: 0.5rem; +} + +.event > form { + display: flex; + margin: 0; +} + +.event-button { + position: relative; + flex: 1 1 auto; + padding: 0.25rem; + background: white; + color: #000b; + border-radius: 0.25rem; + text-wrap: nowrap; + text-overflow: ellipsis; + overflow: hidden; + text-align: start; + font-size: 0.8rem; + font-weight: bold; + text-decoration: none; +} +.event-button::after { + content: ""; + position: absolute; + inset: 0; +} +.event-button:hover::after, +.event-button:focus-visible::after { + background: #fff4; +} +.day-past .event:not(:focus-within):not(:has(dialog[open])) .event-button { + opacity: 0.4; +} + +.event dialog { + inset: unset; + margin-top: 0.3rem; + padding: 0.75rem; + background: white; + border: solid 1px #ceb; + box-shadow: 0 0.25rem 0.5rem #0301, 0 0rem 2rem #0301; + z-index: 9999; +} +.event dialog::after { + content: ''; + position: absolute; + left: 0.4rem; + top: calc(-0.3rem - 2px); + width: 0.6rem; + height: 0.6rem; + transform: rotate(45deg); + background: inherit; + border: inherit; + border-right: none; + border-bottom: none; +} + +.event dialog form { + margin: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.event-dialog-row { + display: flex; + gap: 0.5rem; +} + +.event input[type="text"] { + border-bottom: solid 1px currentColor; + max-width: 15ch; +} + +.delete-button { + background: #820; +} +.delete-button:hover, +.delete-button:focus-visible { + background: #a42; +} +''' +++ html +|= time=@da ^- manx +=, chrono:userlib +=/ dat (yore time) +=+ [[a y] m [d h mm s f]]=dat +=/ mon %+ snag (dec m) mon:yu +=/ nmon %+ snag m mon:yu +=/ pmon =/ ind ?: .=(1 m) 11 (sub m 2) + %+ snag ind mon:yu +=/ year (scow:parsing:sr %ud y) +=/ nyear (scow:parsing:sr %ud +(y)) +=/ pyear (scow:parsing:sr %ud (dec y)) +=/ weekday %+ snag (daws dat) wik:yu +:: =/ weeknames (snoc +.wik:yu -.wik:yu) +=/ weeknames wik:yu +=/ first-of-month dat(d.t 1) +=/ month-starts-at (daws first-of-month) +;div#month.month + ;style: {css} + ;div.month-control + ;h2.current-month:"{mon} {year}" + ;a/"":"<- {pmon}" + ;a/"":"{nmon} ->" + == + ;table + ;tr + ;* %+ turn weeknames |= t=tape ;th.wday-name:"{t}" + == + ;* %+ turn (get-nums time) |= l=(list date) + ;tr + ;* %+ turn l cell + == + == +== ++$ row (list date) +++ get-nums +|= =time ^- (list row) +=, chrono:userlib + =/ =date (yore time) + =+ [[a y] m [d h mm s f]]=date + =/ first-of-month date(d.t 1) + =/ first-day (year first-of-month) + =/ month-start (daws first-of-month) + ~& month-start=month-start + =| l=(list row) + =| i=@ud + |- + =/ dat + ?: (gth month-start i) + =/ diff (sub month-start i) + =/ back (sub first-day (mul ~d1 diff)) + (yore back) + + =/ curr (sub i month-start) + (yore (add first-day (mul ~d1 curr))) + :: =/ nm m.added + :: =/ to-next-month (gth nm m) + :: ?: to-next-month added curr + + ?~ l $(l [~[dat] l], i +(i)) + + ?. .=(0 (mod i 7)) + =. i.l [dat i.l] + $(i +(i)) + + =. i.l (flop i.l) + =/ curr (sub i month-start) + =/ added (yore (add first-day (mul ~d1 curr))) + =/ nm m.added + =/ to-next-month (gth nm m) + ?: to-next-month (flop l) + =/ nrow ~[added] + + $(l [nrow l], i +(i)) + :: exit-condition + +++ cell +|= =date ^- manx + =/ [faded=? today=?] [.n .n] + =/ nums (scow %ud d.t.date) + ?: faded + :: + ;td.faded + ;div:"{nums}" + == + ?: today + ;td.today + ;div:"{nums}" + == + :: + ;td + ;div:"{nums}" + == + :: +++ get-num +|= [feira=@ud =time] ^- @ud +=, chrono:userlib + =/ date (yore time) + =/ first-of-month date(d.t 1) + =/ month-starts-at (daws first-of-month) + ?: (lth feira month-starts-at) + =/ diff (sub month-starts-at feira) + =/ back (sub time (mul ~d1 diff)) + d.t:(yore back) + :: e.g. month starts in day 3 (thu) and we're in day 4 (fri) + =/ diff (sub feira month-starts-at) + +(diff) +-- diff --git a/desk/web/calendar/cal/new.hoon b/desk/web/calendar/cal/new.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/new.hoon diff --git a/desk/web/calendar/cal/week.hoon b/desk/web/calendar/cal/week.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/week.hoon diff --git a/desk/web/calendar/cal/year.hoon b/desk/web/calendar/cal/year.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/cal/year.hoon diff --git a/desk/web/calendar/day.hoon b/desk/web/calendar/day.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/day.hoon diff --git a/desk/web/calendar/event.hoon b/desk/web/calendar/event.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/event.hoon diff --git a/desk/web/calendar/main.hoon b/desk/web/calendar/main.hoon new file mode 100644 index 0000000..bc8e5c2 --- /dev/null +++ b/desk/web/calendar/main.hoon @@ -0,0 +1,77 @@ +/- boke +|_ [s=state:boke =bowl:gall] +++ css ^~ %- trip +''' +html, body, main{ + height: 100%; + overflow-y: hidden; +} +main{ + display: flex; + & #icons{ + width: 5%; + border-right: 1px solid black; + & img{ + display:block; + margin: auto; + cursor: pointer; + width: 30px; + } + } +} +.scroll{ + height: 100%; + overflow-y: auto; +} +#main{ + display: flex; + width: 95%; +} +''' +++ $ ^- manx +;html +=data-theme "light" + ;head + ;meta(charset "utf-8"); + ;meta(name "viewport", content "width=device-width, initial-scale=1, shrink-to-fit=no"); + ;title:"Sorcal" + ;style:"{css}" + == + ;body + ;main + ;div#icons + =kaji "scry" + =swap "swap" + =targ "#main" + ;img@"https://s3.sortug.com/img/icons/notes.svg" + =path "/cal/f/notes" + ; + == + ;img@"https://s3.sortug.com/img/icons/todo.svg" + =path "/cal/f/todo" + ; + == + ;img@"https://s3.sortug.com/img/icons/calendar.svg" + =path "/cal/f/cal" + ; + == + ;select + =kaji "scry" + =path "/search/f" + =name "interval" + ;option + =value "all" + ; All time + == + ;option + =value "day" + :: =selected "" + ; Past 24h + == + == + == + ;div#main; + == + == +== +-- diff --git a/desk/web/calendar/month.hoon b/desk/web/calendar/month.hoon new file mode 100644 index 0000000..6a7d4a1 --- /dev/null +++ b/desk/web/calendar/month.hoon @@ -0,0 +1,326 @@ +/+ sr=sortug +|_ =bowl:gall +++ css ^~ %- trip +''' +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; + margin: 10vh auto; + max-width: 120ch; + background: #fffff4; + color: #140; +} + +h1 { + font-size: 1.2rem; + font-weight: bold; +} + +input, +button { + border: none; + color: inherit; + font: inherit; +} +input { + background: none; +} +input:focus-visible { + outline: solid 1px #140; +} +button { + background: #261; + color: white; + font-weight: bold; + border-radius: 0.25rem; +} +button:hover, +button:focus-visible { + background: #483; +} + +.month-control { + display: flex; +} +.month-control h2 { + font-size: 1rem; + font-weight: bold; + margin: 0; + margin-inline-end: auto; +} +.month-control a { + flex: 0 1 6ch; + text-align: end; + font-weight: bold; + color: inherit; +} + +table { + padding: 0; + width: 100%; + height: 100%; + & th{ + opacity: 0.6; + text-align: center; + padding: 0.5rem 0; + } + & td{ + border-top: solid 1px currentColor; + min-width: 0; + min-height: 8rem; + height: 4rem; + + } +} + + +.day-weekend { + color: #c88; +} +.day-past { + color: #2423; +} + +.date { + height: 100%; + display: flex; + flex-direction: column; +} +.date ul { + padding: 0; + list-style: none; +} + +.date-num { + aspect-ratio: 1; + border-radius: 100rem; + background: #fffff4; + position: absolute; + z-index: 1; +} +.day-today .date-num { + padding: 0 0.125em; + background: #220; + color: white; +} + +.create-event-form { + flex: 1 1 auto; + margin: 0; +} +.create-event { + background: none; + color: transparent; + width: 100%; + height: 100%; + cursor: crosshair; +} +.create-event:hover, +.create-event:focus-visible { + background: #efe4; +} +.create-event:focus-visible { + color: #140; +} + +.event { + margin: 0.25rem 0.5rem; +} +.event:first-child { + margin-top: 0.5rem; +} + +.event > form { + display: flex; + margin: 0; +} + +.event-button { + position: relative; + flex: 1 1 auto; + padding: 0.25rem; + background: white; + color: #000b; + border-radius: 0.25rem; + text-wrap: nowrap; + text-overflow: ellipsis; + overflow: hidden; + text-align: start; + font-size: 0.8rem; + font-weight: bold; + text-decoration: none; +} +.event-button::after { + content: ""; + position: absolute; + inset: 0; +} +.event-button:hover::after, +.event-button:focus-visible::after { + background: #fff4; +} +.day-past .event:not(:focus-within):not(:has(dialog[open])) .event-button { + opacity: 0.4; +} + +.event dialog { + inset: unset; + margin-top: 0.3rem; + padding: 0.75rem; + background: white; + border: solid 1px #ceb; + box-shadow: 0 0.25rem 0.5rem #0301, 0 0rem 2rem #0301; + z-index: 9999; +} +.event dialog::after { + content: ''; + position: absolute; + left: 0.4rem; + top: calc(-0.3rem - 2px); + width: 0.6rem; + height: 0.6rem; + transform: rotate(45deg); + background: inherit; + border: inherit; + border-right: none; + border-bottom: none; +} + +.event dialog form { + margin: 0; + display: flex; + flex-direction: column; + gap: 0.5rem; +} +.event-dialog-row { + display: flex; + gap: 0.5rem; +} + +.event input[type="text"] { + border-bottom: solid 1px currentColor; + max-width: 15ch; +} + +.delete-button { + background: #820; +} +.delete-button:hover, +.delete-button:focus-visible { + background: #a42; +} +''' +++ html +|= time=@da ^- manx +=, chrono:userlib +=/ dat (yore time) +=+ [[a y] m [d h mm s f]]=dat +=/ mon %+ snag (dec m) mon:yu +=/ nmon %+ snag m mon:yu +=/ pmon =/ ind ?: .=(1 m) 11 (sub m 2) + %+ snag ind mon:yu +=/ year (scow:parsing:sr %ud y) +=/ nyear (scow:parsing:sr %ud +(y)) +=/ pyear (scow:parsing:sr %ud (dec y)) +=/ weekday %+ snag (daws dat) wik:yu +:: =/ weeknames (snoc +.wik:yu -.wik:yu) +=/ weeknames wik:yu +=/ first-of-month dat(d.t 1) +=/ month-starts-at (daws first-of-month) +;html +;head; +;body +;style: {css} + ;div#month.month + ;div.month-control + ;h2.current-month:"{mon} {year}" + ;a/"":"<- {pmon}" + ;a/"":"{nmon} ->" + == + ;table + ;tr + ;* %+ turn weeknames |= t=tape ;th.wday-name:"{t}" + == + ;* %+ turn (get-nums time) |= l=(list date) + ;tr + ;* %+ turn l cell + == + == + == +== +== ++$ row (list date) +++ get-nums +|= =time ^- (list row) +=, chrono:userlib + =/ =date (yore time) + =+ [[a y] m [d h mm s f]]=date + =/ first-of-month date(d.t 1) + =/ first-day (year first-of-month) + =/ month-start (daws first-of-month) + ~& month-start=month-start + =| l=(list row) + =| i=@ud + |- + =/ dat + ?: (gth month-start i) + =/ diff (sub month-start i) + =/ back (sub first-day (mul ~d1 diff)) + (yore back) + + =/ curr (sub i month-start) + (yore (add first-day (mul ~d1 curr))) + :: =/ nm m.added + :: =/ to-next-month (gth nm m) + :: ?: to-next-month added curr + + ?~ l $(l [~[dat] l], i +(i)) + + ?. .=(0 (mod i 7)) + =. i.l [dat i.l] + $(i +(i)) + + =. i.l (flop i.l) + =/ curr (sub i month-start) + =/ added (yore (add first-day (mul ~d1 curr))) + =/ nm m.added + =/ to-next-month (gth nm m) + ?: to-next-month (flop l) + =/ nrow ~[added] + + $(l [nrow l], i +(i)) + :: exit-condition + +++ cell +|= =date ^- manx + =/ [faded=? today=?] [.n .n] + =/ nums (scow %ud d.t.date) + ?: faded + :: + ;td.faded + ;div:"{nums}" + == + ?: today + ;td.today + ;div:"{nums}" + == + :: + ;td + ;div:"{nums}" + == + :: +++ get-num +|= [feira=@ud =time] ^- @ud +=, chrono:userlib + =/ date (yore time) + =/ first-of-month date(d.t 1) + =/ month-starts-at (daws first-of-month) + ?: (lth feira month-starts-at) + =/ diff (sub month-starts-at feira) + =/ back (sub time (mul ~d1 diff)) + d.t:(yore back) + :: e.g. month starts in day 3 (thu) and we're in day 4 (fri) + =/ diff (sub feira month-starts-at) + +(diff) +-- diff --git a/desk/web/calendar/new.hoon b/desk/web/calendar/new.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/new.hoon diff --git a/desk/web/calendar/notes.hoon b/desk/web/calendar/notes.hoon new file mode 100644 index 0000000..6190e84 --- /dev/null +++ b/desk/web/calendar/notes.hoon @@ -0,0 +1,100 @@ +/- tp=trill-post +/+ ui=trill-ui +/+ kaji +|_ [notes=(list post:tp) =bowl:gall] + +++ css ^~ %- trip +''' +*{ + box-sizing: border-box; +} +#list{ + width: 20%; + border-right: 1px solid black; + & .entry{ + padding: 1rem; + cursor: pointer; + } +} +#composer{ + width: 80%; + & form{ + height: 100%; + padding: 2rem; + #inputs{ + height: 100%; + & input,textarea{ + display: block; + width: 100%; + outline: none; + } + #top{ + display: flex; + input[type=text]{ + font-size: 2rem; + font-weight: 700; + height: 2rem; + border: none; + margin-bottom: 1rem; + flex-grow: 1; + } + input[type=submit]{ + height: 2rem; + width: fit-content; + } + } + & textarea{ + height: 90%; + resize: none; + border: none; + } + } + } +} +''' +++ $ +;div + ;style: {css} + ;div#list.scroll + =kaji "scry" + =targ "#inputs" + ;* %+ turn notes note-preview + == + ;div#composer + ;form + =kaji "poke" + =action "save-note" + ;div#inputs + ;div#top + ;input(type "text", value "Title"); + ;input(type "submit", value "Save"); + == + ;textarea(name "text") + ; This is a Markdown note + == + == + == + == +== +++ note-preview +|= n=post:tp +=/ id (enc:kaji [author.n id.n]) +;div.entry + =path "/cal/f/note/{id}" + ; {(trip title.n)} +== +++ note +|= n=post:tp ^- manx +=/ pid-string (enc:kaji [author.n id.n]) +=/ post-text (content-to-md:ui contents.n) +;div + ;div#top + ;input(type "hidden", name "pid", value pid-string); + ;input(type "text", value (trip title.n)); + ;input(type "submit", value "Save"); + == + ;textarea(name "text") + ; {post-text} + == +== +-- diff --git a/desk/web/calendar/router.hoon b/desk/web/calendar/router.hoon new file mode 100644 index 0000000..793f946 --- /dev/null +++ b/desk/web/calendar/router.hoon @@ -0,0 +1,66 @@ +/- boke, tp=trill-post, cnt=contact +/+ kaji, fetch-lib=fetch, plib=trill-utils, const=constants, sr=sortug, lib=boke, ui=trill-ui +/= index /web/index +/= main /web/calendar/main +/= notes /web/calendar/notes +/= todo /web/calendar/todo +/= cal /web/calendar/cal/month + +|_ [rl=req-line:kaji s=state:boke =bowl:gall] ++* fetch ~(. fetch-lib [s bowl]) +++ eyre-bail (error-response:kaji 404) +++ manx-bail (error-page:kaji 404) +:: +++ $ ^- eyre-res:kaji + ~& >> routing-cal=rl + =/ p pat.rl ::?. mob.rl pat.rl [%m pat.rl] + ?+ p eyre-bail + ~ root + [%f rest=*] :- %html (fragment rest.p) + == +++ root + :- %page (main s bowl) + +++ fragment +|= p=(pole knot) +=/ st s + ?+ p manx-bail + [%notes ~] (notes note-list bowl) + [%todo ~] (todo st bowl) + [%cal ~] (~(html cal bowl) now.bowl) + :: + [%note uid=@t ~] (note uid.p) + [%todo uid=@t ~] manx-bail + [%cal %day uid=@t ~] manx-bail + [%cal %week uid=@t ~] manx-bail + [%cal %month uid=@t ~] manx-bail + [%cal %event uid=@t ~] manx-bail + == +++ note |= uid=@t ^- manx + =/ upid (dec:kaji uid pid:tp) + ?~ upid manx-bail + =/ =post:tp (make-note 'rofl') + (note:notes post) + +++ note-list ^- (list post:tp) + %+ turn ~['Note 1' 'Lol' 'Hoon' 'Blog ideas' 'lmao'] + make-note +++ make-note + |= t=@t ^- post:tp + =/ tokens (tokenize:ui t) + =/ tags (silt ~[t 'note']) + =/ p (build-post:lib tokens tags [our.bowl now.bowl]) + p(title t) ++$ task + $: title=@t + desc=paragraph:tp + priority=@ud + status=$?(%todo %wip %done) + created=@da + due=((mop @da @da) gth) + creator=@p + subtasks=$~(~ (list task)) + workers=(map @p @t) :: who's doing what + tags=(set @t) + == +-- diff --git a/desk/web/calendar/todo.hoon b/desk/web/calendar/todo.hoon new file mode 100644 index 0000000..311c59e --- /dev/null +++ b/desk/web/calendar/todo.hoon @@ -0,0 +1,6 @@ +|_ [s=* =bowl:gall] +++ $ +;div#todo + ;p: hi +== +-- diff --git a/desk/web/calendar/week.hoon b/desk/web/calendar/week.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/week.hoon diff --git a/desk/web/calendar/year.hoon b/desk/web/calendar/year.hoon new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/desk/web/calendar/year.hoon |