Merge branch 'main' into consolidate-cards
* main: (45 commits) Fix tests Rework min card design and meta section for all cards Move `title` to the `img` element so we get hover in both cases Remove sorting filter UI Sort Considering and Doing by `updated_at` Restore comment action icon Fix dot escaping container Seen cards should be flat Ensure overflow cards are hidden Arrow needs to match derived color Dialog target needs to be present This isn't necessary in the mini card template Revert "The button and dialog need not render in previews" Paginate collection cards Add a rails helper for the new custom stream action Add test Reflect picked color automatically with a custom stream action Simplify conditions to pick up a color Reuse existing constant Update fixtures and test ...
@@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3,22V8H7V22H3M10,22V2H14V22H10M17,22V14H21V22H17Z" /></svg>
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3 22v-14h4v14zm7 0v-20h4v20zm7 0v-8h4v8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 129 B After Width: | Height: | Size: 119 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m23.119 20-9.347-17.85a2 2 0 0 0 -3.543 0l-9.348 17.85a2 2 0 0 0 1.772 2.928h18.694a2 2 0 0 0 1.772-2.928zm-12.119-11.577a1 1 0 0 1 2 0v6a1 1 0 1 1 -2 0zm1.05 11.51h-.028a1.528 1.528 0 0 1 -1.522-1.47 1.476 1.476 0 0 1 1.448-1.53h.028a1.527 1.527 0 0 1 1.524 1.467 1.475 1.475 0 0 1 -1.45 1.533z"/></svg>
|
||||
|
Before Width: | Height: | Size: 373 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 990 990" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h990v990h-990z" fill="none"/><path d="m391.65 879.47c-110.52-15.95-212.21-91.86-255.92-191.23-66.78-143.65-41.62-347.61 48.08-481.17 368.33-516.3 1252.97 520.2 451.03 660.78-44.07 8.84-88.98 13.49-133.01 15.68-36.69 2-73.37 1.91-109.99-4.03z"/></svg>
|
||||
|
Before Width: | Height: | Size: 325 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>calendar-add-1</title><path d="M9.569,16.5H2.5A.5.5,0,0,1,2,16V7.5A.5.5,0,0,1,2.5,7H16a.5.5,0,0,1,.5.5V9.57a7.281,7.281,0,0,1,2,0V3a1,1,0,0,0-1-1H15a.25.25,0,0,1-.25-.25v-1a.75.75,0,1,0-1.5,0V4.5a.75.75,0,1,1-1.5,0v-2a.5.5,0,0,0-.5-.5H7a.25.25,0,0,1-.25-.25v-1a.75.75,0,0,0-1.5,0V4.5a.75.75,0,1,1-1.5,0v-2a.5.5,0,0,0-.5-.5H1A1,1,0,0,0,0,3V16.5a2,2,0,0,0,2,2H9.569a7.281,7.281,0,0,1,0-2Z"/><path d="M17.5,11A6.5,6.5,0,1,0,24,17.5,6.508,6.508,0,0,0,17.5,11Zm.75,9a.75.75,0,1,1-1.5,0V18.5a.25.25,0,0,0-.25-.25H15a.75.75,0,0,1,0-1.5h1.5a.25.25,0,0,0,.25-.25V15a.75.75,0,1,1,1.5,0v1.5a.25.25,0,0,0,.25.25H20a.75.75,0,0,1,0,1.5H18.5a.25.25,0,0,0-.25.25Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 723 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.5 3h-2.75-.00000001c-.138071-.00000001-.25-.111929-.25-.25v-1.75c0-.552285-.447715-1-1-1s-1 .447715-1 1v4.75c0 .414214-.335786.75-.75.75h-.00000003c-.414214-.00000002-.75-.335786-.75-.75v-2.25c0-.276142-.223858-.5-.5-.5h-6.25-.00000001c-.137682.00000109-.249449-.11132-.25-.249v-1.751-.00000753c0-.552285-.447715-1-1-1s-1 .447715-1 1v.00001506 4.75c0 .414214-.335786.75-.75.75h-.00000003c-.414214-.00000002-.75-.335786-.75-.75v-2.25001c0-.276142-.223858-.5-.5-.5h-1.5-.00000009c-1.10457.00000005-2 .895431-2 2v17-.0000003c-.00000017 1.10457.89543 2 2 2h19-.00000009c1.10457.00000005 2-.89543 2-2v-17c0-1.10457-.89543-2-2-2zm-.5 19h-18-.00000002c-.276142-.00000001-.5-.223858-.5-.5v-12 .00000008c-.00000004-.276142.223858-.5.5-.5h18-.00000002c.276142-.00000001.5.223858.5.5v12 .00000002c0 .276142-.223858.5-.5.5-.00000001 0-.00000002 0-.00000002 0z"/></svg>
|
||||
|
Before Width: | Height: | Size: 929 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m6.5 12c0 .4.3.7.7.7h4s.1 0 .1.1v4c0 .4.3.7.7.7s.7-.3.7-.7v-4s0-.1.1-.1h4c.4 0 .7-.3.7-.7s-.3-.7-.7-.7h-4s-.1 0-.1-.1v-4c0-.4-.3-.7-.7-.7s-.7.3-.7.7v4s0 .1-.1.1h-4c-.4 0-.7.3-.7.7z"/><path d="m23.3 8.4c-1.6-4.3-5.7-7.8-9.8-8.2-1.9-.2-4 .3-5.8 1.3-.8-.8-1.9-1.4-3.2-1.4-2.4.1-4.3 2-4.3 4.5s.9 3 2.1 3.7c-.2.5-.5 1-.7 1.5-3.1 7.3-.7 10.8 1 12.2 1.6 1.3 3.9 2 6.4 2s6.6-1 9.5-3c4.6-3.1 6.3-7.7 4.7-12.5zm-21.1-3.8c0-1.3 1.1-2.4 2.4-2.4s1.1.2 1.5.6c.5.4.8 1.1.8 1.8s0 .1 0 .2c0 .9-.7 1.7-1.5 2-.3.1-.6.2-.9.2-.5 0-.9-.1-1.3-.4-.6-.4-1.1-1.2-1.1-2zm15.3 14.7c-4.4 3-10.6 3.5-13.5 1.1-2.3-1.9-2.4-5.3-.4-9.9.2-.5.5-1.1.7-1.6h.3c2.4 0 4.4-2 4.4-4.4s0-.9-.2-1.3c1.4-.9 3.1-1.3 4.5-1.1 3.3.4 6.8 3.3 8.1 6.9 1.8 5.3-1.7 8.7-3.9 10.2z"/></svg>
|
||||
|
Before Width: | Height: | Size: 802 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m1.6 21.7c-1-.8-1.5-2.1-1.4-3.3.2-1.8 1.6-3.6 3.2-4.3 6.4-2.9 9.1 12 .6 8.9-.5-.2-.9-.4-1.4-.6-.4-.2-.7-.4-1-.7z"/><path d="m15.8.9c1-.7 2.3-.9 3.4-.4 1.6.6 2.9 2.3 3.2 4 1 6.7-13.4 5.3-8.3-1.7.3-.4.6-.8.9-1.1s.5-.6.9-.8z"/><path d="m19.7 10c1.8.6 3.2 2.2 3.6 4 .6 2.6-.5 5.9-2.4 7.9-7.9 7.4-19.1-12.9-5.3-12.5.8 0 1.5 0 2.3.2.6 0 1.2.2 1.8.4z"/><path d="m.2 5.7c-.2-1.5.6-3.2 1.8-4.1 1.7-1.3 4.6-1.6 6.7-.9 8.2 3.3-3 18.7-7.5 8.3-.3-.6-.5-1.2-.6-1.8-.1-.5-.3-1-.3-1.5z"/></svg>
|
||||
|
Before Width: | Height: | Size: 547 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M6,16.5L3,19.44V11H6M11,14.66L9.43,13.32L8,14.64V7H11M16,13L13,16V3H16M18.81,12.81L17,11H22V16L20.21,14.21L13,21.36L9.53,18.34L5.75,22H3L9.47,15.66L13,18.64" /></svg>
|
||||
|
Before Width: | Height: | Size: 235 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path d="m0 0h24v24h-24z"/></clipPath><g clip-path="url(#a)"><path d="m1.5 10.5h1.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5h-1.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5zm9-9c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5v1.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5zm12 12h-1.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5h1.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5zm-9 9c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5zm-7.9-19 1.1 1.1c.6.6.6 1.5 0 2.1s-1.5.6-2.1 0l-1.1-1.1c-.6-.6-.6-1.5 0-2.1s1.5-.6 2.1 0zm12.8 0c.6-.6 1.5-.6 2.1 0s.6 1.5 0 2.1l-1.1 1.1c-.6.6-1.5.6-2.1 0s-.6-1.5 0-2.1zm0 17-1.1-1.1c-.6-.6-.6-1.5 0-2.1s1.5-.6 2.1 0l1.1 1.1c.6.6.6 1.5 0 2.1s-1.5.6-2.1 0zm-12.8 0c-.6.6-1.5.6-2.1 0s-.6-1.5 0-2.1l1.1-1.1c.6-.6 1.5-.6 2.1 0s.6 1.5 0 2.1z" fill-rule="evenodd"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 894 B |
@@ -1 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m12 2.9c-5.4 0-9.8 3.6-9.8 8.1 0 2.2 1 4.2 2.7 5.6l-2 3.9c-.1.2 0 .5.2.6h.4l5.3-2.4c1.1.3 2.2.5 3.3.5 5.4 0 9.8-3.6 9.8-8.1s-4.5-8.2-9.9-8.2z"/></svg>
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m21.2 1.4h-18.4c-.9 0-1.6.7-1.6 1.6v13.1c0 .9.7 1.6 1.6 1.6h4.3l-1.2 5.2c0 .4 0 .9.5.9s.6-.2.6-.2l6.9-6h7.3c.9 0 1.6-.7 1.6-1.6v-13c0-.9-.7-1.6-1.6-1.6z"/></svg>
|
||||
|
Before Width: | Height: | Size: 219 B After Width: | Height: | Size: 230 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m14.2 8h2.7c.5 0 1-.4 1-1 0-.2 0-.5-.2-.6l-5-5.6c-.4-.4-1-.4-1.4 0l-4.8 5.6c-.4.4-.3 1 0 1.4.2.2.4.2.6.2h7z"/><path d="m9.8 16h-2.7c-.5 0-1 .4-1 1 0 .2 0 .5.2.6l4.8 5.6c.4.4 1 .4 1.4 0l4.8-5.6c.4-.4.3-1 0-1.4-.2-.2-.4-.2-.6-.2h-2.7s-4.4 0-4.4 0z"/></svg>
|
||||
|
Before Width: | Height: | Size: 323 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 11h8V3H3m0 18h8v-8H3m10 8h8v-8h-8m0-10v8h8V3"/></svg>
|
||||
|
Before Width: | Height: | Size: 125 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 20C16.4 20 20 16.4 20 12S16.4 4 12 4 4 7.6 4 12 7.6 20 12 20M12 2C17.5 2 22 6.5 22 12S17.5 22 12 22C6.5 22 2 17.5 2 12C2 6.5 6.5 2 12 2M17 13.9L16.3 15.2L11 12.3V7H12.5V11.4L17 13.9Z" /></svg>
|
||||
|
Before Width: | Height: | Size: 265 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>hourglass</title><path d="M20.5,22H19V18.5A7.01,7.01,0,0,0,14.6,12,7.011,7.011,0,0,0,19,5.5V2h1.5a1,1,0,0,0,0-2H3.5a1,1,0,0,0,0,2H5V5.5A7.011,7.011,0,0,0,9.4,12,7.01,7.01,0,0,0,5,18.5V22H3.5a1,1,0,0,0,0,2h17a1,1,0,0,0,0-2ZM8.19,6.92a1,1,0,0,1,.89-.544h5.84a1,1,0,0,1,.811,1.584,4.591,4.591,0,0,1-7.462,0A1,1,0,0,1,8.19,6.92ZM7.92,18.63l3.044-2.936a1.544,1.544,0,0,1,2.07,0l0,0,3.043,2.935a1.349,1.349,0,0,1,.269,1.6,1.461,1.461,0,0,1-1.3.771H8.957a1.46,1.46,0,0,1-1.3-.764A1.352,1.352,0,0,1,7.92,18.63Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 578 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 15V5H5V15H9C9 16.66 10.34 18 12 18C13.66 18 15 16.66 15 15H19M19 3C20.1 3 21 3.9 21 5V19C21 20.1 20.1 21 19 21H5C3.89 21 3 20.1 3 19L3 5C3 3.9 3.89 3 5 3H19M7 13V11H17V13H7M7 9V7H17V9H7Z" /></svg>
|
||||
|
Before Width: | Height: | Size: 269 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect width="23" height="3" x=".5" y="2.5" rx="1"/><rect width="23" height="3" x=".5" y="10.5" rx="1"/><rect width="23" height="3" x=".5" y="18.5" rx="1"/></svg>
|
||||
|
Before Width: | Height: | Size: 221 B |
@@ -1 +1 @@
|
||||
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19 2c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm-.1 2.5c.3 0 .6.3.6.6v1.2c0 .2 0 .2.2.2h1.2c.3 0 .6.3.6.6s-.3.6-.6.6h-1.2c-.2 0-.2 0-.2.2v1.2c0 .3-.3.6-.6.6s-.6-.3-.6-.6V7.9c0-.2 0-.2-.2-.2h-1.2c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h1.2c.2 0 .2 0 .2-.2V5.1c0-.3.3-.6.6-.6zM9.7 18.9h.1l-.1-.1v.1z" fill="#000"/><path d="M19.2 13.6v6.3c0 .2 0 .4-.4.4H2V6.6c0-.2 0-.4.4-.4h10.1c0-.7.3-1.3.5-1.8H1.4C.5 4.6 0 5.3 0 6.2v14c0 1 .8 1.8 1.8 1.8h17.5c1 0 1.8-.8 1.8-1.8v-6.9c-.6.2-1.2.3-1.8.3h-.1z" fill="#000"/><path d="M4.8 7.5c-.7 0-1.3.6-1.3 1.3v8.9c0 .4.2.7.5 1l2.6-3.5c.2-.3.6-.5.9-.5.4 0 .7.2.9.5l.9 1.3 2.3-3.5c.3-.4.8-.7 1.3-.7s1 .3 1.3.7l3.1 5v-4.5c-2.8-.6-4.9-3-5.1-6H4.6h.2zm1.9 5c-.9 0-1.6-.7-1.6-1.6 0-.9.7-1.6 1.6-1.6.9 0 1.6.7 1.6 1.6 0 .9-.7 1.6-1.6 1.6z" fill="#000"/><path d="M5.2 18.9h2.6l1-1.5-1.2-1.7-2.4 3.2zM10.4 17.8l-.7 1 .1.1H16.2l-3.1-5.1-2.7 4z" fill="#000"/></svg>
|
||||
<svg fill="none" height="24" width="24" xmlns="http://www.w3.org/2000/svg"><g fill="#000"><path d="m19 2c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm-.1 2.5c.3 0 .6.3.6.6v1.2c0 .2 0 .2.2.2h1.2c.3 0 .6.3.6.6s-.3.6-.6.6h-1.2c-.2 0-.2 0-.2.2v1.2c0 .3-.3.6-.6.6s-.6-.3-.6-.6v-1.2c0-.2 0-.2-.2-.2h-1.2c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h1.2c.2 0 .2 0 .2-.2v-1.2c0-.3.3-.6.6-.6zm-9.2 14.4h.1l-.1-.1z"/><path d="m19.2 13.6v6.3c0 .2 0 .4-.4.4h-16.8v-13.7c0-.2 0-.4.4-.4h10.1c0-.7.3-1.3.5-1.8h-11.6c-.9.2-1.4.9-1.4 1.8v14c0 1 .8 1.8 1.8 1.8h17.5c1 0 1.8-.8 1.8-1.8v-6.9c-.6.2-1.2.3-1.8.3z"/><path d="m4.8 7.5c-.7 0-1.3.6-1.3 1.3v8.9c0 .4.2.7.5 1l2.6-3.5c.2-.3.6-.5.9-.5.4 0 .7.2.9.5l.9 1.3 2.3-3.5c.3-.4.8-.7 1.3-.7s1 .3 1.3.7l3.1 5v-4.5c-2.8-.6-4.9-3-5.1-6h-7.6zm1.9 5c-.9 0-1.6-.7-1.6-1.6s.7-1.6 1.6-1.6 1.6.7 1.6 1.6-.7 1.6-1.6 1.6z"/><path d="m5.2 18.9h2.6l1-1.5-1.2-1.7zm5.2-1.1-.7 1 .1.1h6.4l-3.1-5.1z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 966 B After Width: | Height: | Size: 909 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m3.25 13.25a1 1 0 0 1 -1-1v-6a1 1 0 0 1 1-1h11a1 1 0 0 1 .98.8.25.25 0 0 0 .245.2h1.525a.25.25 0 0 0 .25-.25v-.75a2 2 0 0 0 -2-2h-13a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h1.75a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0 -.25-.25z"/><path d="m21.25 7.75h-13a2.5 2.5 0 0 0 -2.5 2.5v8a2.5 2.5 0 0 0 2.5 2.5h13a2.5 2.5 0 0 0 2.5-2.5v-8a2.5 2.5 0 0 0 -2.5-2.5zm-13 9.5v-6a1 1 0 0 1 1-1h11a1 1 0 0 1 1 1v6a1 1 0 0 1 -1 1h-11a1 1 0 0 1 -1-1z"/></svg>
|
||||
|
Before Width: | Height: | Size: 500 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m20 17h3l-4 4-4-4h3v-14h2zm-12-12c-3.86 0-7 3.13-7 7s3.13 7 7 7c3.86 0 7-3.13 7-7s-3.13-7-7-7m0 2.15c2.67 0 4.85 2.17 4.85 4.85s-2.17 4.85-4.85 4.85-4.85-2.17-4.85-4.85 2.17-4.85 4.85-4.85m-1 1.85v3.69l3.19 1.84.75-1.3-2.44-1.41v-2.82"/></svg>
|
||||
|
Before Width: | Height: | Size: 312 B |
@@ -1 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m18 7h-3l4-4 4 4h-3v14h-2zm-10-2c-3.86 0-7 3.13-7 7s3.13 7 7 7c3.86 0 7-3.13 7-7s-3.13-7-7-7m0 2.15c2.67 0 4.85 2.17 4.85 4.85s-2.17 4.85-4.85 4.85-4.85-2.17-4.85-4.85 2.17-4.85 4.85-4.85m-1 1.85v3.69l3.19 1.84.75-1.3-2.44-1.41v-2.82"/></svg>
|
||||
|
Before Width: | Height: | Size: 311 B |
@@ -1 +0,0 @@
|
||||
<svg id="Bold" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>temperature-thermometer-high</title><path d="M14,4.5a4.5,4.5,0,0,0-9,0v9.438a.248.248,0,0,1-.06.162A5.941,5.941,0,0,0,3.5,18a6,6,0,0,0,12,0,5.941,5.941,0,0,0-1.44-3.9.248.248,0,0,1-.06-.162ZM9.5,22a4,4,0,0,1-2.8-6.856A1,1,0,0,0,7,14.43V4.5a2.5,2.5,0,0,1,5,0v9.93a1,1,0,0,0,.3.714A4,4,0,0,1,9.5,22Z"/><path d="M10.611,16.337a.25.25,0,0,1-.111-.208V5a1,1,0,0,0-2,0V16.129a.25.25,0,0,1-.111.208,2,2,0,1,0,2.222,0Z"/><path d="M19.5,11.5H17a1,1,0,0,0,0,2h2.5a1,1,0,0,0,0-2Z"/><path d="M17,5.5h2.5a1,1,0,0,0,0-2H17a1,1,0,0,0,0,2Z"/><path d="M19.5,7.5H17a1,1,0,0,0,0,2h2.5a1,1,0,0,0,0-2Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 666 B |
@@ -9,16 +9,6 @@
|
||||
}
|
||||
|
||||
/* Keyframes */
|
||||
@keyframes float-up-left {
|
||||
0% { transform: translate(10px, 20px); }
|
||||
100% { transform: translate(0, 0); }
|
||||
}
|
||||
|
||||
@keyframes float-down-right {
|
||||
0% { transform: translate(-10px, -20px); }
|
||||
100% { transform: translate(0, 0); }
|
||||
}
|
||||
|
||||
@keyframes react {
|
||||
0% { transform: scale(0.3); opacity: 0; }
|
||||
50% { transform: scale(1.15); opacity: 1; }
|
||||
@@ -36,30 +26,4 @@
|
||||
50% { transform: translateX(-1rem); }
|
||||
75% { transform: translateX(1rem); }
|
||||
}
|
||||
|
||||
@keyframes wobble {
|
||||
0% { transform: rotate(calc(var(--card-rotate) + 90deg)); }
|
||||
15% { border-radius: 66% 34% 72% 28% / 39% 63% 37% 61%; }
|
||||
25% { border-radius: 55% 47% 62% 40% / 58% 50% 52% 44%; }
|
||||
33% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; }
|
||||
50% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; }
|
||||
75% { border-radius: 53% 45% 60% 38% / 56% 48% 50% 42%; }
|
||||
}
|
||||
|
||||
@keyframes wobble-alt {
|
||||
0% { transform: rotate(calc(var(--card-rotate) + -90deg)); }
|
||||
12% { border-radius: 66% 34% 72% 28% / 39% 63% 37% 61%; }
|
||||
25% { border-radius: 53% 45% 60% 38% / 56% 48% 50% 42%; }
|
||||
33% { border-radius: 55% 47% 62% 40% / 58% 50% 52% 44%; }
|
||||
50% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; }
|
||||
75% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; }
|
||||
}
|
||||
|
||||
@keyframes wobble-img {
|
||||
15% { border-radius: 66% 34% 72% 28% / 39% 63% 37% 61%; }
|
||||
25% { border-radius: 55% 47% 62% 40% / 58% 50% 52% 44%; }
|
||||
33% { border-radius: 46% 54% 61% 39% / 50% 51% 49% 50%; }
|
||||
50% { border-radius: 54% 46% 61% 39% / 57% 49% 51% 43%; }
|
||||
75% { border-radius: 53% 45% 60% 38% / 56% 48% 50% 42%; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,42 +24,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.avatar__group {
|
||||
--avatar-size: 2.5ch;
|
||||
|
||||
block-size: 5ch;
|
||||
display: grid;
|
||||
gap: 1px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: min-content;
|
||||
inline-size: 5ch;
|
||||
place-content: center;
|
||||
|
||||
.avatar {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&:where(:has(> :last-child:nth-child(2))) {
|
||||
--avatar-size: 3.5ch;
|
||||
|
||||
> :first-child {
|
||||
margin-block-end: 1.5ch;
|
||||
margin-inline-end: -0.75ch;
|
||||
}
|
||||
|
||||
> :last-child {
|
||||
margin-block-start: 1.5ch;
|
||||
margin-inline-start: -0.75ch;
|
||||
}
|
||||
}
|
||||
|
||||
&:where(:has(> :last-child:nth-child(3))) {
|
||||
> :last-child {
|
||||
margin-inline: 1.25ch -1.25ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar__form {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
|
||||
@@ -1,493 +0,0 @@
|
||||
:root {
|
||||
--bubble-shape: 54% 46% 61% 39% / 57% 49% 51% 43%;
|
||||
--bubble-shift: 10deg;
|
||||
--bubble-size-one: 14cqi;
|
||||
--bubble-size-two: 16cqi;
|
||||
--bubble-size-three: 18cqi;
|
||||
--bubble-size-four: 20cqi;
|
||||
--bubble-size-five: 22cqi;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.bubbles {
|
||||
--column-gap: 2cqi;
|
||||
--row-gap: 1cqi;
|
||||
|
||||
margin-block: clamp(var(--block-space), 3%, calc(var(--block-space) * 2));
|
||||
|
||||
> * {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.something-to-rename {
|
||||
--bubble-background: radial-gradient(circle at center, color(from var(--bubble-color) srgb r g b / 0.25), color(from var(--bubble-color) srgb r g b / 0.05));
|
||||
--bubble-border-width: 0.2rem;
|
||||
--hover-size: 0;
|
||||
|
||||
aspect-ratio: 1;
|
||||
block-size: var(--bubble-size);
|
||||
color: var(--bubble-color, currentColor);
|
||||
container-type: inline-size;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
position: relative;
|
||||
transition: 0.2s ease;
|
||||
|
||||
.bubbles & {
|
||||
&:nth-child(1) { order: 5; }
|
||||
&:nth-child(2) { order: 3; }
|
||||
&:nth-child(3) { order: 3; }
|
||||
&:nth-child(4) { order: 7; }
|
||||
&:nth-child(5) { order: 9; }
|
||||
&:nth-child(6) { order: 5; }
|
||||
&:nth-child(7) { order: 4; }
|
||||
&:nth-child(8) { order: 9; }
|
||||
&:nth-child(9) { order: 3; }
|
||||
&:nth-child(10) { order: 7; }
|
||||
&:nth-of-type(n+6) {
|
||||
align-self: start;
|
||||
}
|
||||
}
|
||||
|
||||
[data-turbo-preview] & { animation: none; }
|
||||
|
||||
> * {
|
||||
grid-area: 1/1;
|
||||
}
|
||||
|
||||
.bubble__perma & {
|
||||
--bubble-border-width: 0.3rem;
|
||||
--bubble-size: 40dvh !important;
|
||||
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.bubble__detail {
|
||||
--bubble-border-color: color-mix(in srgb, var(--bubble-color) 30%, var(--color-bg));
|
||||
--bubble-border-width: 0.15em;
|
||||
|
||||
aspect-ratio: 1;
|
||||
background: var(--color-bg);
|
||||
block-size: auto;
|
||||
border: var(--bubble-border-width) solid var(--bubble-border-color);
|
||||
border-radius: var(--bubble-shape);
|
||||
display: flex;
|
||||
font-size: 5cqi;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
max-inline-size: 18ch;
|
||||
padding: 1em;
|
||||
place-content: center;
|
||||
place-items: center;
|
||||
position: absolute;
|
||||
scale: 1;
|
||||
text-overflow: ellipsis;
|
||||
transform: none;
|
||||
transition: transform 200ms ease-out;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
|
||||
a {
|
||||
color: var(--bubble-color);
|
||||
}
|
||||
|
||||
&.bubble__assignee {
|
||||
font-size: 4.5cqi;
|
||||
inset: 8em auto auto -1.7em;
|
||||
padding: 0.2em;
|
||||
|
||||
+ & {
|
||||
inset: 4em auto auto -1em;
|
||||
|
||||
+ & {
|
||||
inset: 1em auto auto 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: var(--bubble-shape);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.bubbles .something-to-rename:not(.popped):hover & {
|
||||
transform: translate(0, -1rem);
|
||||
}
|
||||
|
||||
.bubbles .something-to-rename:not(.popped):hover & + & {
|
||||
transform: translate(1rem, -1rem);
|
||||
}
|
||||
|
||||
.bubbles .something-to-rename:not(.popped):hover & + & + & {
|
||||
transform: translate(1.5rem, -0.5rem);;
|
||||
}
|
||||
}
|
||||
|
||||
.assignee__name {
|
||||
display: none;
|
||||
|
||||
.bubble__perma & {
|
||||
color: var(--bubble-color);
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
font-weight: normal;
|
||||
inline-size: 15ch;
|
||||
inset: 0.3em 3.6em auto auto;
|
||||
position: absolute;
|
||||
text-align: end;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__comments {
|
||||
--arrow-size: 1.5em;
|
||||
--border-size: var(--bubble-border-width);
|
||||
|
||||
aspect-ratio: 9/6;
|
||||
inset: auto auto 2em -1em;
|
||||
|
||||
&::before {
|
||||
aspect-ratio: 2;
|
||||
background: var(--bubble-border-color);
|
||||
clip-path: polygon(50% 100%, 100% 0, 0 0);
|
||||
inline-size: var(--arrow-size);
|
||||
content: "";
|
||||
display: block;
|
||||
inset-block-end: auto;
|
||||
inset-block-start: 94%;
|
||||
inset-inline-start: 66%;
|
||||
position: absolute;
|
||||
transform: translateX(-50%) rotate(-20deg);
|
||||
}
|
||||
|
||||
&::after {
|
||||
aspect-ratio: 2;
|
||||
background: var(--color-bg);
|
||||
clip-path: polygon(50% 100%, 100% 0, 0 0);
|
||||
inline-size: var(--arrow-size);
|
||||
content: "";
|
||||
display: block;
|
||||
inset-block-end: auto;
|
||||
inset-block-start: calc(94% - var(--border-size) * 1.5);
|
||||
inset-inline-start: 64%;
|
||||
position: absolute;
|
||||
transform: translateX(-50%) rotate(-20deg);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.bubbles .something-to-rename:not(.popped):hover & {
|
||||
transform: translate(-0.5rem, -2rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.bubble__date {
|
||||
--rotation: -45deg;
|
||||
|
||||
aspect-ratio: 5/7;
|
||||
cursor: pointer;
|
||||
inset: 1cqb 1cqi auto auto;
|
||||
transform: rotate(var(--rotation));
|
||||
|
||||
.bubble__date-text {
|
||||
transform: rotate(calc(var(--rotation) * -1));
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.bubbles .something-to-rename:not(.popped):hover & {
|
||||
transform: rotate(calc(var(--rotation) + var(--bubble-shift) * 1)) translate(0rem, 0.5rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.bubbles .something-to-rename:not(.popped):hover & {
|
||||
transform: translate(1rem, 1rem);
|
||||
}
|
||||
|
||||
.bubbles .something-to-rename:not(.popped):hover & + & {
|
||||
transform: translate(0, -1rem);
|
||||
}
|
||||
|
||||
.bubbles .something-to-rename:not(.popped):hover & + & + & {
|
||||
transform: translate(-1rem, -1rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__image {
|
||||
border: none;
|
||||
border-radius: var(--bubble-shape);
|
||||
block-size: 100cqi;
|
||||
inline-size: 100cqi;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
transform: rotate(var(--bubble-rotate)) scale(0.92);
|
||||
transition: 0.2s ease;
|
||||
|
||||
@media (hover: hover) {
|
||||
.bubbles .something-to-rename:not(.popped):hover & {
|
||||
transform: rotate(calc(var(--bubble-rotate) + var(--bubble-shift))) scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
block-size: 100cqi;
|
||||
inline-size: 100cqi;
|
||||
max-inline-size: none;
|
||||
object-fit: cover;
|
||||
transform: rotate(calc(var(--bubble-rotate) * -1)) scale(1.1);
|
||||
|
||||
&:is([src=""]) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:is(.bubbles, .bubbles-list) .bubble--wobble & {
|
||||
animation: wobble-img 1200ms normal forwards ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__link {
|
||||
content: "";
|
||||
inset: 0;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
|
||||
.bubbles & {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.bubbles-list {
|
||||
--bubble-border-width: 0.15rem;
|
||||
--bubble-shift: 15deg;
|
||||
--bubble-size: 1.8em;
|
||||
--divider-offset: 1.2em;
|
||||
--hover-size: 0;
|
||||
|
||||
margin-inline: auto;
|
||||
|
||||
@media (min-width: 150ch) {
|
||||
margin-inline: var(--tray-size);
|
||||
}
|
||||
|
||||
.something-to-rename {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
.bubble__title-link {
|
||||
color: var(--color-txt);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul {
|
||||
li {
|
||||
border-radius: 0;
|
||||
list-style: none;
|
||||
padding: 0.5em var(--inline-space);
|
||||
position: relative;
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
|
||||
&:not(.dragging) {
|
||||
li {
|
||||
@media (hover: hover) {
|
||||
&:hover {
|
||||
background-color: color(from var(--bubble-color) srgb r g b / 0.15);
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
--avatar-size: 1.1em;
|
||||
|
||||
> * {
|
||||
font-size: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__title-text {
|
||||
font-weight: 700;
|
||||
flex-grow: 1;
|
||||
letter-spacing: -0.015em;
|
||||
white-space: nowrap;
|
||||
|
||||
.drafted & {
|
||||
color: color(from var(--color-ink) srgb r g b / 0.5);
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-block-end: 1px dotted var(--color-subtle-dark);
|
||||
content: "";
|
||||
flex-grow: 1;
|
||||
margin-block-end: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__tags {
|
||||
--row-gap: 0;
|
||||
|
||||
font-size: var(--text-small);
|
||||
margin-block-start: 0.3cqb;
|
||||
max-block-size: 4lh;
|
||||
max-inline-size: 75cqi;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
.bubble__perma & {
|
||||
font-size: var(--text-medium);
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__tag {
|
||||
font-weight: 700;
|
||||
max-inline-size: 75cqi;
|
||||
}
|
||||
|
||||
.bubble__title {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
max-block-size: 90cqi;
|
||||
max-inline-size: 70cqi;
|
||||
|
||||
.bubbles & {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--splat-color);
|
||||
|
||||
&.bubble__title-rendered {
|
||||
-webkit-line-clamp: var(--lines, 4);
|
||||
-webkit-box-orient: vertical;
|
||||
display: -webkit-box;
|
||||
font-size: 9cqi;
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
overflow: hidden;
|
||||
text-overflow: clip;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
/*textarea {*/
|
||||
/* --input-color: var(--bubble-color);*/
|
||||
/* --input-border-radius: 0;*/
|
||||
|
||||
/* font-size: 9cqi;*/
|
||||
/* font-weight: 800;*/
|
||||
/* line-height: 1.2;*/
|
||||
|
||||
/* &::selection {*/
|
||||
/* background-color: var(--bubble-color);*/
|
||||
/* color: var(--color-ink-reversed);*/
|
||||
/* }*/
|
||||
/*}*/
|
||||
|
||||
@media (hover: hover) {
|
||||
.something-to-rename:has(.bubble__image img:not([src=""])):hover & {
|
||||
color: var(--color-ink-reversed);
|
||||
text-shadow: 0 0 0.2em var(--bubble-color), 0 0 0.2em var(--bubble-color), 0 0 0.2em var(--bubble-color);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__shape {
|
||||
background: var(--bubble-background);
|
||||
block-size: var(--bubble-size, 1.2em);
|
||||
border-color: var(--bubble-border-color, color-mix(in srgb, var(--bubble-color) 15%, var(--color-bg)));
|
||||
border-radius: var(--bubble-shape);
|
||||
border-style: var(--bubble-border-style, solid);
|
||||
border-width: 1px;
|
||||
inline-size: var(--bubble-size, 1.2em);
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
transform: rotate(var(--bubble-rotate));
|
||||
transition: 200ms ease-out;
|
||||
z-index: 0;
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--bubble-background: radial-gradient(circle at center, color(from var(--bubble-color) srgb r g b / 0.45), color(from var(--bubble-color) srgb r g b / 0.15));
|
||||
--bubble-border-color: color-mix(in srgb, var(--bubble-color) 30%, var(--color-bg));
|
||||
}
|
||||
|
||||
.something-to-rename & {
|
||||
--bubble-size: 100%;
|
||||
}
|
||||
|
||||
.drafted & {
|
||||
--bubble-border-style: dashed;
|
||||
}
|
||||
|
||||
:is(.bubbles, .bubbles-list) .bubble--wobble & {
|
||||
animation: wobble 1200ms normal forwards ease-out;
|
||||
}
|
||||
|
||||
.bubble--wobble:nth-child(even) & {
|
||||
animation-name: wobble-alt;
|
||||
animation-duration: 900ms;
|
||||
}
|
||||
|
||||
.popped & {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.event &,
|
||||
.bucket &,
|
||||
.bubbles-list & {
|
||||
--bubble-background: color-mix(in srgb, var(--bubble-color) 30%, var(--color-bg));
|
||||
--bubble-border-color: color-mix(in srgb, var(--bubble-color) 40%, var(--color-bg))
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__actions-container {
|
||||
background-color: color-mix(in srgb, var(--bubble-color) 20%, var(--color-bg));
|
||||
margin-block-start: -0.7em;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.btn--plain {
|
||||
--btn-color: var(--bubble-color);
|
||||
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.bubble__pop-message {
|
||||
color: var(--bubble-color);
|
||||
}
|
||||
}
|
||||
|
||||
.bubble__splat {
|
||||
display: none;
|
||||
pointer-events: none;
|
||||
transform: rotate(var(--bubble-rotate));
|
||||
|
||||
.popped & {
|
||||
display: block;
|
||||
fill: color-mix(in srgb, var(--bubble-color) 20%, var(--color-bg));
|
||||
position: absolute;
|
||||
scale: 130%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.bubbles-list & {
|
||||
block-size: var(--bubble-size);
|
||||
fill: color-mix(in srgb, var(--bubble-color) 35%, var(--color-bg));
|
||||
inline-size: var(--bubble-size);
|
||||
position: relative;
|
||||
scale: 1;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,10 +181,6 @@
|
||||
--btn-border-color: var(--color-bg);
|
||||
}
|
||||
|
||||
.btn--small {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.btn--success {
|
||||
animation: success 1s ease-out;
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
@layer components {
|
||||
.collection {
|
||||
inline-size: min(35ch, 40%);
|
||||
line-height: 1.2;
|
||||
|
||||
mark {
|
||||
background-color: transparent;
|
||||
color: var(--color-link);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.collections {
|
||||
--gap: 2cqi;
|
||||
--hover-size: 0;
|
||||
--column-gap: var(--gap);
|
||||
--row-gap: var(--gap);
|
||||
|
||||
list-style: none;
|
||||
padding: var(--gap);
|
||||
}
|
||||
|
||||
.collection__button {
|
||||
position: absolute;
|
||||
inset: calc((var(--btn-size) * -1) - 2cqi) 1cqi auto auto;
|
||||
}
|
||||
|
||||
.collection__cards {
|
||||
--border-radius: 1.5em;
|
||||
|
||||
margin-block: 0;
|
||||
max-inline-size: 100%;
|
||||
padding: 1cqi;
|
||||
}
|
||||
|
||||
.cards__container {
|
||||
aspect-ratio: 18 / 9;
|
||||
container-type: inline-size;
|
||||
}
|
||||
}
|
||||
@@ -17,41 +17,28 @@
|
||||
background: none;
|
||||
}
|
||||
|
||||
.icon--activity { --svg: url("activity.svg "); }
|
||||
.icon--add { --svg: url("add.svg "); }
|
||||
.icon--alert { --svg: url("alert.svg "); }
|
||||
.icon--arrow-left { --svg: url("arrow-left.svg "); }
|
||||
.icon--arrow-right { --svg: url("arrow-right.svg "); }
|
||||
.icon--art { --svg: url("art.svg "); }
|
||||
.icon--assigned { --svg: url("assigned.svg "); }
|
||||
.icon--bell-off { --svg: url("bell-off.svg "); }
|
||||
.icon--bell { --svg: url("bell.svg "); }
|
||||
.icon--blob { --svg: url("blob.svg "); }
|
||||
.icon--bolt { --svg: url("bolt.svg "); }
|
||||
.icon--bookmark-outline { --svg: url("bookmark-outline.svg "); }
|
||||
.icon--bookmark { --svg: url("bookmark.svg "); }
|
||||
.icon--card-add { --svg: url("card-add.svg "); }
|
||||
.icon--cards { --svg: url("cards.svg "); }
|
||||
.icon--calendar-add { --svg: url("calendar-add.svg "); }
|
||||
.icon--calendar { --svg: url("calendar.svg "); }
|
||||
.icon--camera { --svg: url("camera.svg "); }
|
||||
.icon--caret-down { --svg: url("caret-down.svg "); }
|
||||
.icon--chart { --svg: url("chart.svg "); }
|
||||
.icon--check { --svg: url("check.svg "); }
|
||||
.icon--close { --svg: url("close.svg "); }
|
||||
.icon--comment { --svg: url("comment.svg "); }
|
||||
.icon--copy-paste { --svg: url("copy-paste.svg "); }
|
||||
.icon--crown { --svg: url("crown.svg "); }
|
||||
.icon--drag { --svg: url("drag.svg "); }
|
||||
.icon--email { --svg: url("email.svg "); }
|
||||
.icon--everyone { --svg: url("everyone.svg "); }
|
||||
.icon--filter { --svg: url("filter.svg "); }
|
||||
.icon--globe { --svg: url("globe.svg "); }
|
||||
.icon--grid { --svg: url("grid.svg "); }
|
||||
.icon--history { --svg: url("history.svg "); }
|
||||
.icon--home { --svg: url("home.svg "); }
|
||||
.icon--hourglass { --svg: url("hourglass.svg "); }
|
||||
.icon--inbox { --svg: url("inbox.svg "); }
|
||||
.icon--logout { --svg: url("logout.svg "); }
|
||||
.icon--menu { --svg: url("menu.svg "); }
|
||||
.icon--menu-dots-horizontal { --svg: url("menu-dots-horizontal.svg "); }
|
||||
@@ -66,7 +53,6 @@
|
||||
.icon--picture-double { --svg: url("picture-double.svg "); }
|
||||
.icon--picture-remove { --svg: url("picture-remove.svg "); }
|
||||
.icon--pinned { --svg: url("pinned.svg "); }
|
||||
.icon--closure { --svg: url("closure.svg "); }
|
||||
.icon--qr-code { --svg: url("qr-code.svg "); }
|
||||
.icon--reaction { --svg: url("reaction.svg "); }
|
||||
.icon--refresh { --svg: url("refresh.svg "); }
|
||||
@@ -75,11 +61,8 @@
|
||||
.icon--rename { --svg: url("rename.svg "); }
|
||||
.icon--settings { --svg: url("settings.svg "); }
|
||||
.icon--share { --svg: url("share.svg "); }
|
||||
.icon--sort-ascending { --svg: url("sort-ascending.svg "); }
|
||||
.icon--sort-descending { --svg: url("sort-descending.svg "); }
|
||||
.icon--star { --svg: url("star.svg "); }
|
||||
.icon--tag { --svg: url("tag.svg "); }
|
||||
.icon--temperature { --svg: url("temperature.svg "); }
|
||||
.icon--thumb-up { --svg: url("thumb-up.svg "); }
|
||||
.icon--trash { --svg: url("trash.svg "); }
|
||||
.icon--unpinned { --svg: url("unpinned.svg"); }
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
@layer components {
|
||||
.notification {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.notification-tray {
|
||||
inset: auto var(--inline-space) var(--block-space-half) auto;
|
||||
|
||||
@@ -48,7 +52,7 @@
|
||||
.notificiations-list--read & {
|
||||
--border-color: var(--color-subtle);
|
||||
|
||||
box-shadow: none;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
.panel {
|
||||
background-color: var(--color-bg);
|
||||
border: var(--panel-border-size, 1px) solid var(--panel-border-color, var(--color-subtle));
|
||||
color: var(--color-ink);
|
||||
border-radius: var(--panel-border-radius, 1em);
|
||||
color: var(--color-ink);
|
||||
inline-size: var(--panel-size, 60ch);
|
||||
max-inline-size: 100%;
|
||||
padding: var(--panel-padding, calc(var(--block-space) * 2));
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
@layer components {
|
||||
.pin-tray {
|
||||
inset: auto auto var(--block-space-half) var(--inline-space);
|
||||
|
||||
.pin {
|
||||
--z: calc(10 - var(--position));
|
||||
|
||||
&:nth-child(7) { --position: 7; }
|
||||
&:nth-child(8) { --position: 8; }
|
||||
&:nth-child(9) { --position: 9; }
|
||||
&:nth-child(10) { --position: 10; }
|
||||
|
||||
&:nth-child(1n + 11) { display: none; }
|
||||
}
|
||||
}
|
||||
|
||||
.pin__collection {
|
||||
background-color: var(--card-color);
|
||||
font-weight: 800;
|
||||
@@ -51,4 +36,19 @@
|
||||
.pin__title {
|
||||
margin-block-start: 0.3rem;
|
||||
}
|
||||
|
||||
.pin-tray {
|
||||
inset: auto auto var(--block-space-half) var(--inline-space);
|
||||
|
||||
.pin {
|
||||
--z: calc(10 - var(--position));
|
||||
|
||||
&:nth-child(7) { --position: 7; }
|
||||
&:nth-child(8) { --position: 8; }
|
||||
&:nth-child(9) { --position: 9; }
|
||||
&:nth-child(10) { --position: 10; }
|
||||
|
||||
&:nth-child(1n + 11) { display: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
@layer components {
|
||||
/* Language translations */
|
||||
.lanuage-list-menu {
|
||||
--max-width: 40ch;
|
||||
|
||||
background-color: var(--color-subtle);
|
||||
border: 1px solid var(--color-subtle-dark);
|
||||
border-radius: 0.5em;
|
||||
inset: auto;
|
||||
inline-size: max-content;
|
||||
margin-inline: var(--inline-space);
|
||||
max-inline-size: 40ch;
|
||||
overflow: clip;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
|
||||
@media (max-width: 70ch) {
|
||||
max-inline-size: calc(var(--max-width) - var(--inline-space));
|
||||
}
|
||||
|
||||
.popover-orientation-top & {
|
||||
inset-block-end: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.language-list {
|
||||
display: grid;
|
||||
gap: var(--block-space-half) var(--inline-space);
|
||||
grid-template-rows: min-content;
|
||||
grid-template-columns: min-content 1fr;
|
||||
justify-content: start;
|
||||
margin: 0;
|
||||
text-align: start;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
--scale: calc(1 - var(--position) / 30);
|
||||
--z: calc(6 - var(--position));
|
||||
|
||||
display: flex;
|
||||
inset: auto 0 0;
|
||||
inline-size: var(--tray-size);
|
||||
outline: 0;
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
background-color: color(from var(--card-color) srgb r g b / 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
.cards-list & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow-stage--current {
|
||||
@@ -38,30 +34,5 @@
|
||||
border-radius: 0.2em;
|
||||
color: var(--color-ink-reversed);
|
||||
}
|
||||
|
||||
.cards-list & {
|
||||
display: flex;
|
||||
background: transparent;
|
||||
border-radius: 0.2em;
|
||||
color: var(--color-ink);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.workflow__popup {
|
||||
--panel-border-radius: 0.5em;
|
||||
--panel-padding: 0.5em;
|
||||
--panel-size: 100%;
|
||||
|
||||
inline-size: auto !important;
|
||||
inset: 0 auto auto 0;
|
||||
margin-block-start: 1lh;
|
||||
margin-inline-start: calc((var(--panel-padding) + 0.7em) * -1);
|
||||
min-inline-size: 12ch;
|
||||
max-inline-size: var(--panel-size) !important;
|
||||
position: absolute;
|
||||
transform-origin: top left;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class Cards::PreviewsController < ApplicationController
|
||||
include FilterScoped
|
||||
before_action :set_filter, only: :index
|
||||
|
||||
def index
|
||||
set_page_and_extract_portion_from @filter.cards, per_page: CardsController::PAGE_SIZE
|
||||
end
|
||||
end
|
||||
@@ -1,20 +1,17 @@
|
||||
require "ostruct"
|
||||
|
||||
class CardsController < ApplicationController
|
||||
include CollectionScoped
|
||||
include CollectionScoped, FilterScoped
|
||||
|
||||
skip_before_action :set_collection, only: :index
|
||||
|
||||
before_action :set_filter, only: :index
|
||||
before_action :set_card, only: %i[ show edit update destroy ]
|
||||
before_action :handle_display_count, only: :index
|
||||
|
||||
DISPLAY_COUNT_OPTIONS = [ 6, 12, 18, 24 ].freeze
|
||||
DEFAULT_DISPLAY_COUNT = 6
|
||||
RECENTLY_CLOSED_LIMIT = 100
|
||||
PAGE_SIZE = 50
|
||||
|
||||
def index
|
||||
@considering_cards = @filter.cards.considering.load_async
|
||||
@doing_cards = @filter.cards.doing.load_async
|
||||
@closed_cards = @filter.with(indexed_by: "closed").cards.recently_closed_first.limit(RECENTLY_CLOSED_LIMIT).load_async
|
||||
@considering = page_and_filter_for @filter.with(engagement_status: "considering", indexed_by: "latest"), per_page: PAGE_SIZE
|
||||
@doing = page_and_filter_for @filter.with(engagement_status: "doing", indexed_by: "latest"), per_page: PAGE_SIZE
|
||||
@closed = page_and_filter_for @filter.with(indexed_by: "closed"), per_page: PAGE_SIZE
|
||||
end
|
||||
|
||||
def create
|
||||
@@ -38,16 +35,16 @@ class CardsController < ApplicationController
|
||||
end
|
||||
|
||||
private
|
||||
DEFAULT_PARAMS = { indexed_by: "newest" }
|
||||
|
||||
def set_filter
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**DEFAULT_PARAMS).permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
|
||||
def set_card
|
||||
@card = @collection.cards.find params[:id]
|
||||
end
|
||||
|
||||
def page_and_filter_for(filter, per_page: nil)
|
||||
OpenStruct.new \
|
||||
page: GearedPagination::Recordset.new(filter.cards, per_page:).page(1),
|
||||
filter: filter
|
||||
end
|
||||
|
||||
def card_params
|
||||
params.expect(card: [ :status, :title, :color, :due_on, :image, :draft_comment, tag_ids: [] ])
|
||||
end
|
||||
@@ -55,17 +52,4 @@ class CardsController < ApplicationController
|
||||
def deleted_notice
|
||||
"Card deleted" unless @card.creating?
|
||||
end
|
||||
|
||||
def handle_display_count
|
||||
if params[:set_display_count].present?
|
||||
cookies[:display_count] = params[:set_display_count]
|
||||
redirect_to cards_path(
|
||||
params.permit(*Filter::PERMITTED_PARAMS, :collection_ids).except(:set_display_count)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def display_count
|
||||
(cookies[:display_count] || DEFAULT_DISPLAY_COUNT).to_i
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
module FilterScoped
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_action :set_filter, only: :index
|
||||
end
|
||||
|
||||
private
|
||||
DEFAULT_PARAMS = { indexed_by: "newest" }
|
||||
|
||||
def set_filter
|
||||
@filter = Current.user.filters.from_params params.reverse_merge(**DEFAULT_PARAMS).permit(*Filter::PERMITTED_PARAMS)
|
||||
end
|
||||
end
|
||||
@@ -31,6 +31,6 @@ class Workflows::StagesController < ApplicationController
|
||||
end
|
||||
|
||||
def stage_params
|
||||
params.expect workflow_stage: [ :name ]
|
||||
params.require(:workflow_stage).permit(:name, :color)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ module AvatarsHelper
|
||||
end
|
||||
|
||||
def avatar_tag(user, hidden_for_screen_reader: false, **options)
|
||||
link_to user_path(user), title: user.name, class: "btn avatar", data: { turbo_frame: "_top" },
|
||||
link_to user_path(user), class: "btn avatar", data: { turbo_frame: "_top" },
|
||||
aria: { hidden: hidden_for_screen_reader, label: user.name },
|
||||
tabindex: hidden_for_screen_reader ? -1 : nil do
|
||||
avatar_image_tag(user, **options)
|
||||
@@ -19,6 +19,6 @@ module AvatarsHelper
|
||||
end
|
||||
|
||||
def avatar_image_tag(user, **options)
|
||||
image_tag user_avatar_path(user), aria: { hidden: "true" }, size: 48, class: ("avatar__photo" if user.avatar.attached?), **options
|
||||
image_tag user_avatar_path(user), aria: { hidden: "true" }, size: 48, title: user.name, class: ("avatar__photo" if user.avatar.attached?), **options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,14 +11,19 @@ module CardsHelper
|
||||
"--card-rotate: #{value}deg;"
|
||||
end
|
||||
|
||||
def display_count_options
|
||||
CardsController::DISPLAY_COUNT_OPTIONS.map do |count|
|
||||
{
|
||||
value: count,
|
||||
label: count,
|
||||
selected: @display_count == count,
|
||||
id: "display-count-#{count}"
|
||||
}
|
||||
def cards_next_page_link(target, page:, filter:, fetch_on_visible: false, data: {}, **options)
|
||||
url = cards_previews_path(target: target, page: page.next_param, **filter.as_params)
|
||||
|
||||
if fetch_on_visible
|
||||
data[:controller] = "#{data[:controller]} fetch-on-visible"
|
||||
data[:fetch_on_visible_url_value] = url
|
||||
end
|
||||
|
||||
link_to "Load more",
|
||||
url,
|
||||
id: "#{target}-load-page-#{page.next_param}",
|
||||
data: { turbo_stream: true, **data },
|
||||
class: "btn txt-small",
|
||||
**options
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ module NotificationsHelper
|
||||
end
|
||||
|
||||
def notification_tag(notification, &)
|
||||
tag.div id: dom_id(notification), class: "notification tray__item border-radius flex txt-normal" do
|
||||
tag.div id: dom_id(notification), class: "notification tray__item border-radius txt-normal" do
|
||||
concat(
|
||||
link_to(notification.resource,
|
||||
class: "notification__content border-radius shadow fill-white flex align-start txt-align-start gap flex-item-grow max-width border txt-ink",
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
module TranslationsHelper
|
||||
TRANSLATIONS = {
|
||||
user_name: { "🇺🇸": "Enter your name", "🇪🇸": "Introduce tu nombre", "🇫🇷": "Entrez votre nom", "🇮🇳": "अपना नाम दर्ज करें", "🇩🇪": "Geben Sie Ihren Namen ein", "🇧🇷": "Insira seu nome" },
|
||||
email_address: { "🇺🇸": "Enter your email address", "🇪🇸": "Introduce tu correo electrónico", "🇫🇷": "Entrez votre adresse courriel", "🇮🇳": "अपना ईमेल पता दर्ज करें", "🇩🇪": "Geben Sie Ihre E-Mail-Adresse ein", "🇧🇷": "Insira seu endereço de email" },
|
||||
password: { "🇺🇸": "Enter your password", "🇪🇸": "Introduce tu contraseña", "🇫🇷": "Saisissez votre mot de passe", "🇮🇳": "अपना पासवर्ड दर्ज करें", "🇩🇪": "Geben Sie Ihr Passwort ein", "🇧🇷": "Insira sua senha" },
|
||||
collection_name: { "🇺🇸": "Give it a name", "🇪🇸": "Dale un nombre", "🇫🇷": "Donnez lui un nom", "🇮🇳": "इसे एक नाम दें", "🇩🇪": "Gib ihm einen Namen", "🇧🇷": "Dê-lhe um nome" }
|
||||
}
|
||||
|
||||
def translations_for(translation_key)
|
||||
tag.dl(class: "language-list") do
|
||||
TRANSLATIONS[translation_key].map do |language, translation|
|
||||
concat tag.dt(language)
|
||||
concat tag.dd(translation, class: "margin-none")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def translation_button(translation_key)
|
||||
tag.div(class: "position-relative", data: { controller: "popover", action: "keydown.esc->popover#close click@document->popover#closeOnClickOutside", popover_orientation_top_class: "popover-orientation-top" }) do
|
||||
tag.button(type: "button", class: "btn", tabindex: -1, data: { action: "popover#toggle" }) do
|
||||
concat image_tag("globe.svg", class: "icon", role: "presentation")
|
||||
concat tag.span("Translate", class: "for-screen-reader")
|
||||
end +
|
||||
tag.dialog(class: "lanuage-list-menu popover shadow", data: { popover_target: "menu" }) do
|
||||
translations_for(translation_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,4 +2,10 @@ module UsersHelper
|
||||
def prepend_current_user_to(users_scope)
|
||||
users_scope.to_a.prepend(Current.user).uniq
|
||||
end
|
||||
|
||||
def familiar_name_for(user)
|
||||
names = user.name.split
|
||||
return user.name if names.length == 1
|
||||
"#{names.first} #{names[1..].map { |n| "#{n[0]}." }.join}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,4 +9,8 @@ module WorkflowsHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def stage_color(stage)
|
||||
stage.color.presence || Colorable::DEFAULT_COLOR
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Turbo } from "@hotwired/turbo-rails"
|
||||
|
||||
Turbo.StreamActions.set_css_variable = function() {
|
||||
const name = this.getAttribute("name")
|
||||
const value = this.getAttribute("value")
|
||||
|
||||
this.targetElements.forEach(element => element.style.setProperty(name, value))
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
import "initializers/current"
|
||||
import "initializers/custom_stream_actions"
|
||||
|
||||
@@ -15,6 +15,7 @@ class Card < ApplicationRecord
|
||||
|
||||
scope :reverse_chronologically, -> { order created_at: :desc, id: :desc }
|
||||
scope :chronologically, -> { order created_at: :asc, id: :asc }
|
||||
scope :latest, -> { order updated_at: :desc, id: :desc }
|
||||
scope :in_collection, ->(collection) { where collection: collection }
|
||||
|
||||
scope :indexed_by, ->(index) do
|
||||
@@ -24,11 +25,19 @@ class Card < ApplicationRecord
|
||||
when "most_boosted" then ordered_by_boosts
|
||||
when "newest" then reverse_chronologically
|
||||
when "oldest" then chronologically
|
||||
when "latest" then latest
|
||||
when "stalled" then ordered_by_staleness
|
||||
when "closed" then closed
|
||||
end
|
||||
end
|
||||
|
||||
scope :by_engagement_status, ->(status) do
|
||||
case status.to_s
|
||||
when "considering" then considering
|
||||
when "doing" then doing
|
||||
end
|
||||
end
|
||||
|
||||
def cache_key
|
||||
[ super, collection&.name ].compact.join("/")
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module Card::Closeable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
AUTO_CLOSURE_AFTER = 30.days
|
||||
AUTO_CLOSE_AFTER = 30.days
|
||||
|
||||
included do
|
||||
has_one :closure, dependent: :destroy
|
||||
@@ -10,7 +10,7 @@ module Card::Closeable
|
||||
scope :active, -> { where.missing(:closure) }
|
||||
|
||||
scope :recently_closed_first, -> { closed.order("closures.created_at": :desc) }
|
||||
scope :due_to_be_closed, -> { considering.where(last_active_at: ..AUTO_CLOSURE_AFTER.ago) }
|
||||
scope :due_to_be_closed, -> { considering.where(last_active_at: ..AUTO_CLOSE_AFTER.ago) }
|
||||
end
|
||||
|
||||
class_methods do
|
||||
@@ -22,7 +22,7 @@ module Card::Closeable
|
||||
end
|
||||
|
||||
def auto_close_at
|
||||
last_active_at + AUTO_CLOSURE_AFTER if last_active_at
|
||||
last_active_at + AUTO_CLOSE_AFTER if last_active_at
|
||||
end
|
||||
|
||||
def closed?
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
module Card::Colored
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
COLORS = %w[ #b7462b #ff63a8 #eb7a32 #6ac967 #2c6da8 #663251 ]
|
||||
|
||||
included do
|
||||
attribute :color, default: "#2c6da8"
|
||||
def color
|
||||
color_from_stage || Colorable::DEFAULT_COLOR
|
||||
end
|
||||
|
||||
private
|
||||
def color_from_stage
|
||||
stage&.color&.presence if doing?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
module Colorable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
COLORS = %w[ #3b3633 #67695e #eb7a32 #bf7c2b #c09c6f #746b1e #2c6da8 #5d618f #663251 #ff63a8 ]
|
||||
DEFAULT_COLOR = "#2c6da8"
|
||||
|
||||
included do
|
||||
attribute :color, default: DEFAULT_COLOR
|
||||
end
|
||||
end
|
||||
@@ -1,22 +0,0 @@
|
||||
module Filter::Params
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
PERMITTED_PARAMS = %i[
|
||||
indexed_by assignment_status collection_ids creator_ids
|
||||
assignee_ids stage_ids tag_ids terms display_count
|
||||
].freeze
|
||||
|
||||
def as_params
|
||||
self.class.normalize_params(
|
||||
indexed_by: indexed_by,
|
||||
assignment_status: assignment_status,
|
||||
collection_ids: collections.ids,
|
||||
creator_ids: creators.ids,
|
||||
assignee_ids: assignees.ids,
|
||||
stage_ids: stages.ids,
|
||||
tag_ids: tags.ids,
|
||||
terms: terms,
|
||||
display_count: display_count
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -20,6 +20,7 @@ class Filter < ApplicationRecord
|
||||
@cards ||= begin
|
||||
result = creator.accessible_cards.indexed_by(indexed_by)
|
||||
result = result.active unless indexed_by.closed?
|
||||
result = result.by_engagement_status(engagement_status) if engagement_status.present?
|
||||
result = result.unassigned if assignment_status.unassigned?
|
||||
result = result.assigned_to(assignees.ids) if assignees.present?
|
||||
result = result.where(creator_id: creators.ids) if creators.present?
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
module Filter::Fields
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
INDEXES = %w[ most_discussed most_boosted newest oldest stalled ]
|
||||
INDEXES = %w[ most_discussed most_boosted newest oldest latest stalled ]
|
||||
|
||||
delegate :default_value?, to: :class
|
||||
|
||||
class_methods do
|
||||
def default_values
|
||||
{ indexed_by: "most_active" }
|
||||
{ indexed_by: "latest" }
|
||||
end
|
||||
|
||||
def default_value?(key, value)
|
||||
@@ -16,7 +16,7 @@ module Filter::Fields
|
||||
end
|
||||
|
||||
included do
|
||||
store_accessor :fields, :assignment_status, :indexed_by, :terms
|
||||
store_accessor :fields, :assignment_status, :indexed_by, :terms, :engagement_status
|
||||
|
||||
def assignment_status
|
||||
super.to_s.inquiry
|
||||
@@ -26,6 +26,10 @@ module Filter::Fields
|
||||
(super || default_indexed_by).inquiry
|
||||
end
|
||||
|
||||
def engagement_status
|
||||
super&.inquiry
|
||||
end
|
||||
|
||||
def terms
|
||||
Array(super)
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ module Filter::Params
|
||||
PERMITTED_PARAMS = [
|
||||
:assignment_status,
|
||||
:indexed_by,
|
||||
:engagement_status,
|
||||
assignee_ids: [],
|
||||
creator_ids: [],
|
||||
collection_ids: [],
|
||||
@@ -35,6 +36,7 @@ module Filter::Params
|
||||
def as_params
|
||||
{}.tap do |params|
|
||||
params[:indexed_by] = indexed_by
|
||||
params[:engagement_status] = engagement_status
|
||||
params[:assignment_status] = assignment_status
|
||||
params[:terms] = terms
|
||||
params[:tag_ids] = tags.ids
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<% end %>
|
||||
|
||||
<%# FIXME: Move this Current.user check to a stimulus controller that just checks for admin? or the like we so we can cache user list %>
|
||||
<%= button_to account_user_path(user), method: :delete, class: "btn btn--small btn--negative flex-item-no-shrink",
|
||||
<%= button_to account_user_path(user), method: :delete, class: "btn txt-small btn--negative flex-item-no-shrink",
|
||||
disabled: !Current.user.can_administer?(user),
|
||||
data: { turbo_confirm: "Are you sure you want to permanently remove this person from the account?" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<div class="card-count__selector txt-x-small" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<button class="btn borderless btn--circle"
|
||||
data-action="click->dialog#open:stop"
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded="false"
|
||||
aria-controls="display-count-dialog">
|
||||
<span><%= display_count %></span>
|
||||
</button>
|
||||
|
||||
<dialog id="display-count-dialog"
|
||||
class="popup panel flex-column align-start justify-start fill-white shadow"
|
||||
data-dialog-target="dialog"
|
||||
aria-label="Select number of tickets to display">
|
||||
<% display_count_options.each do |option| %>
|
||||
<div class="btn fill-transparent popup__item full-width">
|
||||
<%= form_tag request.path, method: :get, class: "full-width" do %>
|
||||
<% filter.as_params.each do |key, value| %>
|
||||
<% if value.is_a?(Array) %>
|
||||
<% value.each do |v| %>
|
||||
<%= filter_hidden_field_tag key, v %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= hidden_field_tag :set_display_count, option[:value] %>
|
||||
<input type="checkbox"
|
||||
id="<%= option[:id] %>"
|
||||
<%= "checked" if option[:selected] %>
|
||||
onChange="this.form.submit()"
|
||||
aria-label="<%= option[:label] %>">
|
||||
<label for="<%= option[:id] %>" class="overflow-ellipsis"><%= option[:label] %></label>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</dialog>
|
||||
</div>
|
||||
@@ -1 +1 @@
|
||||
<%= turbo_stream.replace([ @card, :assignees ], partial: "cards/display/perma/assignees", locals: { card: @card }) %>
|
||||
<%= turbo_stream.replace([ @card, :meta ], partial: "cards/display/perma/meta", locals: { card: @card }) %>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<%= turbo_frame_tag @card, :assignment do %>
|
||||
<dialog class="popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog">
|
||||
<strong class="popup__title margin-block-start-half pad-inline-half txt-nowrap">Assign this to…</strong>
|
||||
<strong class="popup__title margin-block-start-half pad-inline-half txt-nowrap">Assign this to…</strong>
|
||||
|
||||
<div class="flex flex-column full-width popup__list">
|
||||
<% @card.collection.users.active.alphabetically.each do |user| %>
|
||||
<%= button_to card_assignments_path(@card, params: { assignee_id: user.id }), method: :post, class: "btn popup__item full-width" do %>
|
||||
<span class="overflow-ellipsis"><%= user.name %></span>
|
||||
<%= icon_tag "check", size: 18, class: "checked flex-item-justify-end" if @card.assignees.include?(user) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</dialog>
|
||||
<div class="flex flex-column full-width popup__list">
|
||||
<% @card.collection.users.active.alphabetically.each do |user| %>
|
||||
<%= button_to card_assignments_path(@card, params: { assignee_id: user.id }), method: :post, class: "btn popup__item full-width" do %>
|
||||
<span class="overflow-ellipsis"><%= user.name %></span>
|
||||
<%= icon_tag "check", size: 18, class: "checked flex-item-justify-end" if @card.assignees.include?(user) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
<div class="card card--mini shadow border flex gap position-relative txt-align-start full-width border-radius" style="view-transition-name: <%= dom_id(card, :ticket) %>;">
|
||||
<%= avatar_image_tag card.creator, class: "avatar" %>
|
||||
<div class="card card--mini border flex flex-column gap position-relative txt-align-start full-width border-radius fill-white" style="--card-color: <%= card.color %>; view-transition-name: <%= dom_id(card, :ticket) %>;">
|
||||
<header class="card__header flex align-center gap min-width">
|
||||
<span class="card__collection txt-uppercase overflow-ellipsis txt-reversed">
|
||||
<%= card.collection.name %>
|
||||
</span>
|
||||
|
||||
<div class="overflow-ellipsis"><%= render "cards/display/mini/tags", card: card %></div>
|
||||
</header>
|
||||
|
||||
<div class="card__body flex flex-column gap-half full-width flex-item-grow min-width max-width">
|
||||
<h3 class="card__title">
|
||||
<%= card_title(card) %>
|
||||
</h3>
|
||||
|
||||
<div class="txt-small overflow-ellipsis txt-uppercase"><%= "Added to #{card.collection.name} by #{card.creator.name}" %>
|
||||
<%= local_datetime_tag(card.created_at, style: :daysago) %>
|
||||
<div class="flex align-center gap min-width margin-block-end-half">
|
||||
<h3 class="card__title overflow-ellipsis">
|
||||
<%= card_title(card) %>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="card__stuff flex align-center gap">
|
||||
<%= render "cards/display/mini/assignees", card: card %>
|
||||
<div class="overflow-ellipsis"><%= render "cards/display/mini/tags", card: card %></div>
|
||||
</div>
|
||||
<%= render "cards/display/mini/meta", card: card %>
|
||||
</div>
|
||||
|
||||
<%= link_to collection_card_path(card.collection, card), class: "card__link" do %>
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
</div>
|
||||
|
||||
<footer class="card__footer full-width flex align-start gap">
|
||||
<%= render "cards/display/perma/people", card: card %>
|
||||
<%= render "cards/display/perma/meta", card: card %>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
<%= render "cards/stagings/stages", card: card if card.doing? %>
|
||||
</div>
|
||||
|
||||
<footer class="card__footer full-width flex align-start gap">
|
||||
<%= render "cards/display/preview/people", card: card %>
|
||||
<footer class="card__footer">
|
||||
<%= render "cards/display/preview/meta", card: card %>
|
||||
</footer>
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<span class="for-screen-reader">Assign</span>
|
||||
</button>
|
||||
|
||||
<%= yield %>
|
||||
<dialog class="popup panel flex-column align-start gap-half fill-white shadow" data-dialog-target="dialog">
|
||||
<%= yield %>
|
||||
</dialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
<div class="card__meta flex txt-tight-lines txt-uppercase">
|
||||
<div class="flex flex-column gap txt-align-end">
|
||||
<span class="pad-inline overflow-ellipsis"><%= card.creating? ? "Added" : "Updated" %>
|
||||
<div class="card__meta flex align-center txt-tight-lines txt-uppercase max-width min-width" id="<%= dom_id(card, :meta) %>">
|
||||
<%= avatar_image_tag card.creator, class: "avatar margin-inline-end" %>
|
||||
|
||||
<div class="flex flex-column gap txt-align-start">
|
||||
<span class="pad-inline overflow-ellipsis">Added
|
||||
<%= local_datetime_tag(card.created_at, style: :daysago) %>
|
||||
</span>
|
||||
|
||||
<hr class="full-width separator--horizontal unpad margin-none">
|
||||
|
||||
<span class="pad-inline overflow-ellipsis">
|
||||
Reported by <strong><%= familiar_name_for(card.creator) %></strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<hr class="separator margin-none unpad">
|
||||
|
||||
<div class="flex flex-column gap txt-align-start overflow-ellipsis">
|
||||
<span class="pad-inline overflow-ellipsis"><%= card.creating? ? "Created" : "Updated" %>
|
||||
<%= local_datetime_tag(card.updated_at, style: :daysago) %>
|
||||
</span>
|
||||
|
||||
<hr class="full-width separator--horizontal unpad margin-none">
|
||||
|
||||
<% if card.creating? %>
|
||||
<span class="pad-inline overflow-ellipsis">Expires
|
||||
<%= local_datetime_tag(card.auto_close_at, style: :indays) %>
|
||||
</span>
|
||||
<% else %>
|
||||
<span class="pad-inline overflow-ellipsis">Added
|
||||
<%= local_datetime_tag(card.created_at, style: :daysago) %>
|
||||
</span>
|
||||
<% end %>
|
||||
<span class="pad-inline overflow-ellipsis">
|
||||
Assigned to <%= card.assignees.any? ? card.assignees.map { |assignee| "<strong>#{familiar_name_for(assignee)}</strong>" }.to_sentence.html_safe : "no one" %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<hr class="separator margin-none unpad">
|
||||
|
||||
<div class="flex flex-column gap txt-align-start">
|
||||
<span class="pad-inline overflow-ellipsis">
|
||||
<strong><%= card.comments_count %></strong> <%= card.comments_count == 1 ? "comment" : "comments" %>
|
||||
</span>
|
||||
|
||||
<hr class="full-width separator--horizontal unpad margin-none">
|
||||
|
||||
<div class="margin-inline-start flex-item-no-shrink">
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<div class="card__people flex gap">
|
||||
<div class="flex flex-column align-center">
|
||||
<span class="card__people-label txt-uppercase">Reported</span>
|
||||
<%= avatar_tag card.creator, class: "avatar" %>
|
||||
</div>
|
||||
|
||||
<div class="card__assignees flex flex-column align-center">
|
||||
<span class="card__people-label txt-uppercase">Assigned</span>
|
||||
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,12 +3,5 @@
|
||||
<% card.assignees.each do |assignee| %>
|
||||
<%= avatar_tag assignee, class: "avatar" %>
|
||||
<% end %>
|
||||
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<button class="btn card__hide-on-index <%= card.creating? || card.drafted? ? "fill-highlight" : "fill-transparent" %>" data-action="click->dialog#open:stop">
|
||||
<%= icon_tag "add" %>
|
||||
<span class="for-screen-reader">Assign</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<%= render "cards/display/common/meta", card: card do %>
|
||||
<%= render "cards/display/mini/assignees", card: card %>
|
||||
<% end %>
|
||||
@@ -1,3 +0,0 @@
|
||||
<%= turbo_frame_tag dom_id(card, :boosts) do %>
|
||||
<%= render "cards/boosts/boosts", card: card %>
|
||||
<% end %>
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= render "cards/display/common/meta", card: card do %>
|
||||
<%= render "cards/display/perma/boosts", card: card %>
|
||||
<%= render "cards/display/perma/assignees", card: card %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<%= render "cards/display/common/people", card: card do%>
|
||||
<%= render "cards/display/perma/assignees", card: card %>
|
||||
<% end %>
|
||||
@@ -1,8 +0,0 @@
|
||||
<%= turbo_frame_tag dom_id(card, :boosts) do %>
|
||||
<%= tag.div class: "pad-inline flex align-center gap" do %>
|
||||
<span class="overflow-ellipsis">
|
||||
<strong><%= card.boosts_count %></strong>
|
||||
<span><%= card.boosts_count == 1 ? "boost" : "boosts" %></span>
|
||||
</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= render "cards/display/common/meta", card: card do %>
|
||||
<%= render "cards/display/preview/boosts", card: card %>
|
||||
<%= render "cards/display/preview/assignees", card: card %>
|
||||
<% end %>
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<% end %>
|
||||
|
||||
<div class="card-columns">
|
||||
<%= render "cards/index/engagement/considering", cards: @considering_cards %>
|
||||
<%= render "cards/index/engagement/doing", cards: @doing_cards, filter: @filter %>
|
||||
<%= render "cards/index/engagement/considering", **@considering.to_h %>
|
||||
<%= render "cards/index/engagement/doing", **@doing.to_h %>
|
||||
</div>
|
||||
|
||||
<%= render "cards/index/engagement/closed", cards: @closed_cards, filter: @filter %>
|
||||
<%= render "cards/index/engagement/closed", **@closed.to_h %>
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
<%= render "cards/index/collections_filter", filter: filter %>
|
||||
</dialog>
|
||||
</div>
|
||||
|
||||
<%= render "cards/index/sorting_options", filter: filter %>
|
||||
</header>
|
||||
|
||||
<% if collection = filter.single_collection %>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<div class="card-filter--sorting flex-inline">
|
||||
<%= form_with url: cards_path, method: :get do |form| %>
|
||||
<% filter.as_params.except(:indexed_by).each do |key, value| %>
|
||||
<%= filter_hidden_field_tag key, value %>
|
||||
<% end %>
|
||||
|
||||
<%= form.hidden_field :indexed_by, value: filter.indexed_by == "oldest" ? "newest" : "oldest" %>
|
||||
|
||||
<button class="btn borderless txt-medium">
|
||||
<%= icon_tag filter.indexed_by == "oldest" ? "sort-ascending" : "sort-descending", size: 24, aria: { hidden: true } %>
|
||||
<span class="for-screen-reader">Sort by <%= filter.indexed_by == "oldest" ? "newest" : "oldest" %></span>
|
||||
</button>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -3,9 +3,13 @@
|
||||
Recently closed
|
||||
</h2>
|
||||
|
||||
<section class="cards cards--closed">
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/preview", collection: cards, as: :card, cached: true %>
|
||||
<section id="closed-cards" class="cards cards--closed">
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "closed-cards", page: page, filter: filter, fetch_on_visible: true %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<section class="cards cards--considering">
|
||||
<section id="considering-cards" class="cards cards--considering">
|
||||
<h2 class="txt-align-center flex-inline center txt-uppercase txt-medium margin-none-block">
|
||||
Considering
|
||||
</h2>
|
||||
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/preview", collection: cards, as: :card, cached: true %>
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "considering-cards", page: page, filter: filter %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<section class="cards cards--doing" style="view-transition-name: cards-container;" data-controller="card-size" data-action="turbo:morph@window->card-size#resize">
|
||||
<section id="doing-cards" class="cards cards--doing" style="view-transition-name: cards-container;" data-controller="card-size" data-action="turbo:morph@window->card-size#resize">
|
||||
<% if workflow = filter.single_workflow %>
|
||||
<%= render "cards/index/workflow_filter", workflow: workflow, filter: filter %>
|
||||
<% else %>
|
||||
@@ -7,8 +7,12 @@
|
||||
</h2>
|
||||
<% end %>
|
||||
|
||||
<% if cards.any? %>
|
||||
<%= render partial: "cards/display/preview", collection: cards, as: :card, cached: true %>
|
||||
<% if page.used? %>
|
||||
<%= render partial: "cards/display/preview", collection: page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless page.last? %>
|
||||
<%= cards_next_page_link "doing-cards", page: page, filter: filter %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="txt-medium translucent">Nothing here</p>
|
||||
<% end %>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<%= turbo_stream.remove "#{params[:target]}-load-page-#{@page.number}" %>
|
||||
|
||||
<%= turbo_stream.append params[:target] do %>
|
||||
<%= render partial: @filter.engagement_status&.considering? ? "cards/display/mini" : "cards/display/preview",
|
||||
collection: @page.records, as: :card, cached: true %>
|
||||
|
||||
<% unless @page.last? %>
|
||||
<%= cards_next_page_link params[:target], page: @page, filter: @filter, fetch_on_visible: @filter.indexed_by.closed? %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
@@ -28,14 +28,13 @@
|
||||
<%= render "cards/doing_toggle", card: @card %>
|
||||
|
||||
<div data-controller="beacon" data-beacon-url-value="<%= card_reading_url(@card) %>">
|
||||
<section class="card-perma <%= "card-perma--pointing" unless @card.published? %>" style="--card-color: <%= @card.color %>;">
|
||||
<section id="<%= dom_id(@card, :card_container) %>" class="card-perma <%= "card-perma--pointing" unless @card.published? %>" style="--card-color: <%= @card.color %>;">
|
||||
<aside class="card-perma__actions" role="toolbar">
|
||||
<button class="btn">
|
||||
<%= icon_tag "star" %>
|
||||
<span class="for-screen-reader">Star this card</span>
|
||||
<input type="checkbox" class="card-perma__star-input">
|
||||
</button>
|
||||
<%= render "cards/color", card: @card %>
|
||||
<%= render "cards/image", card: @card %>
|
||||
<%= button_to collection_card_path(@card.collection, @card),
|
||||
method: :delete,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<%= turbo_stream.replace dom_id(@card, "stages") do %>
|
||||
<%= render partial: "cards/stagings/stages", locals: { card: @card } %>
|
||||
<% end %>
|
||||
|
||||
<%= turbo_stream.set_css_variable dom_id(@card, :card_container), name: "--card-color", value: @card.color %>
|
||||
<%= turbo_stream.set_css_variable dom_id(@card, :ticket), name: "--card-color", value: @card.color %>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<li class="collection flex flex-column txt-align-center max-width">
|
||||
<%= link_to cards_path(collection_ids: [ collection ]),
|
||||
class: "border border-radius margin-block-end-half cards__container flex justify-center align-center position-relative",
|
||||
aria: { hidden: true }, tabindex: -1 do %>
|
||||
<div class="cards collection__cards flex flex-wrap gap justify-center align-end" style="view-transition-name: cards_<%= collection.id %>">
|
||||
<% collection.cards.active.published_or_drafted_by(Current.user).ordered_by_activity.limit(10).each do |card| %>
|
||||
<div class="<%= class_names("card", drafted: card.drafted?) %>" style="--card-color: <%= card.color %>; <%= card_rotation(card) %>"
|
||||
data-card-size-target="card"
|
||||
data-activity-score="<%= card.activity_score %>"
|
||||
data-activity-score-at="<%= card.activity_score_at.to_i %>">
|
||||
<span class="card__shape"></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex align-center justify-center flex-column flex-wrap center gap-half position-relative full-width">
|
||||
<%= link_to cards_path(collection_ids: [ collection ]), class: "txt-ink flex flex-column" do %>
|
||||
<strong class="txt-large"><%= collection.name %></strong>
|
||||
<% end %>
|
||||
|
||||
<%= link_to edit_collection_path(collection), class: "btn txt-small collection__button" do %>
|
||||
<%= icon_tag "settings" %>
|
||||
<span class="for-screen-reader">Settings for <%= collection.name %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
</li>
|
||||
@@ -16,8 +16,6 @@
|
||||
<div class="panel shadow center" style="--panel-size: 55ch;">
|
||||
<%= form_with model: @collection, class: "flex flex-column gap txt-large", data: { controller: "form" } do |form| %>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button(:collection_name) %>
|
||||
|
||||
<label class="flex-item-grow txt-large">
|
||||
<strong><%= form.text_field :name, name: "collection[name]", class: "input full-width",
|
||||
required: true, autofocus: true, placeholder: "Give it a name…",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<%= turbo_frame_tag comment, :new_reaction do %>
|
||||
<div class="flex-inline" data-controller="soft-keyboard">
|
||||
<%= link_to new_collection_card_comment_reaction_path(comment.card.collection, comment.card, comment), role: "button",
|
||||
class: "txt-small btn reaction__action", action: "soft-keyboard#open" do %>
|
||||
class: "btn reaction__action", action: "soft-keyboard#open" do %>
|
||||
<%= icon_tag "reaction" %>
|
||||
<span class="for-screen-reader">Add a reaction</span>
|
||||
<% end %>
|
||||
|
||||
@@ -173,7 +173,6 @@
|
||||
|
||||
<div class="flex align-center txt-align-center justify-space-between gap-half margin-block-start">
|
||||
<%= tag.button class: "btn", form: :filter_form, formaction: filters_path, formmethod: :post do %>
|
||||
<%= icon_tag "cards" %>
|
||||
<span>Save collection</span>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
<% cache_if filter.cacheable?, filter do %>
|
||||
<li class="collection flex flex-column txt-align-center max-width position-relative">
|
||||
<%= link_to cards_path(**filter.as_params),
|
||||
class: "border border-radius margin-block-end-half cards__container flex justify-center align-center position-relative",
|
||||
aria: { hidden: true }, tabindex: -1 do %>
|
||||
<div class="cards collection__cards flex flex-wrap gap justify-center align-end" style="view-transition-name: cards_<%= filter.id %>">
|
||||
<% filter.cards.ordered_by_activity.limit(10).each do |card| %>
|
||||
<div class="<%= class_names("card", drafted: card.drafted?) %>" style="--card-color: <%= card.color %>; <%= card_rotation(card) %>"
|
||||
data-card-size-target="card"
|
||||
data-activity-score="<%= card.activity_score %>"
|
||||
data-activity-score-at="<%= card.activity_score_at.to_i %>">
|
||||
<span class="card__shape"></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex align-center justify-center flex-column flex-wrap center gap-half position-relative full-width">
|
||||
<%= link_to cards_path(**filter.as_params), class: "txt-ink" do %>
|
||||
<strong class="txt-medium"><%= icon_tag "filter", class: "flex-inline", style: "vertical-align: bottom" %> <%= filter.summary %></strong>
|
||||
<% end %>
|
||||
<%= button_to filter_path(filter), method: :delete, class: "btn txt-small btn--negative collection__button", data: { turbo_confirm: "Are you sure you want to delete this filter?" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Delete</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</li>
|
||||
<% end %>
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
<%= form_with model: User.new, url: first_run_path, class: "flex flex-column gap txt-large" do |form| %>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :user_name %>
|
||||
<label class="flex align-center gap input input--actor txt-large">
|
||||
<%= form.text_field :name, class: "input", autocomplete: "name", placeholder: "Name", autofocus: true, required: true, data: { "1p-ignore": true } %>
|
||||
<%= icon_tag "person", class: "txt-large" %>
|
||||
@@ -13,7 +12,6 @@
|
||||
</div>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :email_address %>
|
||||
<label class="flex align-center gap input input--actor txt-large">
|
||||
<%= form.email_field :email_address, class: "input", autocomplete: "username", placeholder: "Email address", required: true %>
|
||||
<%= icon_tag "email", class: "txt-large" %>
|
||||
@@ -21,7 +19,6 @@
|
||||
</div>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :password %>
|
||||
<label class="flex align-center gap input input--actor txt-large">
|
||||
<%= form.password_field :password, class: "input", autocomplete: "new-password", placeholder: "Password", required: true, maxlength: 72 %>
|
||||
<%= icon_tag "password", class: "txt-large" %>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% cache pin do %>
|
||||
<%= tag.div id: dom_id(pin), class: "pin tray__item flex txt-normal" do %>
|
||||
<%= tag.div id: dom_id(pin), class: "pin tray__item txt-normal" do %>
|
||||
<%= link_to collection_card_path(pin.card.collection, pin.card),
|
||||
class: "pin__content shadow fill-white flex align-start txt-align-start gap flex-item-grow max-width border border-radius txt-ink overflow-clip",
|
||||
data: { action: "click->dialog#close", turbo_frame: "_top" },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% cache [notification, "2025-03-20"] do %>
|
||||
<% cache [notification, "2025-04-09"] do %>
|
||||
<%= notification_tag notification do %>
|
||||
<div class="avatar txt-x-small flex-item-no-shrink">
|
||||
<%= avatar_image_tag(notification.creator) %>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
<%= form_with url: session_path, class: "flex flex-column gap txt-large" do |form| %>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :email_address %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.email_field :email_address, required: true, class: "input full-width", autofocus: true, autocomplete: "username", placeholder: "Enter your email address" %>
|
||||
<%= icon_tag "email", class: "txt-large" %>
|
||||
@@ -13,7 +12,6 @@
|
||||
</div>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :password %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.password_field :password, required: true, class: "input full-width", autocomplete: "current-password", placeholder: "Enter your password", maxlength: 72 %>
|
||||
<%= icon_tag "password", class: "txt-large" %>
|
||||
|
||||
@@ -29,21 +29,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :user_name %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.text_field :name, class: "input full-width", autocomplete: "name", placeholder: "Name", autofocus: true, required: true, data: { "1p-ignore": true, action: "keydown.esc@document->form#cancel" } %>
|
||||
<%= icon_tag "person", class: "txt-large" %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :email_address %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.email_field :email_address, class: "input full-width", autocomplete: "username", placeholder: "Email address", required: true %>
|
||||
<%= icon_tag "email", class: "txt-large" %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :password %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.password_field :password, class: "input full-width", autocomplete: "new-password", placeholder: "Password", required: false, maxlength: 72 %>
|
||||
<%= icon_tag "password", class: "txt-large" %>
|
||||
|
||||
@@ -13,21 +13,18 @@
|
||||
|
||||
<%= form_with model: @user, url: join_path(@account.join_code), class: "flex flex-column gap" do |form| %>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :user_name %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.text_field :name, class: "input full-width", autocomplete: "name", placeholder: "Name", autofocus: true, required: true, data: { "1p-ignore": true } %>
|
||||
<%= icon_tag "person", class: "txt-large" %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :email_address %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.email_field :email_address, class: "input full-width", autocomplete: "username", placeholder: "Email address", required: true %>
|
||||
<%= icon_tag "email", class: "txt-large" %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex align-center gap">
|
||||
<%= translation_button :password %>
|
||||
<label class="flex align-center gap input input--actor">
|
||||
<%= form.password_field :password, class: "input full-width", autocomplete: "new-password", placeholder: "Password", required: true, maxlength: 72 %>
|
||||
<%= icon_tag "password", class: "txt-large" %>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<%= turbo_frame_tag dom_id(workflow, :stages) do %>
|
||||
<%= render partial: "workflows/stages/stage", collection: workflow.stages %>
|
||||
|
||||
<%= link_to new_workflow_stage_path(workflow), class: "btn btn--small" do %>
|
||||
<%= link_to new_workflow_stage_path(workflow), class: "btn txt-small" do %>
|
||||
<%= icon_tag "add" %>
|
||||
<span class="for-screen-reader">New stage</span>
|
||||
<% end %>
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
<%= link_to "Cancel", workflow_path(@workflow), data: { form_target: "cancel", turbo_frame: dom_id(@workflow) }, hidden: true %>
|
||||
<% end %>
|
||||
|
||||
<%= tag.button type: :submit, class: "btn btn--small btn--positive", form: dom_id(@workflow, :form) do %>
|
||||
<%= tag.button type: :submit, class: "btn txt-small btn--positive", form: dom_id(@workflow, :form) do %>
|
||||
<%= icon_tag "check" %>
|
||||
<span class="for-screen-reader">Save</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to workflow_path(@workflow), class: "btn btn--small", data: { turbo_frame: dom_id(@workflow) } do %>
|
||||
<%= link_to workflow_path(@workflow), class: "btn txt-small", data: { turbo_frame: dom_id(@workflow) } do %>
|
||||
<%= icon_tag "remove-med" %>
|
||||
<span class="for-screen-reader">Cancel</span>
|
||||
<% end %>
|
||||
|
||||
<%= button_to workflow_path(@workflow), method: :delete, class: "btn btn--small btn--negative", data: { turbo_frame: :workflows, turbo_confirm: "Are you sure you want to delete this workflow?" } do %>
|
||||
<%= button_to workflow_path(@workflow), method: :delete, class: "btn txt-small btn--negative", data: { turbo_frame: :workflows, turbo_confirm: "Are you sure you want to delete this workflow?" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Delete <%= @workflow.name %></span>
|
||||
<% end %>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<div class="position-relative" data-controller="dialog" data-action="keydown.esc->dialog#close">
|
||||
<button class="btn" data-action="dialog#open:stop">
|
||||
<button class="btn btn--reversed txt-x-small" data-action="dialog#open:stop" style="--btn-background: <%= stage_color(stage) %>">
|
||||
<%= icon_tag "art" %>
|
||||
<span class="for-screen-reader">Change color</span>
|
||||
</button>
|
||||
|
||||
<dialog class="color-picker panel fill-white shadow gap-half" data-dialog-target="dialog" data-action="keydown.esc->dialog#close click@document->dialog#closeOnClickOutside">
|
||||
<%= form_with model: card, url: collection_card_path(card.collection, card), class: "flex gap-half", data: { controller: "form", action: "change->form#submit" } do |form| %>
|
||||
<% Card::COLORS.each do |color| %>
|
||||
<%= form_with model: stage, url: workflow_stage_path(stage.workflow, stage), class: "flex gap-half", data: { controller: "form", action: "change->form#submit" } do |form| %>
|
||||
<% Colorable::COLORS.each do |color| %>
|
||||
<span class="color-picker__color">
|
||||
<label class="btn btn--circle" style="--btn-background: <%= color %>" title="<%= color %>">
|
||||
<%= form.radio_button :color, color %>
|
||||
@@ -1,7 +1,9 @@
|
||||
<div class="flex gap-half align-center justify-space-between">
|
||||
<div class="flex gap-half align-center">
|
||||
<%= render "workflows/stages/color", stage: stage %>
|
||||
|
||||
<%= turbo_frame_tag stage do %>
|
||||
<%= link_to edit_workflow_stage_path(stage.workflow, stage) do %>
|
||||
<strong class="txt-nowrap overflow-ellipsis"><%= stage.name %></strong>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -5,18 +5,18 @@
|
||||
<% end %>
|
||||
|
||||
<div class="flex align-center gap-half">
|
||||
<%= tag.button type: :submit, class: "btn btn--small btn--positive", form: dom_id(@stage, :form) do %>
|
||||
<%= tag.button type: :submit, class: "btn txt-small btn--positive", form: dom_id(@stage, :form) do %>
|
||||
<%= icon_tag "check" %>
|
||||
<span class="for-screen-reader">Save</span>
|
||||
<% end %>
|
||||
|
||||
<%= link_to workflow_path(@workflow), class: "btn btn--small", data: { turbo_frame: dom_id(@workflow) } do %>
|
||||
<%= link_to workflow_path(@workflow), class: "btn txt-small", data: { turbo_frame: dom_id(@workflow) } do %>
|
||||
<%= icon_tag "remove-med" %>
|
||||
<span class="for-screen-reader">Cancel</span>
|
||||
<% end %>
|
||||
|
||||
<% if @stage.workflow.stages.many? %>
|
||||
<%= button_to workflow_stage_path(@stage.workflow, @stage), method: :delete, class: "btn btn--negative btn--small",
|
||||
<%= button_to workflow_stage_path(@stage.workflow, @stage), method: :delete, class: "btn btn--negative txt-small",
|
||||
data: { turbo_frame: dom_id(@workflow), turbo_confirm: "Are you sure you want to delete this stage?" } do %>
|
||||
<%= icon_tag "minus" %>
|
||||
<span class="for-screen-reader">Delete <%= @stage.name %></span>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<%= icon_tag "check" %>
|
||||
<span class="for-screen-reader">Add stage</span>
|
||||
<% end %>
|
||||
<%= link_to workflow_path(@workflow), class: "btn btn--small", data: { form_target: "cancel", controller: "hotkey", action: "keydown.esc@document->hotkey#click" } do %>
|
||||
<%= link_to workflow_path(@workflow), class: "btn txt-small", data: { form_target: "cancel", controller: "hotkey", action: "keydown.esc@document->hotkey#click" } do %>
|
||||
<%= icon_tag "remove-med" %>
|
||||
<span class="for-screen-reader">Cancel</span>
|
||||
<% end %>
|
||||
|
||||
@@ -8,6 +8,10 @@ Rails.application.routes.draw do
|
||||
end
|
||||
end
|
||||
|
||||
namespace :cards do
|
||||
resources :previews
|
||||
end
|
||||
|
||||
resources :cards do
|
||||
scope module: :cards do
|
||||
resource :engagement
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddColorToWorkflowStages < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
add_column :workflow_stages, :color, :string
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class RemoveColorFromCards < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
remove_column :cards, :color, :string
|
||||
end
|
||||
end
|
||||