git.iko.soy/purestack-dev/purescript-plum
on master help sign in
Added links, downloads and colors
commitef55c2ad64edef5ce97c1633e09ab880ab01a695 authoriko <mail@iko.soy> dateSun 18 May 2025, 21:28 (1 year ago) parentfd949c8
5 files changed+536−39
plum/index.js+447−28 plum/spago.dhall+2 plum/src/Main.purs+7−2 plum/src/Plum.purs+1−1 plum/src/Plum/View.purs+79−8
plum/index.js+447−28
@@ -1,4 +1,31 @@
11(() => {
2+ // output/Control.Semigroupoid/index.js
3+ var semigroupoidFn = {
4+ compose: function(f) {
5+ return function(g) {
6+ return function(x) {
7+ return f(g(x));
8+ };
9+ };
10+ }
11+ };
12+
13+ // output/Control.Category/index.js
14+ var identity = function(dict) {
15+ return dict.identity;
16+ };
17+ var categoryFn = {
18+ identity: function(x) {
19+ return x;
20+ },
21+ Semigroupoid0: function() {
22+ return semigroupoidFn;
23+ }
24+ };
25+
26+ // output/Data.Boolean/index.js
27+ var otherwise = true;
28+
229 // output/Data.Function/index.js
330 var flip = function(f) {
431 return function(b) {
@@ -145,17 +172,101 @@
145172 };
146173
147174 // output/Data.Bounded/foreign.js
175+ var topInt = 2147483647;
176+ var bottomInt = -2147483648;
148177 var topChar = String.fromCharCode(65535);
149178 var bottomChar = String.fromCharCode(0);
150179 var topNumber = Number.POSITIVE_INFINITY;
151180 var bottomNumber = Number.NEGATIVE_INFINITY;
152181
182+ // output/Data.Ord/foreign.js
183+ var unsafeCompareImpl = function(lt) {
184+ return function(eq2) {
185+ return function(gt) {
186+ return function(x) {
187+ return function(y) {
188+ return x < y ? lt : x === y ? eq2 : gt;
189+ };
190+ };
191+ };
192+ };
193+ };
194+ var ordIntImpl = unsafeCompareImpl;
195+
196+ // output/Data.Eq/foreign.js
197+ var refEq = function(r1) {
198+ return function(r2) {
199+ return r1 === r2;
200+ };
201+ };
202+ var eqIntImpl = refEq;
203+
204+ // output/Data.Eq/index.js
205+ var eqInt = {
206+ eq: eqIntImpl
207+ };
208+
209+ // output/Data.Ordering/index.js
210+ var LT = /* @__PURE__ */ function() {
211+ function LT2() {
212+ }
213+ ;
214+ LT2.value = new LT2();
215+ return LT2;
216+ }();
217+ var GT = /* @__PURE__ */ function() {
218+ function GT2() {
219+ }
220+ ;
221+ GT2.value = new GT2();
222+ return GT2;
223+ }();
224+ var EQ = /* @__PURE__ */ function() {
225+ function EQ2() {
226+ }
227+ ;
228+ EQ2.value = new EQ2();
229+ return EQ2;
230+ }();
231+
232+ // output/Data.Ord/index.js
233+ var ordInt = /* @__PURE__ */ function() {
234+ return {
235+ compare: ordIntImpl(LT.value)(EQ.value)(GT.value),
236+ Eq0: function() {
237+ return eqInt;
238+ }
239+ };
240+ }();
241+
242+ // output/Data.Bounded/index.js
243+ var top = function(dict) {
244+ return dict.top;
245+ };
246+ var boundedInt = {
247+ top: topInt,
248+ bottom: bottomInt,
249+ Ord0: function() {
250+ return ordInt;
251+ }
252+ };
253+ var bottom = function(dict) {
254+ return dict.bottom;
255+ };
256+
153257 // output/Data.Show/foreign.js
154258 var showIntImpl = function(n) {
155259 return n.toString();
156260 };
261+ var showNumberImpl = function(n) {
262+ var str = n.toString();
263+ return isNaN(str + ".0") ? str : str + ".0";
264+ };
157265
158266 // output/Data.Show/index.js
267+ var showNumber = {
268+ show: showNumberImpl
269+ };
159270 var showInt = {
160271 show: showIntImpl
161272 };
@@ -164,6 +275,7 @@
164275 };
165276
166277 // output/Data.Maybe/index.js
278+ var identity2 = /* @__PURE__ */ identity(categoryFn);
167279 var Nothing = /* @__PURE__ */ function() {
168280 function Nothing2() {
169281 }
@@ -181,6 +293,24 @@
181293 };
182294 return Just2;
183295 }();
296+ var maybe = function(v) {
297+ return function(v1) {
298+ return function(v2) {
299+ if (v2 instanceof Nothing) {
300+ return v;
301+ }
302+ ;
303+ if (v2 instanceof Just) {
304+ return v1(v2.value0);
305+ }
306+ ;
307+ throw new Error("Failed pattern match at Data.Maybe (line 237, column 1 - line 237, column 51): " + [v.constructor.name, v1.constructor.name, v2.constructor.name]);
308+ };
309+ };
310+ };
311+ var fromMaybe = function(a) {
312+ return maybe(a)(identity2);
313+ };
184314
185315 // output/Data.Monoid/index.js
186316 var monoidArray = {
@@ -1202,9 +1332,9 @@
12021332 }
12031333 function replace(projector) {
12041334 return function(el) {
1205− return function(render) {
1335+ return function(render3) {
12061336 return function() {
1207− projector.replace(el, render);
1337+ projector.replace(el, render3);
12081338 };
12091339 };
12101340 };
@@ -1214,6 +1344,51 @@
12141344 var string = unsafeCoerce2;
12151345 var h2 = _h;
12161346
1347+ // output/Data.Int/foreign.js
1348+ var fromNumberImpl = function(just) {
1349+ return function(nothing) {
1350+ return function(n) {
1351+ return (n | 0) === n ? just(n) : nothing;
1352+ };
1353+ };
1354+ };
1355+ var toNumber = function(n) {
1356+ return n;
1357+ };
1358+
1359+ // output/Data.Number/foreign.js
1360+ var isFiniteImpl = isFinite;
1361+ var round = Math.round;
1362+
1363+ // output/Data.Int/index.js
1364+ var top2 = /* @__PURE__ */ top(boundedInt);
1365+ var bottom2 = /* @__PURE__ */ bottom(boundedInt);
1366+ var fromNumber = /* @__PURE__ */ function() {
1367+ return fromNumberImpl(Just.create)(Nothing.value);
1368+ }();
1369+ var unsafeClamp = function(x) {
1370+ if (!isFiniteImpl(x)) {
1371+ return 0;
1372+ }
1373+ ;
1374+ if (x >= toNumber(top2)) {
1375+ return top2;
1376+ }
1377+ ;
1378+ if (x <= toNumber(bottom2)) {
1379+ return bottom2;
1380+ }
1381+ ;
1382+ if (otherwise) {
1383+ return fromMaybe(0)(fromNumber(x));
1384+ }
1385+ ;
1386+ throw new Error("Failed pattern match at Data.Int (line 72, column 1 - line 72, column 29): " + [x.constructor.name]);
1387+ };
1388+ var round2 = function($37) {
1389+ return unsafeClamp(round($37));
1390+ };
1391+
12171392 // output/Foreign.Object/foreign.js
12181393 function _copyST(m) {
12191394 return function() {
@@ -1321,8 +1496,28 @@
13211496 });
13221497 };
13231498
1499+ // output/Record.Unsafe.Union/foreign.js
1500+ function unsafeUnionFn(r1, r2) {
1501+ var copy = {};
1502+ for (var k1 in r2) {
1503+ if ({}.hasOwnProperty.call(r2, k1)) {
1504+ copy[k1] = r2[k1];
1505+ }
1506+ }
1507+ for (var k2 in r1) {
1508+ if ({}.hasOwnProperty.call(r1, k2)) {
1509+ copy[k2] = r1[k2];
1510+ }
1511+ }
1512+ return copy;
1513+ }
1514+
1515+ // output/Record.Unsafe.Union/index.js
1516+ var unsafeUnion = /* @__PURE__ */ runFn2(unsafeUnionFn);
1517+
13241518 // output/Plum.View/index.js
13251519 var show2 = /* @__PURE__ */ show(showInt);
1520+ var show1 = /* @__PURE__ */ show(showNumber);
13261521 var append1 = /* @__PURE__ */ append(semigroupArray);
13271522 var mempty2 = /* @__PURE__ */ mempty(monoidArray);
13281523 var map2 = /* @__PURE__ */ map(functorArray);
@@ -1350,6 +1545,32 @@
13501545 Fit2.value = new Fit2();
13511546 return Fit2;
13521547 }();
1548+ var Max2 = /* @__PURE__ */ function() {
1549+ function Max3(value0, value1) {
1550+ this.value0 = value0;
1551+ this.value1 = value1;
1552+ }
1553+ ;
1554+ Max3.create = function(value0) {
1555+ return function(value1) {
1556+ return new Max3(value0, value1);
1557+ };
1558+ };
1559+ return Max3;
1560+ }();
1561+ var Min2 = /* @__PURE__ */ function() {
1562+ function Min3(value0, value1) {
1563+ this.value0 = value0;
1564+ this.value1 = value1;
1565+ }
1566+ ;
1567+ Min3.create = function(value0) {
1568+ return function(value1) {
1569+ return new Min3(value0, value1);
1570+ };
1571+ };
1572+ return Min3;
1573+ }();
13531574 var X = /* @__PURE__ */ function() {
13541575 function X2() {
13551576 }
@@ -1476,6 +1697,70 @@
14761697 Wrapped2.value = new Wrapped2();
14771698 return Wrapped2;
14781699 }();
1700+ var BackgroundColor = /* @__PURE__ */ function() {
1701+ function BackgroundColor2(value0) {
1702+ this.value0 = value0;
1703+ }
1704+ ;
1705+ BackgroundColor2.create = function(value0) {
1706+ return new BackgroundColor2(value0);
1707+ };
1708+ return BackgroundColor2;
1709+ }();
1710+ var Padding = /* @__PURE__ */ function() {
1711+ function Padding2(value0) {
1712+ this.value0 = value0;
1713+ }
1714+ ;
1715+ Padding2.create = function(value0) {
1716+ return new Padding2(value0);
1717+ };
1718+ return Padding2;
1719+ }();
1720+ var Spread = /* @__PURE__ */ function() {
1721+ function Spread2() {
1722+ }
1723+ ;
1724+ Spread2.value = new Spread2();
1725+ return Spread2;
1726+ }();
1727+ var Opacity = /* @__PURE__ */ function() {
1728+ function Opacity2(value0) {
1729+ this.value0 = value0;
1730+ }
1731+ ;
1732+ Opacity2.create = function(value0) {
1733+ return new Opacity2(value0);
1734+ };
1735+ return Opacity2;
1736+ }();
1737+ var Pointer = /* @__PURE__ */ function() {
1738+ function Pointer2() {
1739+ }
1740+ ;
1741+ Pointer2.value = new Pointer2();
1742+ return Pointer2;
1743+ }();
1744+ var Move = /* @__PURE__ */ function() {
1745+ function Move2(value0) {
1746+ this.value0 = value0;
1747+ }
1748+ ;
1749+ Move2.create = function(value0) {
1750+ return new Move2(value0);
1751+ };
1752+ return Move2;
1753+ }();
1754+ var Clip = /* @__PURE__ */ function() {
1755+ function Clip2(value0) {
1756+ this.value0 = value0;
1757+ }
1758+ ;
1759+ Clip2.create = function(value0) {
1760+ return new Clip2(value0);
1761+ };
1762+ return Clip2;
1763+ }();
14791764 var Column = /* @__PURE__ */ function() {
14801765 function Column2(value0) {
14811766 this.value0 = value0;
@@ -1526,6 +1811,38 @@
15261811 };
15271812 return Text2;
15281813 }();
1814+ var Link = /* @__PURE__ */ function() {
1815+ function Link2(value0, value1, value22) {
1816+ this.value0 = value0;
1817+ this.value1 = value1;
1818+ this.value2 = value22;
1819+ }
1820+ ;
1821+ Link2.create = function(value0) {
1822+ return function(value1) {
1823+ return function(value22) {
1824+ return new Link2(value0, value1, value22);
1825+ };
1826+ };
1827+ };
1828+ return Link2;
1829+ }();
1830+ var Download = /* @__PURE__ */ function() {
1831+ function Download2(value0, value1, value22) {
1832+ this.value0 = value0;
1833+ this.value1 = value1;
1834+ this.value2 = value22;
1835+ }
1836+ ;
1837+ Download2.create = function(value0) {
1838+ return function(value1) {
1839+ return function(value22) {
1840+ return new Download2(value0, value1, value22);
1841+ };
1842+ };
1843+ };
1844+ return Download2;
1845+ }();
15291846 var semigroupSkin = {
15301847 append: function(v) {
15311848 return function(v1) {
@@ -1543,6 +1860,11 @@
15431860 };
15441861 }
15451862 };
1863+ var renderableColor = {
1864+ render: function(v) {
1865+ return "rgba(" + (show2(v.r) + ("," + (show2(v.g) + ("," + (show2(v.b) + ("," + (show1(v.a) + ")")))))));
1866+ }
1867+ };
15461868 var monoidSkin = {
15471869 mempty: empty2,
15481870 Semigroup0: function() {
@@ -1576,21 +1898,48 @@
15761898 return singleton2(key)(val);
15771899 };
15781900 };
1579− var length2 = function(v) {
1580− if (v instanceof Px) {
1581− return show2(v.value0) + "px";
1582− }
1583− ;
1584− if (v instanceof Fit) {
1585− return "fit-content";
1586− }
1587− ;
1588− if (v instanceof Fill) {
1589− return "100%";
1901+ var rgb = function(r) {
1902+ return function(g) {
1903+ return function(b) {
1904+ return {
1905+ r: round2(r * 255),
1906+ g: round2(g * 255),
1907+ b: round2(b * 255),
1908+ a: 1
1909+ };
1910+ };
1911+ };
1912+ };
1913+ var render = function(dict) {
1914+ return dict.render;
1915+ };
1916+ var render1 = /* @__PURE__ */ render(renderableColor);
1917+ var renderableLength = {
1918+ render: function(v) {
1919+ if (v instanceof Px) {
1920+ return show2(v.value0) + "px";
1921+ }
1922+ ;
1923+ if (v instanceof Fit) {
1924+ return "fit-content";
1925+ }
1926+ ;
1927+ if (v instanceof Fill) {
1928+ return "100%";
1929+ }
1930+ ;
1931+ if (v instanceof Max2) {
1932+ return "max(" + (show2(v.value0) + ("px," + (render(renderableLength)(v.value1) + ")")));
1933+ }
1934+ ;
1935+ if (v instanceof Min2) {
1936+ return "min(" + (show2(v.value0) + ("px," + (render(renderableLength)(v.value1) + ")")));
1937+ }
1938+ ;
1939+ throw new Error("Failed pattern match at Plum.View (line 131, column 12 - line 136, column 62): " + [v.constructor.name]);
15901940 }
1591− ;
1592− throw new Error("Failed pattern match at Plum.View (line 99, column 10 - line 102, column 17): " + [v.constructor.name]);
15931941 };
1942+ var render2 = /* @__PURE__ */ render(renderableLength);
15941943 var skin = function(ctx) {
15951944 return function(v) {
15961945 if (v instanceof Spacing) {
@@ -1620,7 +1969,7 @@
16201969 return "align-items";
16211970 }
16221971 ;
1623− throw new Error("Failed pattern match at Plum.View (line 70, column 9 - line 72, column 29): " + [v.value0.constructor.name]);
1972+ throw new Error("Failed pattern match at Plum.View (line 88, column 9 - line 90, column 29): " + [v.value0.constructor.name]);
16241973 }())(function() {
16251974 if (v.value1 instanceof Start) {
16261975 return "start";
@@ -1634,7 +1983,7 @@
16341983 return "end";
16351984 }
16361985 ;
1637− throw new Error("Failed pattern match at Plum.View (line 74, column 9 - line 77, column 23): " + [v.value1.constructor.name]);
1986+ throw new Error("Failed pattern match at Plum.View (line 92, column 9 - line 95, column 23): " + [v.value1.constructor.name]);
16381987 }());
16391988 }
16401989 ;
@@ -1657,7 +2006,7 @@
16572006 return "justify-content";
16582007 }
16592008 ;
1660− throw new Error("Failed pattern match at Plum.View (line 81, column 9 - line 85, column 38): " + [v1.constructor.name]);
2009+ throw new Error("Failed pattern match at Plum.View (line 99, column 9 - line 103, column 38): " + [v1.constructor.name]);
16612010 }())(function() {
16622011 if (v.value1 instanceof Start) {
16632012 return "flex-start";
@@ -1671,19 +2020,19 @@
16712020 return "flex-end";
16722021 }
16732022 ;
1674− throw new Error("Failed pattern match at Plum.View (line 87, column 9 - line 90, column 28): " + [v.value1.constructor.name]);
2023+ throw new Error("Failed pattern match at Plum.View (line 105, column 9 - line 108, column 28): " + [v.value1.constructor.name]);
16752024 }());
16762025 }
16772026 ;
1678− throw new Error("Failed pattern match at Plum.View (line 66, column 26 - line 91, column 8): " + [ctx.constructor.name]);
2027+ throw new Error("Failed pattern match at Plum.View (line 84, column 26 - line 109, column 8): " + [ctx.constructor.name]);
16792028 }
16802029 ;
16812030 if (v instanceof Width) {
1682− return sk("width")(length2(v.value0));
2031+ return sk("width")(render2(v.value0));
16832032 }
16842033 ;
16852034 if (v instanceof Height) {
1686− return sk("height")(length2(v.value0));
2035+ return sk("height")(render2(v.value0));
16872036 }
16882037 ;
16892038 if (v instanceof Wrapped) {
@@ -1694,7 +2043,54 @@
16942043 return mempty1;
16952044 }
16962045 ;
1697− throw new Error("Failed pattern match at Plum.View (line 63, column 12 - line 96, column 16): " + [v.constructor.name]);
2046+ if (v instanceof BackgroundColor) {
2047+ return sk("background-color")(render1(v.value0));
2048+ }
2049+ ;
2050+ if (v instanceof Padding) {
2051+ return sk("padding")(show2(v.value0.top) + ("px " + (show2(v.value0.right) + ("px " + (show2(v.value0.bottom) + ("px " + (show2(v.value0.left) + "px")))))));
2052+ }
2053+ ;
2054+ if (v instanceof Spread) {
2055+ if (ctx instanceof Flexbox) {
2056+ return sk("justify-content")("space-between");
2057+ }
2058+ ;
2059+ return mempty1;
2060+ }
2061+ ;
2062+ if (v instanceof Opacity) {
2063+ return sk("opacity")(show1(v.value0));
2064+ }
2065+ ;
2066+ if (v instanceof Pointer) {
2067+ return sk("cursor")("pointer");
2068+ }
2069+ ;
2070+ if (v instanceof Move) {
2071+ return sk("transform")("translate(" + (show2(v.value0.x) + ("px, " + (show2(v.value0.y) + ")"))));
2072+ }
2073+ ;
2074+ if (v instanceof Clip && v.value0 instanceof X) {
2075+ return sk("overflow-x")("hidden");
2076+ }
2077+ ;
2078+ if (v instanceof Clip && v.value0 instanceof Y) {
2079+ return sk("overflow-y")("hidden");
2080+ }
2081+ ;
2082+ throw new Error("Failed pattern match at Plum.View (line 81, column 12 - line 125, column 37): " + [v.constructor.name]);
2083+ };
2084+ };
2085+ var hWith = function(el) {
2086+ return function(props) {
2087+ return function(v) {
2088+ return function(children) {
2089+ return h2(el)(unsafeUnion(props)({
2090+ styles: v
2091+ }))(children);
2092+ };
2093+ };
16982094 };
16992095 };
17002096 var h3 = function(el) {
@@ -1729,7 +2125,7 @@
17292125 return widthFill;
17302126 }
17312127 ;
1732− throw new Error("Failed pattern match at Plum.View (line 128, column 16 - line 132, column 35): " + [ctx.constructor.name]);
2128+ throw new Error("Failed pattern match at Plum.View (line 181, column 16 - line 185, column 35): " + [ctx.constructor.name]);
17332129 }())(function() {
17342130 if (ctx instanceof Grid) {
17352131 return alignCenter;
@@ -1747,7 +2143,7 @@
17472143 return alignCenter;
17482144 }
17492145 ;
1750− throw new Error("Failed pattern match at Plum.View (line 133, column 16 - line 137, column 37): " + [ctx.constructor.name]);
2146+ throw new Error("Failed pattern match at Plum.View (line 186, column 16 - line 190, column 37): " + [ctx.constructor.name]);
17512147 }()))))(v.extraSkin);
17522148 };
17532149 if (v1.bones instanceof Text) {
@@ -1772,7 +2168,28 @@
17722168 return h3("div")(append2(skn(new Flexbox(Y.value)))(append2(sk("display")("flex"))(sk("flex-direction")("column"))))(map2(growSkin(fire)(mempty22))(v1.bones.value0));
17732169 }
17742170 ;
1775− throw new Error("Failed pattern match at Plum.View (line 140, column 5 - line 148, column 46): " + [v1.bones.constructor.name]);
2171+ if (v1.bones instanceof Link) {
2172+ return hWith("a")({
2173+ href: v1.bones.value0,
2174+ rel: "noopener noreferrer",
2175+ target: function() {
2176+ if (v1.bones.value1.newTab) {
2177+ return "_blank";
2178+ }
2179+ ;
2180+ return "_self";
2181+ }()
2182+ })(append2(skn(new Flexbox(X.value)))(append2(sk("display")("flex"))(sk("flex-direction")("row"))))([growSkin(fire)(mempty22)(v1.bones.value2)]);
2183+ }
2184+ ;
2185+ if (v1.bones instanceof Download) {
2186+ return hWith("a")({
2187+ href: v1.bones.value0,
2188+ download: fromMaybe("")(v1.bones.value1.filename)
2189+ })(append2(skn(new Flexbox(X.value)))(append2(sk("display")("flex"))(sk("flex-direction")("row"))))([growSkin(fire)(mempty22)(v1.bones.value2)]);
2190+ }
2191+ ;
2192+ throw new Error("Failed pattern match at Plum.View (line 193, column 5 - line 215, column 39): " + [v1.bones.constructor.name]);
17762193 };
17772194 };
17782195 };
@@ -1855,7 +2272,7 @@
18552272 height: "100%",
18562273 width: "100%"
18572274 }
1858− })([el, h2("style")({})([string(outerStyle)])]);
2275+ })([h2("style")({})([string(outerStyle)]), el]);
18592276 })();
18602277 }
18612278 ;
@@ -1876,7 +2293,9 @@
18762293 text: "Test"
18772294 }),
18782295 view: function(model) {
1879− return view([])([Wrapped.value])(new Column(map4($$const(view([])([])(new Text("hello"))))(range2(1)(100))));
2296+ return view([])([])(new Column([view([])([])(new Link("https://iko.soy", {
2297+ newTab: false
2298+ }, view([])([])(new Text("my website")))), view([])([])(new Row(map4($$const(view([])([new BackgroundColor(rgb(1)(0)(0))])(new Text("hello"))))(range2(1)(100))))]));
18802299 },
18812300 update: function(msg) {
18822301 return function(model) {
plum/spago.dhall+2
@@ -5,9 +5,11 @@
55 , "debug"
66 , "effect"
77 , "foreign-object"
8+ , "integers"
89 , "maybe"
910 , "numbers"
1011 , "prelude"
12+ , "record"
1113 , "refs"
1214 , "strings-extra"
1315 , "tuples"
plum/src/Main.purs+7−2
@@ -1,11 +1,11 @@
11module Main where
22
3−import Plum.View (Bones(..), view)
43import Prelude
54
65import Data.Array as Array
76import Effect (Effect)
87import Plum as Plum
8+import Plum.View (Bones(..), Meat(..), rgb, view)
99
1010main :: Effect Unit
1111main = do
@@ -17,7 +17,12 @@ plum :: Plum.Plum Unit Model
1717plum =
1818 { init: pure { text: "Test" }
1919 , view: \model ->
20− view [] [] (Column $ Array.range 1 100 # map (const $ view [] [] (Text "hello")))
20+ view [] []
21+ ( Column
22+ [ view [] [] (Link "https://iko.soy" { newTab: false } $ view [] [] (Text "my website"))
23+ , view [] [] (Row $ Array.range 1 100 # map (const $ view [] [ BackgroundColor (rgb 1.0 0.0 0.0) ] (Text "hello")))
24+ ]
25+ )
2126 , update: \msg model -> case msg of
2227 _ -> pure { text: "Button pressed" }
2328 }
plum/src/Plum.purs+1−1
@@ -35,7 +35,7 @@ run id plum = do
3535 Ref.write m_ modelRef
3636 )
3737 (plum.view model)
38− pure $ Maquette.h "div" { styles: { height: "100%", width: "100%" } } [ el, Maquette.h "style" {} [ Maquette.string outerStyle ] ]
38+ pure $ Maquette.h "div" { styles: { height: "100%", width: "100%" } } [ Maquette.h "style" {} [ Maquette.string outerStyle ], el ]
3939 Nothing -> pure unit
4040
4141outerStyle :: String
plum/src/Plum/View.purs+79−8
@@ -8,22 +8,35 @@ module Plum.View
88 , Direction(..)
99 , Alignment(..)
1010 , Length(..)
11+ , Color(..)
12+ , rgb255
13+ , rgba255
14+ , rgb
15+ , rgba
1116 ) where
1217
1318import Prelude
1419
1520import Data.Array as Array
21+import Data.Int as Int
22+import Data.Maybe (Maybe)
23+import Data.Maybe as Maybe
1624import Data.Tuple.Nested ((/\))
1725import Effect (Effect)
1826import Foreign.Object (Object)
1927import Foreign.Object as Object
2028import Maquette (VNode, string)
2129import Maquette as Maquette
30+import Record as Record
31+import Record.Unsafe.Union as Record
2232
2333h :: String -> Skin -> Array VNode -> VNode
2434h el (Skin styles) children = Maquette.h el { styles } children
2535
26−data Length = Px Int | Fill | Fit
36+hWith :: forall props. String -> Record props -> Skin -> Array VNode -> VNode
37+hWith el props (Skin styles) children = Maquette.h el (Record.unsafeUnion props { styles }) children
38+
39+data Length = Px Int | Fill | Fit | Max Int Length | Min Int Length
2740
2841data Alignment = Start | Center | End
2942
@@ -36,6 +49,13 @@ data Meat
3649 | Width Length
3750 | Height Length
3851 | Wrapped
52+ | BackgroundColor Color
53+ | Padding { top :: Int, right :: Int, bottom :: Int, left :: Int }
54+ | Spread
55+ | Opacity Number
56+ | Pointer
57+ | Move { x :: Int, y :: Int }
58+ | Clip Direction
3959
4060data Nerve msg = OnClick msg
4161
@@ -87,17 +107,50 @@ skin ctx = case _ of
87107 Center -> "center"
88108 End -> "flex-end"
89109 )
90− Width l -> sk "width" (length l)
91− Height l -> sk "height" (length l)
110+ Width l -> sk "width" (render l)
111+ Height l -> sk "height" (render l)
92112 Wrapped -> case ctx of
93113 Flexbox _ -> sk "flex-wrap" "wrap"
94114 _ -> mempty
115+ BackgroundColor color -> sk "background-color" (render color)
116+ Padding { top, right, bottom, left } ->
117+ sk "padding" (show top <> "px " <> show right <> "px " <> show bottom <> "px " <> show left <> "px")
118+ Spread -> case ctx of
119+ Flexbox _ -> sk "justify-content" "space-between"
120+ _ -> mempty
121+ Opacity o -> sk "opacity" (show o)
122+ Pointer -> sk "cursor" "pointer"
123+ Move { x, y } -> sk "transform" ("translate(" <> show x <> "px, " <> show y <> ")")
124+ Clip X -> sk "overflow-x" "hidden"
125+ Clip Y -> sk "overflow-y" "hidden"
126+
127+class Renderable x where
128+ render :: x -> String
129+
130+instance Renderable Length where
131+ render = case _ of
132+ Px px -> show px <> "px"
133+ Fit -> "fit-content"
134+ Fill -> "100%"
135+ Max px l -> "max(" <> show px <> "px," <> render l <> ")"
136+ Min px l -> "min(" <> show px <> "px," <> render l <> ")"
137+
138+newtype Color = Color { r :: Int, g :: Int, b :: Int, a :: Number }
139+
140+rgb255 :: Int -> Int -> Int -> Color
141+rgb255 r g b = Color { r, g, b, a: 1.0 }
142+
143+rgba255 :: Int -> Int -> Int -> Number -> Color
144+rgba255 r g b a = Color { r, g, b, a }
145+
146+rgb :: Number -> Number -> Number -> Color
147+rgb r g b = Color { r: Int.round (r * 255.0), g: Int.round (g * 255.0), b: Int.round (b * 255.0), a: 1.0 }
148+
149+rgba :: Number -> Number -> Number -> Number -> Color
150+rgba r g b a = Color { r: Int.round (r * 255.0), g: Int.round (g * 255.0), b: Int.round (b * 255.0), a }
95151
96−length :: Length -> String
97−length = case _ of
98− Px px -> show px <> "px"
99− Fit -> "fit-content"
100− Fill -> "100%"
152+instance Renderable Color where
153+ render (Color { r, g, b, a }) = "rgba(" <> show r <> "," <> show g <> "," <> show b <> "," <> show a <> ")"
101154
102155data Bones :: Type -> Type
103156data Bones msg
@@ -106,6 +159,9 @@ data Bones msg
106159 | Stack (Array (View msg))
107160 | Wrapper (View msg)
108161 | Text String
162+ | Link String { newTab :: Boolean } (View msg)
163+ | Download String { filename :: Maybe String } (View msg)
164+ | Image String { description :: String }
109165
110166newtype Mutation = Mutation { extraSkin :: Skin }
111167
@@ -144,6 +200,21 @@ growSkin fire (Mutation mutation) { meat, bones } =
144200 (map (growSkin fire mempty) children)
145201 Column children -> h "div" (skn (Flexbox Y) <> sk "display" "flex" <> sk "flex-direction" "column")
146202 (map (growSkin fire mempty) children)
203+ Link href { newTab } child -> hWith "a"
204+ { href
205+ , rel: "noopener noreferrer"
206+ , target: if newTab then "_blank" else "_self"
207+ }
208+ (skn (Flexbox X) <> sk "display" "flex" <> sk "flex-direction" "row")
209+ [ growSkin fire mempty child ]
210+
211+ Download href { filename } child -> hWith "a"
212+ { href
213+ , download: Maybe.fromMaybe "" filename
214+ }
215+ (skn (Flexbox X) <> sk "display" "flex" <> sk "flex-direction" "row")
216+ [ growSkin fire mempty child ]
217+ Image src { description } -> hWith "img" { src, alt: description } (skn Generic) []
147218
148219grow :: forall msg. (msg -> Effect Unit) -> View msg -> VNode
149220grow fire v = growSkin fire mempty v