ags: sync
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.0"
|
||||
width="20"
|
||||
height="19.999941"
|
||||
id="svg2424"
|
||||
sodipodi:docname="archlinux-logo-black-scalable.f931920e6cdb.svg"
|
||||
viewBox="0 0 166.18749 166.187"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="16.650008"
|
||||
inkscape:cx="13.093087"
|
||||
inkscape:cy="16.366359"
|
||||
inkscape:window-width="1340"
|
||||
inkscape:window-height="768"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g2424" />
|
||||
<defs
|
||||
id="defs2426">
|
||||
<linearGradient
|
||||
x1="112.49854"
|
||||
y1="6.1372099"
|
||||
x2="112.49853"
|
||||
y2="129.3468"
|
||||
id="path1082_2_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(287,-83)">
|
||||
<stop
|
||||
id="stop193"
|
||||
style="stop-color:#ffffff;stop-opacity:0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop195"
|
||||
style="stop-color:#ffffff;stop-opacity:0.27450982"
|
||||
offset="1" />
|
||||
<midPointStop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="midPointStop197" />
|
||||
<midPointStop
|
||||
offset="0.5"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="midPointStop199" />
|
||||
<midPointStop
|
||||
offset="1"
|
||||
style="stop-color:#000000"
|
||||
id="midPointStop201" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="541.33502"
|
||||
y1="104.50665"
|
||||
x2="606.91248"
|
||||
y2="303.14029"
|
||||
id="linearGradient2544"
|
||||
xlink:href="#path1082_2_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-0.3937741,0,0,0.393752,357.51969,122.00151)" />
|
||||
<linearGradient
|
||||
id="linearGradient3388">
|
||||
<stop
|
||||
id="stop3390"
|
||||
style="stop-color:#000000;stop-opacity:0"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3392"
|
||||
style="stop-color:#000000;stop-opacity:0.37113401"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="490.72305"
|
||||
y1="237.72447"
|
||||
x2="490.72305"
|
||||
y2="183.9644"
|
||||
id="linearGradient4416"
|
||||
xlink:href="#linearGradient3388"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.749107,0,0,0.749107,-35.459862,91.44108)" />
|
||||
</defs>
|
||||
<g
|
||||
transform="translate(-57.527313,-146.42741)"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(0.8746356,0,0,0.8746356,14.730518,23.408954)"
|
||||
id="g2424"
|
||||
style="fill:#000000">
|
||||
<g
|
||||
transform="matrix(0.6378586,0,0,0.6378586,36.486487,2.17139)"
|
||||
id="g2809"
|
||||
style="fill:#000000;fill-opacity:1" />
|
||||
<path
|
||||
d="m 143.91698,140.65081 c -8.45709,20.73453 -13.55799,34.29734 -22.97385,54.41552 5.7731,6.11948 12.85931,13.24593 24.36729,21.29458 -12.37221,-5.09109 -20.81157,-10.20242 -27.11844,-15.50646 -12.0505,25.14523 -30.930177,60.96349 -69.243121,129.80406 30.112687,-17.38458 53.455511,-28.10236 75.209891,-32.19198 -0.93414,-4.01773 -1.46524,-8.36369 -1.42916,-12.89823 l 0.0357,-0.96469 c 0.47781,-19.2924 10.51371,-34.12825 22.40218,-33.12093 11.88848,1.00732 21.12927,17.4729 20.65146,36.76531 -0.0899,3.63022 -0.49934,7.12245 -1.21479,10.36146 21.51819,4.20934 44.61141,14.89968 74.31666,32.04906 -5.85729,-10.78369 -11.08544,-20.5044 -16.07812,-29.7624 -7.86429,-6.09535 -16.06714,-14.02847 -32.79938,-22.61656 11.50078,2.98839 19.73519,6.43619 26.15375,10.29 -50.76203,-94.51003 -54.87267,-107.06846 -72.2801,-147.91874 z"
|
||||
id="path2518"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.14333" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="-30.5 0 317.00242 317.00243"
|
||||
version="1.1"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
id="svg12"
|
||||
sodipodi:docname="debian-symbolic.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview12"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="17.5"
|
||||
inkscape:cx="13.742857"
|
||||
inkscape:cy="12.628571"
|
||||
inkscape:window-width="1295"
|
||||
inkscape:window-height="867"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<g
|
||||
fill="#A80030"
|
||||
id="g12"
|
||||
style="fill:#1a1a1a"
|
||||
transform="translate(0.05835351,0.0538775)">
|
||||
<path
|
||||
d="m 152.79662,167.42537 c -5.25095,0.0731 0.9935,2.70583 7.84865,3.76069 1.8935,-1.47856 3.61167,-2.97466 5.14283,-4.42984 -4.26913,1.04609 -8.61424,1.06947 -12.99148,0.66915"
|
||||
id="path1"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 180.9799,160.40073 c 3.12661,-4.31588 5.40581,-9.04086 6.20938,-13.92654 -0.70129,3.4831 -2.59187,6.4899 -4.3714,9.66326 -9.81521,6.18016 -0.92337,-3.67011 -0.006,-7.41328 -10.55448,13.2837 -1.44934,7.96554 -1.83213,11.67656"
|
||||
id="path2"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 191.38244,133.33075 c 0.63409,-9.45579 -1.86135,-6.46652 -2.69999,-2.85777 0.9789,0.50844 1.75324,6.66522 2.69999,2.85777"
|
||||
id="path3"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 132.88569,4.0879643 c 2.80225,0.5025946 6.05451,0.8883068 5.59867,1.5574589 3.06524,-0.6720742 3.76069,-1.2915513 -5.59867,-1.5574589"
|
||||
id="path4"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 138.48436,5.6454232 -1.98116,0.4090887 1.84382,-0.1636355 0.13734,-0.2454532"
|
||||
id="path5"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 225.86569,136.91612 c 0.31266,8.49151 -2.48375,12.61162 -5.00549,19.90509 l -4.53796,2.26752 c -3.71394,7.21165 0.35941,4.57887 -2.29967,10.31487 -5.79737,5.15452 -17.59373,16.12979 -21.36903,17.13205 -2.75551,-0.0614 1.86719,-3.25225 2.47206,-4.50289 -7.76099,5.32984 -6.22691,8.0006 -18.09633,11.23824 l -0.34772,-0.77142 c -29.27322,13.77168 -69.93663,-13.52038 -69.40189,-50.75913 -0.31266,2.36394 -0.88831,1.77369 -1.537,2.7292 -1.51071,-19.15996 8.848,-38.40465 26.31901,-46.262078 17.08821,-8.459369 37.12187,-4.987959 49.36238,6.419768 -6.72366,-8.807092 -20.1067,-18.14308 -35.96765,-17.269383 -15.53661,0.245453 -30.07094,10.1191 -34.92156,20.837223 -7.9597,5.01133 -8.88307,19.31775 -12.351558,21.93592 -4.666532,34.29623 8.777878,49.11401 31.520278,66.54411 3.57953,2.41362 1.00811,2.77888 1.49318,4.61685 -7.55646,-3.53861 -14.4759,-8.88014 -20.16515,-15.41972 3.01849,4.41816 6.27659,8.71359 10.48728,12.08857 -7.12399,-2.41362 -16.64115,-17.26354 -19.42003,-17.8684 12.28143,21.98851 49.827,38.56245 69.48663,30.33976 -9.09638,0.33604 -20.65313,0.18702 -30.8745,-3.59121 -4.29251,-2.20908 -10.13079,-6.78503 -9.08761,-7.64119 26.83037,10.02267 54.54612,7.59151 77.7619,-11.0191 5.90549,-4.59932 12.3574,-12.4246 14.22168,-12.53272 -2.8081,4.22238 0.47921,2.03083 -1.67727,5.75938 5.88504,-9.49085 -2.5568,-3.86296 6.08374,-16.38984 l 3.19089,4.39478 c -1.18636,-7.87788 9.78306,-17.44471 8.66975,-29.90438 2.5159,-3.81037 2.80811,4.09965 0.13734,12.86584 3.70517,-9.72462 0.97597,-11.28793 1.92856,-19.31191 1.02857,2.69707 2.37856,5.56361 3.07109,8.4097 -2.41362,-9.39735 2.47791,-15.82589 3.68764,-21.28722 -1.1922,-0.52889 -3.72563,4.15517 -4.3042,-6.94574 0.0847,-4.8214 1.34123,-2.52759 1.82629,-3.71394 -0.94675,-0.54351 -3.4305,-4.23991 -4.9412,-11.328836 1.09577,-1.665575 2.9279,4.318806 4.41815,4.564256 -0.95843,-5.636653 -2.6094,-9.935006 -2.67661,-14.259657 -4.35387,-9.0993 -1.53992,1.212656 -5.07269,-3.906796 -4.63439,-14.45544 3.84543,-3.354527 4.41815,-9.923322 7.02464,10.177541 11.03079,25.950835 12.86876,32.484565 -1.40259,-7.965545 -3.67011,-15.68271 -6.4373,-23.148578 2.13311,0.897073 -3.43634,-16.389844 2.77304,-4.941206 -6.63308,-24.40506 -28.38783,-47.208829 -48.40103,-57.909419 2.44869,2.241221 5.54023,5.055166 4.42984,5.496398 -9.95254,-5.925941 -8.20223,-6.387627 -9.62819,-8.891834 -8.10872,-3.299008 -8.64054,0.265908 -14.01129,0.0058 -15.28238,-8.105755 -18.22782,-7.243747 -32.2917,-12.32229 l 0.63993,2.9892691 c -10.12494,-3.3720592 -11.79636,1.279863 -22.73948,0.011688 -0.66623,-0.520127 3.50647,-1.8818077 6.93989,-2.3814803 -9.7889,1.2915513 -9.33014,-1.9285607 -18.90866,0.3564916 2.36103,-1.656809 4.85647,-2.7525822 7.37529,-4.1610159 -7.98308,0.4850622 -19.05769,4.6460781 -15.63888,0.8620082 C 96.316085,8.9298206 73.190888,17.085295 60.214012,29.25276 L 59.804924,26.526476 C 53.858528,33.665073 33.874548,47.845838 32.282025,57.091242 l -1.589602,0.371102 C 27.59796,62.7016 25.596347,68.63923 23.141816,74.030433 19.09476,80.926499 17.21003,76.683665 17.785676,77.764828 9.8259803,93.903375 5.8724309,107.46466 2.4565407,118.58603 4.8906182,122.224 2.514982,140.48688 3.4354314,155.10304 -0.56194899,227.28965 54.098137,297.37822 113.84553,313.5606 c 8.75742,3.13245 21.78105,3.01264 32.85859,3.33407 -13.07039,-3.73732 -14.75934,-1.98116 -27.49076,-6.41977 -9.18404,-4.32465 -11.19734,-9.26293 -17.70185,-14.90836 l 2.57434,4.54965 c -12.757724,-4.51458 -7.419118,-5.58698 -17.798281,-8.8743 l 2.74966,-3.59121 c -4.134717,-0.31266 -10.951887,-6.96912 -12.816162,-10.65384 l -4.523352,0.17825 C 66.26268,270.46895 63.366917,265.63586 63.577306,261.8927 l -1.461031,2.60356 c -1.656809,-2.84317 -19.995669,-25.15019 -10.481436,-19.95768 -1.767847,-1.6159 -4.117185,-2.62986 -6.665222,-7.2584 l 1.937326,-2.21493 c -4.57887,-5.89087 -8.427226,-13.44148 -8.135019,-15.95737 2.442843,3.299 4.137639,3.91556 5.814902,4.47952 -11.562598,-28.68881 -12.211295,-1.58084 -20.968714,-29.20309 l 1.852587,-0.14902 c -1.420122,-2.13895 -2.28213,-4.46199 -3.424657,-6.7412 l 0.80649,-8.03567 c -8.324954,-9.62527 -2.328884,-40.9264 -1.127916,-58.09351 0.832787,-6.9808 6.948662,-14.41161 11.600585,-26.064789 l -2.8344,-0.487985 c 5.417502,-9.449947 30.932945,-37.951737 42.749763,-36.484862 5.724319,-7.191194 -1.136683,-0.0263 -2.255832,-1.837977 12.573631,-13.011941 16.527181,-9.192806 25.012848,-11.533378 9.1519,-5.432112 -7.854502,2.118495 -3.51524,-2.071741 15.82004,-4.041212 11.21195,-9.186962 31.85047,-11.23825 2.17694,1.238955 -5.05224,1.913951 -6.86684,3.521085 13.18142,-6.448991 41.71243,-4.982116 60.24414,3.579525 21.50346,10.04897 45.66306,39.75465 46.61565,67.704172 l 1.08409,0.2922 c -0.54935,11.10968 1.70064,23.95799 -2.19739,35.76019 l 2.65323,-5.58698"
|
||||
id="path6"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 95.483297,174.6341 -0.736359,3.68179 c 3.450955,4.68699 6.188932,9.76553 10.595392,13.4298 -3.17043,-6.18893 -5.525615,-8.74573 -9.859033,-17.11159"
|
||||
id="path7"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 103.64169,174.31267 c -1.82629,-2.01915 -2.90745,-4.4503 -4.117181,-6.87269 1.157141,4.25744 3.526931,7.91586 5.733081,11.63565 l -1.6159,-4.76296"
|
||||
id="path8"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 248.00323,142.93557 -0.77142,1.9344 c -1.41428,10.04605 -4.46784,19.98691 -9.14898,29.20309 5.17205,-9.72462 8.51781,-20.36093 9.9204,-31.13749"
|
||||
id="path9"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="M 133.92302,1.5691471 C 137.47332,0.26882968 142.65122,0.85616408 146.41775,0 141.50869,0.4120107 136.623,0.65746388 131.79868,1.279863 l 2.12434,0.2892841"
|
||||
id="path10"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="m 9.2824769,67.847351 c 0.8181771,7.573984 -5.6980203,10.513578 1.4434981,5.519774 3.827901,-8.623004 -1.4960952,-2.38148 -1.4434981,-5.519774"
|
||||
id="path11"
|
||||
style="fill:#1a1a1a" />
|
||||
<path
|
||||
d="M 0.89031567,102.9004 C 2.5354364,97.85108 2.8334867,94.81798 3.46173,91.895919 -1.084998,97.707899 1.3695338,98.946854 0.89031567,102.9004"
|
||||
id="path12"
|
||||
style="fill:#1a1a1a" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.3 KiB |
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 448.00288 448.00288"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="Fa-Team-Fontawesome-Brands-FontAwesome-Brands-Fedora.svg"
|
||||
width="19.999744"
|
||||
height="19.999744"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="13.671875"
|
||||
inkscape:cx="19.2"
|
||||
inkscape:cy="17.664"
|
||||
inkscape:window-width="1313"
|
||||
inkscape:window-height="908"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. -->
|
||||
<path
|
||||
d="M 0.0413,223.8 C 0.1219,100.2 100.3,0 224,0 347.7,0 448,100.3 448,224 448,347.7 347.8,447.9 224.1,448 H 50.93 C 22.84,448 0.0832,425.3 0.0416,397.2 H 0 V 223.8 Z M 342.6,160.7 c 0,-39.7 -35.6,-68.5 -73.2,-68.5 -34.9,0 -65.8,26.3 -70.1,59.9 -0.2,3.8 -0.4,5 -0.4,8.5 -0.1,21.1 0,42.8 -0.8,64.4 0.9,26.1 1,52.1 0,76.6 0,27.1 -19.4,45.5 -44.7,45.5 -25.3,0 -45.8,-20.2 -45.8,-45.5 0.5,-27.7 22.6,-45.3 48.5,-46.1 h 0.2 l 26.3,-0.2 V 218 l -26.3,0.2 c -47.1,-0.4 -84.58,36.5 -85.94,83.4 0,45.6 37.54,82.9 83.04,82.9 43,0 78.7,-33.6 82.6,-75.6 l 0.2,-53.5 32.6,-0.3 c 25.3,0.2 25,-37.8 -0.2,-37.3 l -32.4,0.3 c 0,-6.4 0.1,-12.8 0.1,-19.2 0.1,-12.7 0.1,-25.4 -0.1,-38.2 0.1,-16.5 15.8,-31.2 33.2,-31.2 17.5,0 35.9,8.7 35.9,31.2 0,3.2 -0.1,5.1 -0.3,6.3 -1.9,10.5 5.2,20.4 15.7,21.9 10.6,1.5 20.2,-6.1 21.2,-16.6 0.6,-4.2 0.7,-7.9 0.7,-11.6 z"
|
||||
id="path1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
role="img"
|
||||
viewBox="0 0 24.000009 24.000009"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="flatpak_logo_icon_248537.svg"
|
||||
width="20"
|
||||
height="20"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="18.229167"
|
||||
inkscape:cx="11.190857"
|
||||
inkscape:cy="11.766857"
|
||||
inkscape:window-width="1164"
|
||||
inkscape:window-height="648"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<title
|
||||
id="title1">Flatpak</title>
|
||||
<path
|
||||
d="m 12.000004,7.3336774e-5 c -0.556,0 -1.110999,0.143999993226 -1.609999,0.431999993226 L 2.7870046,4.8220733 a 3.217,3.217 0 0 0 -1.61,2.788 v 8.7799997 c 0,1.151 0.612,2.212 1.61,2.788 l 7.6030004,4.39 a 3.217,3.217 0 0 0 3.219999,0 l 7.603,-4.39 a 3.217,3.217 0 0 0 1.61,-2.788 V 7.6100733 a 3.217,3.217 0 0 0 -1.61,-2.788 l -7.603,-4.38999997 a 3.218,3.218 0 0 0 -1.61,-0.431999993226 z m 0,2.357999963226 c 0.15,0 0.299,0.039 0.431,0.115 l 7.604,4.39 c 0.132,0.077 0.24,0.187 0.315,0.316 l -8.35,4.8209997 v 9.642 a 0.863,0.863 0 0 1 -0.431,-0.116 l -7.6039994,-4.39 a 0.866,0.866 0 0 1 -0.431,-0.746 V 7.6100733 c 0,-0.153 0.041,-0.302 0.116,-0.43 l 8.3499994,4.8199997 z"
|
||||
id="path1" />
|
||||
<metadata
|
||||
id="metadata1">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>Flatpak</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -3,17 +3,20 @@
|
||||
|
||||
<svg
|
||||
fill="#000000"
|
||||
width="800px"
|
||||
height="800px"
|
||||
viewBox="0 0 512 512"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 380.95238 380.95238"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="google-gemini-symbolic.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
@@ -25,10 +28,10 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.77339804"
|
||||
inkscape:cx="391.13107"
|
||||
inkscape:cy="332.94628"
|
||||
inkscape:window-width="1908"
|
||||
inkscape:zoom="6.1871843"
|
||||
inkscape:cx="39.840417"
|
||||
inkscape:cy="52.931994"
|
||||
inkscape:window-width="1183"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
@@ -37,12 +40,21 @@
|
||||
<title
|
||||
id="title1">ionicons-v5_logos</title>
|
||||
<path
|
||||
d="m 377.94638,279.52117 -1.75376,-7.44181 H 214.44368 v 68.45852 h 96.64274 c -10.03366,47.64625 -56.59351,72.7265 -94.62516,72.7265 -27.67207,0 -56.84182,-11.63997 -76.14863,-30.34928 a 108.70175,108.70175 0 0 1 -32.43671,-76.73064 c 0,-28.83607 12.95917,-57.67991 31.81591,-76.65304 18.85674,-18.97314 47.33585,-29.5888 75.652,-29.5888 32.42894,0 55.67007,17.21939 64.36125,25.07248 l 48.64728,-48.3912 C 314.08178,164.08378 274.87838,132.48516 213.77632,132.48516 v 0 c -47.14186,0 -92.34372,18.05745 -125.385701,50.9908 -32.607419,32.42893 -49.485367,79.32247 -49.485367,122.83266 0,43.51018 15.970029,88.06021 47.56865,120.74522 33.763658,34.85782 81.580638,53.07825 130.817688,53.07825 44.79835,0 87.26093,-17.55307 117.52483,-49.40001 29.75175,-31.3503 45.13979,-74.72857 45.13979,-120.20204 0,-19.14386 -1.92447,-30.51221 -2.00983,-31.00887 z"
|
||||
d="m 275.79491,211.5275 -1.32807,-5.6355 H 151.97845 v 51.84191 h 73.1851 c -7.59823,36.0813 -42.85683,55.07394 -71.65724,55.07394 -20.95536,0 -43.04487,-8.81465 -57.665446,-22.98274 A 82.317089,82.317089 0 0 1 71.277365,231.71893 c 0,-21.83683 9.813652,-43.67954 24.093389,-58.04741 14.279736,-14.36788 35.846246,-22.40685 57.289356,-22.40685 24.55762,0 42.15754,13.03981 48.73915,18.98676 l 36.83935,-36.64544 c -10.80674,-9.49631 -40.49449,-33.42515 -86.76554,-33.42515 v 0 c -35.69934,0 -69.929575,13.67445 -94.951433,38.61404 -24.692774,24.55761 -37.474018,60.06891 -37.474018,93.01808 0,32.94916 12.0937,66.68577 36.022537,91.4373 25.568365,26.39695 61.778964,40.19482 99.064944,40.19482 33.92466,0 66.0805,-13.2925 88.99858,-37.40938 22.53025,-23.74079 34.18323,-56.59006 34.18323,-91.02597 0,-14.49716 -1.45736,-23.10613 -1.522,-23.48223 z"
|
||||
id="path1"
|
||||
style="stroke-width:0.775997" />
|
||||
style="stroke-width:0.587643" />
|
||||
<path
|
||||
d="m 396.33661,224.32725 v 0 0 c -8.3763,-55.27516 -51.76093,-98.65984 -107.03609,-107.0361 v 0 0 c 55.27516,-8.3763 98.65979,-51.760947 107.03609,-107.036116 v 0 0 c 8.37627,55.275169 51.76088,98.659816 107.0361,107.036116 v 0 0 c -55.27522,8.37626 -98.65983,51.76094 -107.0361,107.0361 z"
|
||||
d="m 289.72137,169.73053 v 0 0 C 283.37821,127.87205 250.52413,95.017925 208.66564,88.674797 v 0 0 c 41.85849,-6.343163 74.71257,-39.197259 81.05573,-81.0557495 v 0 0 c 6.34314,41.8584905 39.19721,74.7125865 81.05574,81.0557495 v 0 0 c -41.85853,6.343128 -74.7126,39.197253 -81.05574,81.055733 z"
|
||||
fill="#076eff"
|
||||
id="path19"
|
||||
style="fill:#000000;stroke-width:2.9422" />
|
||||
style="fill:#000000;stroke-width:2.22805" />
|
||||
<metadata
|
||||
id="metadata1">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>ionicons-v5_logos</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
width="19.999744"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="nixos-symbolic.svg"
|
||||
viewBox="0 0 512.00001 512.00656"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="27.34375"
|
||||
inkscape:cx="8.832"
|
||||
inkscape:cy="15.817143"
|
||||
inkscape:window-width="1075"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill-rule="evenodd"
|
||||
transform="matrix(1.2756532,0,0,-1.2756532,9.0810546e-6,478.03773)"
|
||||
id="g8"
|
||||
style="fill:#000000">
|
||||
<path
|
||||
d="m 122.453,169.761 97.758,-169.34 -44.926,-0.422 -26.101,45.496 -26.286,-45.25 -22.32,0.008 -11.433,19.75 37.449,64.394 -26.582,46.258 z"
|
||||
fill="#5277c3"
|
||||
id="path1"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="M 157.738,239.515 59.961,70.183 37.133,108.882 63.484,154.229 11.152,154.366 0,173.702 l 11.391,19.777 74.488,-0.234 26.769,46.152 z"
|
||||
fill="#7ebae4"
|
||||
id="path2"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="M 165.238,104.155 360.77,104.143 338.672,65.026 286.223,65.171 312.27,19.784 301.102,0.456 278.277,0.429 241.238,65.058 187.883,65.167 Z"
|
||||
fill="#7ebae4"
|
||||
id="path3"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="m 279.043,178.35 -97.758,169.34 44.926,0.422 26.101,-45.496 26.286,45.254 22.32,-0.008 11.434,-19.754 -37.45,-64.39 26.582,-46.262 z"
|
||||
fill="#7ebae4"
|
||||
id="path4"
|
||||
style="fill:#000000" />
|
||||
<g
|
||||
fill="#5277c3"
|
||||
id="g7"
|
||||
style="fill:#000000">
|
||||
<path
|
||||
d="m 122.453,169.761 97.758,-169.34 -44.926,-0.422 -26.101,45.496 -26.286,-45.25 -22.32,0.008 -11.433,19.75 37.449,64.394 -26.582,46.258 z"
|
||||
id="path5"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="m 236,244.386 -195.535,0.011 22.101,39.118 52.45,-0.149 -26.047,45.391 11.168,19.328 22.82,0.023 37.043,-64.625 53.352,-0.109 z"
|
||||
id="path6"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="m 243.625,108.636 97.777,169.328 22.825,-38.696 -26.348,-45.351 52.332,-0.137 11.152,-19.336 -11.39,-19.777 -74.489,0.238 -26.769,-46.152 z"
|
||||
id="path7"
|
||||
style="fill:#000000" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1 +1,38 @@
|
||||
<svg viewBox="0 0 320 320" xmlns="http://www.w3.org/2000/svg"><path d="m297.06 130.97c7.26-21.79 4.76-45.66-6.85-65.48-17.46-30.4-52.56-46.04-86.84-38.68-15.25-17.18-37.16-26.95-60.13-26.81-35.04-.08-66.13 22.48-76.91 55.82-22.51 4.61-41.94 18.7-53.31 38.67-17.59 30.32-13.58 68.54 9.92 94.54-7.26 21.79-4.76 45.66 6.85 65.48 17.46 30.4 52.56 46.04 86.84 38.68 15.24 17.18 37.16 26.95 60.13 26.8 35.06.09 66.16-22.49 76.94-55.86 22.51-4.61 41.94-18.7 53.31-38.67 17.57-30.32 13.55-68.51-9.94-94.51zm-120.28 168.11c-14.03.02-27.62-4.89-38.39-13.88.49-.26 1.34-.73 1.89-1.07l63.72-36.8c3.26-1.85 5.26-5.32 5.24-9.07v-89.83l26.93 15.55c.29.14.48.42.52.74v74.39c-.04 33.08-26.83 59.9-59.91 59.97zm-128.84-55.03c-7.03-12.14-9.56-26.37-7.15-40.18.47.28 1.3.79 1.89 1.13l63.72 36.8c3.23 1.89 7.23 1.89 10.47 0l77.79-44.92v31.1c.02.32-.13.63-.38.83l-64.41 37.19c-28.69 16.52-65.33 6.7-81.92-21.95zm-16.77-139.09c7-12.16 18.05-21.46 31.21-26.29 0 .55-.03 1.52-.03 2.2v73.61c-.02 3.74 1.98 7.21 5.23 9.06l77.79 44.91-26.93 15.55c-.27.18-.61.21-.91.08l-64.42-37.22c-28.63-16.58-38.45-53.21-21.95-81.89zm221.26 51.49-77.79-44.92 26.93-15.54c.27-.18.61-.21.91-.08l64.42 37.19c28.68 16.57 38.51 53.26 21.94 81.94-7.01 12.14-18.05 21.44-31.2 26.28v-75.81c.03-3.74-1.96-7.2-5.2-9.06zm26.8-40.34c-.47-.29-1.3-.79-1.89-1.13l-63.72-36.8c-3.23-1.89-7.23-1.89-10.47 0l-77.79 44.92v-31.1c-.02-.32.13-.63.38-.83l64.41-37.16c28.69-16.55 65.37-6.7 81.91 22 6.99 12.12 9.52 26.31 7.15 40.1zm-168.51 55.43-26.94-15.55c-.29-.14-.48-.42-.52-.74v-74.39c.02-33.12 26.89-59.96 60.01-59.94 14.01 0 27.57 4.92 38.34 13.88-.49.26-1.33.73-1.89 1.07l-63.72 36.8c-3.26 1.85-5.26 5.31-5.24 9.06l-.04 89.79zm14.63-31.54 34.65-20.01 34.65 20v40.01l-34.65 20-34.65-20z"/></svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 322.58065 322.58064"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="openai-symbolic.svg"
|
||||
width="20"
|
||||
height="20"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="30.935922"
|
||||
inkscape:cx="9.0348044"
|
||||
inkscape:cy="14.917933"
|
||||
inkscape:window-width="1183"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 298.66868,131.77215 c 7.30439,-21.92321 4.7891,-45.939129 -6.89187,-65.880296 C 274.21007,35.30601 238.89549,19.570397 204.40593,26.975391 189.0627,9.6903649 167.01876,-0.13936259 143.90833,0.0014933 108.65412,-0.07899576 77.374064,22.618921 66.528162,56.162739 43.880552,60.800921 24.33177,74.977058 12.892261,95.069141 -4.8052718,125.57449 -0.77075743,164.02814 22.872905,190.18709 c -7.304382,21.92321 -4.789099,45.93913 6.891877,65.8803 17.566738,30.58585 52.881316,46.32146 87.370878,38.91646 15.33316,17.28503 37.38717,27.11476 60.49759,26.96384 35.27433,0.0905 66.56446,-22.62749 77.41036,-56.20149 22.64761,-4.63818 42.19639,-18.81432 53.6359,-38.9064 17.67741,-30.50536 13.63284,-68.92883 -10.00077,-95.08777 z M 177.65337,300.90986 c -14.11577,0.0201 -27.78885,-4.91989 -38.62469,-13.96485 0.493,-0.26159 1.34819,-0.73446 1.90156,-1.07654 l 64.10954,-37.02497 c 3.27993,-1.86131 5.29215,-5.35253 5.27203,-9.12545 v -90.37916 l 27.09463,15.64506 c 0.29178,0.14086 0.48294,0.42257 0.52318,0.74453 v 74.84477 c -0.0402,33.28222 -26.99402,60.26618 -60.27625,60.33661 z M 48.025738,245.54345 c -7.072976,-12.21422 -9.618443,-26.53121 -7.19371,-40.42564 0.472874,0.28171 1.307948,0.79483 1.901554,1.13691 l 64.109538,37.02497 c 3.24974,1.90155 7.2742,1.90155 10.534,0 l 78.26556,-45.19461 v 31.29012 c 0.0201,0.32196 -0.1308,0.63386 -0.38232,0.83508 l -64.80376,37.41735 c -28.86539,16.62099 -65.72938,6.74096 -82.4208,-22.08418 z M 31.153218,105.60314 c 7.042793,-12.234331 18.160346,-21.591185 31.400797,-26.450712 0,0.553362 -0.03018,1.529292 -0.03018,2.213449 v 74.059993 c -0.02012,3.76287 1.992105,7.25408 5.261973,9.11539 l 78.265542,45.18455 -27.09463,15.64506 c -0.27165,0.1811 -0.61373,0.21129 -0.91556,0.0805 L 53.227344,188.00382 C 24.42232,171.32247 14.542287,134.46853 31.143157,105.6132 Z m 222.612632,51.80478 -78.26556,-45.19461 27.09463,-15.634999 c 0.27165,-0.181101 0.61373,-0.211284 0.91557,-0.08049 l 64.81382,37.417349 c 28.85533,16.6713 38.74542,53.5856 22.07412,82.44093 -7.05285,12.21421 -18.16034,21.57107 -31.39073,26.44066 V 166.5233 c 0.0302,-3.76286 -1.97199,-7.24401 -5.23179,-9.11538 z m 26.96383,-40.58661 c -0.47287,-0.29178 -1.30794,-0.79483 -1.90155,-1.13691 L 214.71859,78.659433 c -3.24975,-1.901555 -7.2742,-1.901555 -10.53401,0 L 125.91903,123.85404 V 92.563919 c -0.0201,-0.321957 0.13079,-0.633852 0.38232,-0.835074 l 64.80376,-37.387171 c 28.86539,-16.651176 65.76963,-6.74096 82.41074,22.134493 7.03273,12.194093 9.5782,26.470833 7.19371,40.345143 z M 111.18953,172.59017 84.08484,156.94511 c -0.291773,-0.14086 -0.482934,-0.42257 -0.523179,-0.74453 V 81.355816 c 0.02012,-33.322473 27.054379,-60.326555 60.376859,-60.306432 14.09564,0 27.73854,4.950077 38.57438,13.964853 -0.493,0.261589 -1.33813,0.734462 -1.90155,1.076541 l -64.10954,37.02497 c -3.27993,1.86131 -5.29216,5.342462 -5.27204,9.115387 l -0.0402,90.338915 z m 14.71943,-31.73282 34.86183,-20.13232 34.86183,20.12226 v 40.2546 l -34.86183,20.12226 -34.86183,-20.12226 z"
|
||||
id="path1"
|
||||
style="stroke-width:1.00611" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
|
||||
<svg
|
||||
fill="#000000"
|
||||
height="20.000002"
|
||||
width="20"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
viewBox="0 0 493.42511 493.42516"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="ubuntu-logo-svgrepo-com.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs9" /><sodipodi:namedview
|
||||
id="namedview9"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#505050"
|
||||
inkscape:zoom="12.374369"
|
||||
inkscape:cx="24.76894"
|
||||
inkscape:cy="15.515943"
|
||||
inkscape:window-width="1415"
|
||||
inkscape:window-height="753"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Capa_1" />
|
||||
<g
|
||||
id="ubuntu"
|
||||
transform="translate(5.5573583e-4,0.00107926)">
|
||||
<g
|
||||
id="g2">
|
||||
<g
|
||||
id="g1">
|
||||
<path
|
||||
d="m 168.839,241.198 c 0,-38.117 17.894,-72.05 45.685,-93.896 L 171.988,79.22 c -35.648,25.603 -62.472,62.66 -75.127,105.796 19.811,12.751 32.949,35.031 32.949,60.353 0,24.424 -12.143,45.957 -30.783,58.918 13.606,40.86 40.12,75.838 74.706,100.113 l 39.559,-70.358 c -27.105,-21.838 -44.453,-55.318 -44.453,-92.844 z"
|
||||
id="path1" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3">
|
||||
<path
|
||||
d="m 109.704,245.368 c 0,28.484 -23.132,51.592 -51.609,51.592 -28.491,0 -51.606,-23.107 -51.606,-51.592 0,-28.47 23.115,-51.577 51.606,-51.577 28.477,0 51.609,23.107 51.609,51.577 z"
|
||||
id="path2" />
|
||||
</g>
|
||||
<g
|
||||
id="g5">
|
||||
<g
|
||||
id="g4">
|
||||
<path
|
||||
d="m 399.494,370.126 c 12.002,0 23.301,2.936 33.23,8.149 30.924,-32.591 50.906,-75.595 54.211,-123.228 l -80.148,-1.551 c -6.171,60.111 -56.954,106.941 -118.677,106.941 -17.084,0 -33.388,-3.594 -48.101,-10.093 l -39.841,69.704 c 26.56,13.069 56.376,20.411 87.941,20.411 13.622,0 26.981,-1.379 39.854,-4.006 2.746,-37.072 33.717,-66.327 71.531,-66.327 z"
|
||||
id="path3" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g6">
|
||||
<path
|
||||
d="m 451.071,441.847 c 0,28.478 -23.084,51.576 -51.577,51.576 -28.493,0 -51.594,-23.098 -51.594,-51.576 0,-28.5 23.101,-51.592 51.594,-51.592 28.493,0 51.577,23.092 51.577,51.592 z"
|
||||
id="path5" />
|
||||
</g>
|
||||
<g
|
||||
id="g8">
|
||||
<g
|
||||
id="g7">
|
||||
<path
|
||||
d="m 438.211,110.152 c -11.677,8.269 -25.968,13.163 -41.399,13.163 -39.637,0 -71.73,-32.102 -71.73,-71.715 0,-2.104 0.094,-4.139 0.25,-6.181 -12.05,-2.307 -24.503,-3.491 -37.222,-3.491 -31.859,0 -61.988,7.498 -88.689,20.777 l 39.607,69.75 c 14.979,-6.748 31.593,-10.544 49.082,-10.544 61.177,0 111.601,46.074 118.491,105.414 l 80.147,-2.447 C 483.209,181.12 465.487,141.372 438.211,110.152 Z"
|
||||
id="path6" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g9">
|
||||
<path
|
||||
d="m 448.374,51.601 c 0,28.492 -23.038,51.592 -51.561,51.592 -28.491,0 -51.592,-23.1 -51.592,-51.592 C 345.22,23.107 368.321,0 396.812,0 c 28.523,0 51.562,23.107 51.562,51.601 z"
|
||||
id="path8" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
@@ -1,8 +1,4 @@
|
||||
"use strict";
|
||||
const gi = imports.gi;
|
||||
const availableModules = Object.keys(gi);
|
||||
print("Available modules: " + availableModules.join(', '));
|
||||
|
||||
// Import
|
||||
import Gdk from 'gi://Gdk';
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js'
|
||||
@@ -68,7 +64,7 @@ export default {
|
||||
};
|
||||
|
||||
// Stuff that don't need to be toggled. And they're async so ugh...
|
||||
// Bar().catch(print); // Use this to debug the bar
|
||||
// Bar().catch(print); // Use this to debug the bar. Single monitor only.
|
||||
forMonitors(Bar);
|
||||
forMonitors(BarCornerTopleft);
|
||||
forMonitors(BarCornerTopright);
|
||||
forMonitors(BarCornerTopright);
|
||||
|
||||
@@ -71,7 +71,9 @@ export const oskLayouts = {
|
||||
{ keytype: "normal", label: "\\", labelShift: "|", shape: "expand", keycode: 43 }
|
||||
],
|
||||
[
|
||||
{ keytype: "normal", label: "Caps", shape: "caps", keycode: 58 },
|
||||
//{ keytype: "normal", label: "Caps", shape: "caps", keycode: 58 }, // not needed as double-pressing shift does that
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "normal", label: "a", labelShift: "A", shape: "normal", keycode: 30 },
|
||||
{ keytype: "normal", label: "s", labelShift: "S", shape: "normal", keycode: 31 },
|
||||
{ keytype: "normal", label: "d", labelShift: "D", shape: "normal", keycode: 32 },
|
||||
@@ -86,7 +88,7 @@ export const oskLayouts = {
|
||||
{ keytype: "normal", label: "Enter", shape: "expand", keycode: 28 }
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Shift", shape: "shift", keycode: 42 },
|
||||
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
|
||||
{ keytype: "normal", label: "z", labelShift: "Z", shape: "normal", keycode: 44 },
|
||||
{ keytype: "normal", label: "x", labelShift: "X", shape: "normal", keycode: 45 },
|
||||
{ keytype: "normal", label: "c", labelShift: "C", shape: "normal", keycode: 46 },
|
||||
@@ -97,7 +99,7 @@ export const oskLayouts = {
|
||||
{ keytype: "normal", label: ",", labelShift: "<", shape: "normal", keycode: 51 },
|
||||
{ keytype: "normal", label: ".", labelShift: ">", shape: "normal", keycode: 52 },
|
||||
{ keytype: "normal", label: "/", labelShift: "?", shape: "normal", keycode: 53 },
|
||||
{ keytype: "modkey", label: "Shift", shape: "expand", keycode: 54 }
|
||||
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 } // optional
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 29 },
|
||||
@@ -110,5 +112,107 @@ export const oskLayouts = {
|
||||
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 97 }
|
||||
]
|
||||
]
|
||||
},
|
||||
qwertz_full: {
|
||||
name: "QWERTZ - Full",
|
||||
name_short: "DE",
|
||||
comment: "Keyboard layout commonly used in German-speaking countries",
|
||||
keys: [
|
||||
[
|
||||
{ keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
|
||||
{ keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
|
||||
{ keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
|
||||
{ keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
|
||||
{ keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
|
||||
{ keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
|
||||
{ keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
|
||||
{ keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
|
||||
{ keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
|
||||
{ keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
|
||||
{ keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
|
||||
{ keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
|
||||
{ keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
|
||||
{ keytype: "normal", label: "Druck", shape: "fn", keycode: 99 },
|
||||
{ keytype: "normal", label: "Entf", shape: "fn", keycode: 111 }
|
||||
],
|
||||
[
|
||||
{ keytype: "normal", label: "^", labelShift: "°", labelAlt: "′", shape: "normal", keycode: 41 },
|
||||
{ keytype: "normal", label: "1", labelShift: "!", labelAlt: "¹", shape: "normal", keycode: 2 },
|
||||
{ keytype: "normal", label: "2", labelShift: "\"", labelAlt: "²", shape: "normal", keycode: 3 },
|
||||
{ keytype: "normal", label: "3", labelShift: "§", labelAlt: "³", shape: "normal", keycode: 4 },
|
||||
{ keytype: "normal", label: "4", labelShift: "$", labelAlt: "¼", shape: "normal", keycode: 5 },
|
||||
{ keytype: "normal", label: "5", labelShift: "%", labelAlt: "½", shape: "normal", keycode: 6 },
|
||||
{ keytype: "normal", label: "6", labelShift: "&", labelAlt: "¬", shape: "normal", keycode: 7 },
|
||||
{ keytype: "normal", label: "7", labelShift: "/", labelAlt: "{", shape: "normal", keycode: 8 },
|
||||
{ keytype: "normal", label: "8", labelShift: "(", labelAlt: "[", shape: "normal", keycode: 9 },
|
||||
{ keytype: "normal", label: "9", labelShift: ")", labelAlt: "]", shape: "normal", keycode: 10 },
|
||||
{ keytype: "normal", label: "0", labelShift: "=", labelAlt: "}", shape: "normal", keycode: 11 },
|
||||
{ keytype: "normal", label: "ß", labelShift: "?", labelAlt: "\\", shape: "normal", keycode: 12 },
|
||||
{ keytype: "normal", label: "´", labelShift: "`", labelAlt: "¸", shape: "normal", keycode: 13 },
|
||||
{ keytype: "normal", label: "⟵", shape: "expand", keycode: 14 }
|
||||
],
|
||||
[
|
||||
{ keytype: "normal", label: "Tab ⇆", shape: "tab", keycode: 15 },
|
||||
{ keytype: "normal", label: "q", labelShift: "Q", labelAlt: "@", shape: "normal", keycode: 16 },
|
||||
{ keytype: "normal", label: "w", labelShift: "W", labelAlt: "ſ", shape: "normal", keycode: 17 },
|
||||
{ keytype: "normal", label: "e", labelShift: "E", labelAlt: "€", shape: "normal", keycode: 18 },
|
||||
{ keytype: "normal", label: "r", labelShift: "R", labelAlt: "¶", shape: "normal", keycode: 19 },
|
||||
{ keytype: "normal", label: "t", labelShift: "T", labelAlt: "ŧ", shape: "normal", keycode: 20 },
|
||||
{ keytype: "normal", label: "z", labelShift: "Z", labelAlt: "←", shape: "normal", keycode: 21 },
|
||||
{ keytype: "normal", label: "u", labelShift: "U", labelAlt: "↓", shape: "normal", keycode: 22 },
|
||||
{ keytype: "normal", label: "i", labelShift: "I", labelAlt: "→", shape: "normal", keycode: 23 },
|
||||
{ keytype: "normal", label: "o", labelShift: "O", labelAlt: "ø", shape: "normal", keycode: 24 },
|
||||
{ keytype: "normal", label: "p", labelShift: "P", labelAlt: "þ", shape: "normal", keycode: 25 },
|
||||
{ keytype: "normal", label: "ü", labelShift: "Ü", labelAlt: "¨", shape: "normal", keycode: 26 },
|
||||
{ keytype: "normal", label: "+", labelShift: "*", labelAlt: "~", shape: "normal", keycode: 27 },
|
||||
{ keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
|
||||
],
|
||||
[
|
||||
//{ keytype: "normal", label: "Umschalt ⇩", shape: "caps", keycode: 58 },
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
{ keytype: "normal", label: "a", labelShift: "A", labelAlt: "æ", shape: "normal", keycode: 30 },
|
||||
{ keytype: "normal", label: "s", labelShift: "S", labelAlt: "ſ", shape: "normal", keycode: 31 },
|
||||
{ keytype: "normal", label: "d", labelShift: "D", labelAlt: "ð", shape: "normal", keycode: 32 },
|
||||
{ keytype: "normal", label: "f", labelShift: "F", labelAlt: "đ", shape: "normal", keycode: 33 },
|
||||
{ keytype: "normal", label: "g", labelShift: "G", labelAlt: "ŋ", shape: "normal", keycode: 34 },
|
||||
{ keytype: "normal", label: "h", labelShift: "H", labelAlt: "ħ", shape: "normal", keycode: 35 },
|
||||
{ keytype: "normal", label: "j", labelShift: "J", labelAlt: "", shape: "normal", keycode: 36 },
|
||||
{ keytype: "normal", label: "k", labelShift: "K", labelAlt: "ĸ", shape: "normal", keycode: 37 },
|
||||
{ keytype: "normal", label: "l", labelShift: "L", labelAlt: "ł", shape: "normal", keycode: 38 },
|
||||
{ keytype: "normal", label: "ö", labelShift: "Ö", labelAlt: "˝", shape: "normal", keycode: 39 },
|
||||
{ keytype: "normal", label: "ä", labelShift: 'Ä', labelAlt: "^", shape: "normal", keycode: 40 },
|
||||
{ keytype: "normal", label: "#", labelShift: '\'', labelAlt: "’", shape: "normal", keycode: 43 },
|
||||
{ keytype: "spacer", label: "", shape: "empty" },
|
||||
//{ keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
|
||||
{ keytype: "normal", label: "<", labelShift: ">", labelAlt: "|", shape: "normal", keycode: 86 },
|
||||
{ keytype: "normal", label: "y", labelShift: "Y", labelAlt: "»", shape: "normal", keycode: 44 },
|
||||
{ keytype: "normal", label: "x", labelShift: "X", labelAlt: "«", shape: "normal", keycode: 45 },
|
||||
{ keytype: "normal", label: "c", labelShift: "C", labelAlt: "¢", shape: "normal", keycode: 46 },
|
||||
{ keytype: "normal", label: "v", labelShift: "V", labelAlt: "„", shape: "normal", keycode: 47 },
|
||||
{ keytype: "normal", label: "b", labelShift: "B", labelAlt: "“", shape: "normal", keycode: 48 },
|
||||
{ keytype: "normal", label: "n", labelShift: "N", labelAlt: "”", shape: "normal", keycode: 49 },
|
||||
{ keytype: "normal", label: "m", labelShift: "M", labelAlt: "µ", shape: "normal", keycode: 50 },
|
||||
{ keytype: "normal", label: ",", labelShift: ";", labelAlt: "·", shape: "normal", keycode: 51 },
|
||||
{ keytype: "normal", label: ".", labelShift: ":", labelAlt: "…", shape: "normal", keycode: 52 },
|
||||
{ keytype: "normal", label: "-", labelShift: "_", labelAlt: "–", shape: "normal", keycode: 53 },
|
||||
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 }, // optional
|
||||
],
|
||||
[
|
||||
{ keytype: "modkey", label: "Strg", shape: "control", keycode: 29 },
|
||||
//{ keytype: "normal", label: "", shape: "normal", keycode: 125 }, // dangerous
|
||||
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
|
||||
{ keytype: "normal", label: "Leertaste", shape: "space", keycode: 57 },
|
||||
{ keytype: "modkey", label: "Alt Gr", shape: "normal", keycode: 100 },
|
||||
// { label: "Super", shape: "normal", keycode: 126 }, // dangerous
|
||||
//{ keytype: "normal", label: "Menu", shape: "normal", keycode: 139 }, // doesn't work?
|
||||
{ keytype: "modkey", label: "Strg", shape: "control", keycode: 97 },
|
||||
{ keytype: "normal", label: "⇦", shape: "normal", keycode: 105 },
|
||||
{ keytype: "normal", label: "⇨", shape: "normal", keycode: 106 },
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,208 +1,62 @@
|
||||
// SPDX-FileCopyrightText: 2021 Uwe Jugel
|
||||
// SPDX-License-Identifier: MIT
|
||||
// This file is part of md2pango (https://github.com/ubunatic/md2pango).
|
||||
// Converts from Markdown to Pango. This does not support code blocks.
|
||||
// For illogical-impulse, code blocks are treated separately, in their own GtkSourceView widgets.
|
||||
// Partly inherited from https://github.com/ubunatic/md2pango
|
||||
|
||||
const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace'
|
||||
const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace';
|
||||
|
||||
const H1 = "H1", H2 = "H2", H3 = "H3", H4 = "H4", H5 = "H5", BULLET = "BULLET", NUMBERING = "NUMBERING", CODE = "CODE"
|
||||
const BOLD = "BOLD", EMPH = "EMPH", INLCODE = "INLCODE", LINK = "LINK", HEXCOLOR = "HEXCOLOR", UND = "UND"
|
||||
|
||||
let sub_h1, sub_h2, sub_h3, sub_h4, sub_h5
|
||||
|
||||
// m2p_sections defines how to detect special markdown sections.
|
||||
// These expressions scan the full line to detect headings, lists, and code.
|
||||
const m2p_sections = [
|
||||
sub_h1 = { name: H1, re: /^(#\s+)(.*)(\s*)$/, sub: "<span font_weight='bold' size='170%'>$2</span>" },
|
||||
sub_h2 = { name: H2, re: /^(##\s+)(.*)(\s*)$/, sub: "<span font_weight='bold' size='150%'>$2</span>" },
|
||||
sub_h3 = { name: H3, re: /^(###\s+)(.*)(\s*)$/, sub: "<span font_weight='bold' size='125%'>$2</span>" },
|
||||
sub_h4 = { name: H4, re: /^(####\s+)(.*)(\s*)$/, sub: "<span font_weight='bold' size='100%'>$2</span>" },
|
||||
sub_h5 = { name: H5, re: /^(#####\s+)(.*)(\s*)$/, sub: "<span font_weight='bold' size='90%'>$2</span>" },
|
||||
{ name: BULLET, re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: "$1• $3" },
|
||||
{ name: NUMBERING, re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: " $1$2" },
|
||||
]
|
||||
|
||||
// m2p_styles defines how to replace inline styled text
|
||||
const m2p_styles = [
|
||||
{ name: BOLD, re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "<b>$2</b>" },
|
||||
{ name: UND, re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "<u>$2</u>" },
|
||||
{ name: EMPH, re: /\*(\S.*?\S)\*/g, sub: "<i>$1</i>" },
|
||||
// { name: EMPH, re: /_(\S.*?\S)_/g, sub: "<i>$1</i>" },
|
||||
{ name: HEXCOLOR, re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: `<span bgcolor='#$1' fgcolor='#000000' font_family='${monospaceFonts}'> #$1 </span>` },
|
||||
{ name: INLCODE, re: /(`)([^`]*)(`)/g, sub: `<span font_weight='bold' font_family='${monospaceFonts}'> $2 </span>` },
|
||||
// { name: UND, re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "<u>$2</u>" },
|
||||
]
|
||||
|
||||
const re_comment = /^\s*<!--.*-->\s*$/
|
||||
const re_color = /^(\s*<!--\s*(fg|bg)=(#?[0-9a-z_A-Z-]*)\s*((fg|bg)=(#?[0-9a-z_A-Z-]*))?\s*-->\s*)$/
|
||||
const re_reset = /(<!--\/-->)/
|
||||
const re_uri = /http[s]?:\/\/[^\s']*/
|
||||
const re_href = "/href='(http[s]?:\\/\\/[^\\s]*)'"
|
||||
const re_atag = "<a\s.*>.*(http[s]?:\\/\\/[^\\s]*).*</a>/"
|
||||
const re_h1line = /^===+\s*$/
|
||||
const re_h2line = /^---+\s*$/
|
||||
|
||||
const m2p_escapes = [
|
||||
[/<!--.*-->/, ''],
|
||||
[/&/g, '&'],
|
||||
[/</g, '<'],
|
||||
[/>/g, '>'],
|
||||
]
|
||||
|
||||
const code_color_span = "<span foreground='#bbb' background='#222'>"
|
||||
|
||||
const escape_line = (line) => m2p_escapes.reduce((l, esc) => l.replace(...esc), line)
|
||||
|
||||
const pad = (lines, start = 1, end = 1) => {
|
||||
let len = lines.reduce((n, l) => l.length > n ? l.length : n, 0)
|
||||
return lines.map((l) => l.padEnd(len + end, ' ').padStart(len + end + start, ' '))
|
||||
const replacements = {
|
||||
'indents': [
|
||||
{ name: 'BULLET', re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: ' $1- $3' },
|
||||
{ name: 'NUMBERING', re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: ' $1 $2' },
|
||||
],
|
||||
'escapes': [
|
||||
{ name: 'COMMENT', re: /<!--.*-->/, sub: '' },
|
||||
{ name: 'AMPERSTAND', re: /&/g, sub: '&' },
|
||||
{ name: 'LESSTHAN', re: /</g, sub: '<' },
|
||||
{ name: 'GREATERTHAN', re: />/g, sub: '>' },
|
||||
],
|
||||
'sections': [
|
||||
{ name: 'H1', re: /^(#\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="170%">$2</span>' },
|
||||
{ name: 'H2', re: /^(##\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="150%">$2</span>' },
|
||||
{ name: 'H3', re: /^(###\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="125%">$2</span>' },
|
||||
{ name: 'H4', re: /^(####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="100%">$2</span>' },
|
||||
{ name: 'H5', re: /^(#####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="90%">$2</span>' },
|
||||
],
|
||||
'styles': [
|
||||
{ name: 'BOLD', re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "<b>$2</b>" },
|
||||
{ name: 'UND', re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "<u>$2</u>" },
|
||||
{ name: 'EMPH', re: /\*(\S.*?\S)\*/g, sub: "<i>$1</i>" },
|
||||
// { name: 'EMPH', re: /_(\S.*?\S)_/g, sub: "<i>$1</i>" },
|
||||
{ name: 'HEXCOLOR', re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: '<span bgcolor="#$1" fgcolor="#000000" font_family="' + monospaceFonts + '">#$1</span>' },
|
||||
{ name: 'INLCODE', re: /(`)([^`]*)(`)/g, sub: '<span font_weight="bold" font_family="' + monospaceFonts + '">$2</span>' },
|
||||
// { name: 'UND', re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "<u>$2</u>" },
|
||||
],
|
||||
}
|
||||
|
||||
const replaceCategory = (text, replaces) => {
|
||||
for (const type of replaces) {
|
||||
text = text.replace(type.re, type.sub);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// Main function
|
||||
|
||||
export default (text) => {
|
||||
let lines = text.split('\n')
|
||||
|
||||
// Indicates if the current line is within a code block
|
||||
let is_code = false
|
||||
let code_lines = []
|
||||
|
||||
let output = []
|
||||
let color_span_open = false
|
||||
let tt_must_close = false
|
||||
|
||||
const try_close_span = () => {
|
||||
if (color_span_open) {
|
||||
output.push('</span>')
|
||||
color_span_open = false
|
||||
}
|
||||
}
|
||||
|
||||
const try_open_span = () => {
|
||||
if (!color_span_open) {
|
||||
output.push('</span>')
|
||||
color_span_open = false
|
||||
}
|
||||
}
|
||||
|
||||
let output = [];
|
||||
// Replace
|
||||
for (const line of lines) {
|
||||
// first parse color macros in non-code texts
|
||||
if (!is_code) {
|
||||
let colors = line.match(re_color)
|
||||
if (colors || line.match(re_reset)) {
|
||||
try_close_span()
|
||||
}
|
||||
|
||||
if (colors) {
|
||||
try_close_span()
|
||||
if (color_span_open) {
|
||||
close_span()
|
||||
}
|
||||
|
||||
let fg = colors[2] == 'fg' ? colors[3] : colors[5] == 'fg' ? colors[6] : ''
|
||||
let bg = colors[2] == 'bg' ? colors[3] : colors[5] == 'bg' ? colors[6] : ''
|
||||
let attrs = ''
|
||||
|
||||
if (fg != '') {
|
||||
attrs += ` foreground='${fg}'`
|
||||
}
|
||||
|
||||
if (bg != '') {
|
||||
attrs += ` background='${bg}'`
|
||||
}
|
||||
|
||||
if (attrs != '') {
|
||||
output.push(`<span${attrs}>`)
|
||||
color_span_open = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// all macros processed, let's remove remaining comments
|
||||
if (line.match(re_comment)) {
|
||||
continue
|
||||
}
|
||||
|
||||
// is this line an opening statement of a code block
|
||||
let code_start = false
|
||||
|
||||
// escape all non-verbatim text
|
||||
let result = is_code ? line : escape_line(line)
|
||||
|
||||
for (const { name, re, sub } of m2p_sections) {
|
||||
if (line.match(re)) {
|
||||
if (name === CODE) {
|
||||
if (!is_code) {
|
||||
// haven't been inside a code block, so ``` indicates
|
||||
// that it is starting now
|
||||
code_start = true
|
||||
is_code = true
|
||||
|
||||
if (color_span_open) {
|
||||
// cannot color
|
||||
result = '<tt>'
|
||||
tt_must_close = false
|
||||
} else {
|
||||
result = code_color_span + '<tt>'
|
||||
tt_must_close = true
|
||||
}
|
||||
} else {
|
||||
// the code block ends now
|
||||
is_code = false
|
||||
output.push(...pad(code_lines).map(escape_line))
|
||||
code_lines = []
|
||||
result = '</tt>'
|
||||
if (tt_must_close) {
|
||||
result += '</span>'
|
||||
tt_must_close = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_code) {
|
||||
result = line
|
||||
} else {
|
||||
result = line.replace(re, sub)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_code && !code_start) {
|
||||
code_lines.push(result)
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.match(re_h1line)) {
|
||||
output.push(`# ${output.pop()}`.replace(sub_h1.re, sub_h1.sub))
|
||||
continue
|
||||
}
|
||||
|
||||
if (line.match(re_h2line)) {
|
||||
output.push(`## ${output.pop()}`.replace(sub_h2.re, sub_h2.sub))
|
||||
continue
|
||||
}
|
||||
|
||||
// all other text can be styled
|
||||
for (const style of m2p_styles) {
|
||||
result = result.replace(style.re, style.sub)
|
||||
}
|
||||
|
||||
// all raw urls can be linked if possible
|
||||
let uri = result.match(re_uri) // look for any URI
|
||||
let href = result.match(re_href) // and for URIs in href=''
|
||||
let atag = result.match(re_atag) // and for URIs in <a></a>
|
||||
href = href && href[1] == uri
|
||||
atag = href && atag[1] == uri
|
||||
if (uri && (href || atag)) {
|
||||
result = result.replace(uri, `<a href='${uri}'>${uri}</a>`)
|
||||
}
|
||||
|
||||
let result = line;
|
||||
result = replaceCategory(result, replacements.indents);
|
||||
result = replaceCategory(result, replacements.escapes);
|
||||
result = replaceCategory(result, replacements.sections);
|
||||
result = replaceCategory(result, replacements.styles);
|
||||
output.push(result)
|
||||
}
|
||||
|
||||
try_close_span()
|
||||
|
||||
// remove trailing whitespaces
|
||||
// Remove trailing whitespaces
|
||||
output = output.map(line => line.replace(/ +$/, ''))
|
||||
|
||||
return output.join('\n')
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
export const markdownTest = `# Heading 1
|
||||
@@ -227,5 +81,6 @@ export const markdownTest = `# Heading 1
|
||||
myArray = [23, 123, 43, 54, '6969'];
|
||||
console.log('uwu');
|
||||
\`\`\`
|
||||
To update arch lincox, run \`sudo pacman -Syu\`
|
||||
- Random instruction thing
|
||||
- To update arch lincox, run \`sudo pacman -Syu\`
|
||||
`;
|
||||
@@ -56,12 +56,6 @@ const NotificationIcon = (notifObject) => {
|
||||
Icon({
|
||||
vpack: 'center',
|
||||
icon: icon,
|
||||
setup: (self) => Utils.timeout(1, () => {
|
||||
const styleContext = self.get_parent().get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width * 0.7, height * 0.7, 1); // im too lazy to add another box lol
|
||||
}, self),
|
||||
})
|
||||
:
|
||||
MaterialIcon(`${notifObject.urgency == 'critical' ? 'release_alert' : guessMessageType(notifObject.summary.toLowerCase())}`, 'hugerass', {
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
## Defaults
|
||||
keepGensDef=30; keepDaysDef=30
|
||||
keepGens=$keepGensDef; keepDays=$keepDaysDef
|
||||
|
||||
## Usage
|
||||
usage () {
|
||||
printf "Usage:\n\t ./trim-generations.sh <keep-gernerations> <keep-days> <profile> \n\n
|
||||
(defaults are: Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef Profile=user)\n\n"
|
||||
printf "If you enter any parameters, you must enter all three, or none to use defaults.\n"
|
||||
printf "Example:\n\t trim-generations.sh 15 10 home-manager\n"
|
||||
printf " this will work on the home-manager profile and keep all generations from the\n"
|
||||
printf "last 10 days, and keep at least 15 generations no matter how old.\n"
|
||||
printf "\nProfiles available are:\tuser, home-manager, channels, system (root)\n"
|
||||
printf "\n-h or --help prints this help text."
|
||||
}
|
||||
|
||||
if [ $# -eq 1 ]; then # if help requested
|
||||
if [ $1 = "-h" ]; then
|
||||
usage
|
||||
exit 1;
|
||||
fi
|
||||
if [ $1 = "--help" ]; then
|
||||
usage
|
||||
exit 2;
|
||||
fi
|
||||
printf "Dont recognise your option exiting..\n\n"
|
||||
usage
|
||||
exit 3;
|
||||
|
||||
elif [ $# -eq 0 ]; then # print the defaults
|
||||
printf "The current defaults are:\n Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef \n\n"
|
||||
read -p "Keep these defaults? (y/n):" answer
|
||||
|
||||
case "$answer" in
|
||||
[yY1] )
|
||||
printf "Using defaults..\n"
|
||||
;;
|
||||
[nN0] ) printf "ok, doing nothing, exiting..\n"
|
||||
exit 6;
|
||||
;;
|
||||
* ) printf "%b" "Doing nothing, exiting.."
|
||||
exit 7;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
## Handle parameters (and change if root)
|
||||
if [[ $EUID -ne 0 ]]; then # if not root
|
||||
profile=$(readlink /home/$USER/.nix-profile)
|
||||
else
|
||||
if [ -d /nix/var/nix/profiles/system ]; then # maybe this or the other
|
||||
profile="/nix/var/nix/profiles/system"
|
||||
elif [ -d /nix/var/nix/profiles/default ]; then
|
||||
profile="/nix/var/nix/profiles/default"
|
||||
else
|
||||
echo "Cant find profile for root. Exiting"
|
||||
exit 8
|
||||
fi
|
||||
fi
|
||||
if (( $# < 1 )); then
|
||||
printf "Keeping default: $keepGensDef generations OR $keepDaysDef days, whichever is more\n"
|
||||
elif [[ $# -le 2 ]]; then
|
||||
printf "\nError: Not enough arguments.\n\n" >&2
|
||||
usage
|
||||
exit 1
|
||||
elif (( $# > 4)); then
|
||||
printf "\nError: Too many arguments.\n\n" >&2
|
||||
usage
|
||||
exit 2
|
||||
else
|
||||
if [ $1 -lt 1 ]; then
|
||||
printf "using Gen numbers less than 1 not recommended. Setting to min=1\n"
|
||||
read -p "is that ok? (y/n): " asnwer
|
||||
#printf "$asnwer"
|
||||
case "$asnwer" in
|
||||
[yY1] )
|
||||
printf "ok, continuing..\n"
|
||||
;;
|
||||
[nN0] )
|
||||
printf "ok, doing nothing, exiting..\n"
|
||||
exit 6;
|
||||
;;
|
||||
* )
|
||||
printf "%b" "Doing nothing, exiting.."
|
||||
exit 7;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ $2 -lt 0 ]; then
|
||||
printf "using negative days number not recommended. Setting to min=0\n"
|
||||
read -p "is that ok? (y/n): " asnwer
|
||||
|
||||
case "$asnwer" in
|
||||
[yY1] )
|
||||
printf "ok, continuing..\n"
|
||||
;;
|
||||
[nN0] )
|
||||
printf "ok, doing nothing, exiting..\n"
|
||||
exit 6;
|
||||
;;
|
||||
* )
|
||||
printf "%b" "Doing nothing, exiting.."
|
||||
exit 7;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
keepGens=$1; keepDays=$2;
|
||||
(( keepGens < 1 )) && keepGens=1
|
||||
(( keepDays < 0 )) && keepDays=0
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
if [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
|
||||
profile=$(readlink /home/$USER/.nix-profile)
|
||||
elif [[ $3 == "home-manager" ]]; then
|
||||
# home-manager defaults to $XDG_STATE_HOME; otherwise, use
|
||||
# `home-manager generations` and `nix-store --query --roots
|
||||
# /nix/store/...` to figure out what reference is keeping the old
|
||||
# generations alive.
|
||||
profile="${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles/home-manager"
|
||||
elif [[ $3 == "channels" ]]; then
|
||||
profile="/nix/var/nix/profiles/per-user/$USER/channels"
|
||||
else
|
||||
printf "\nError: Do not understand your third argument. Should be one of: (user / home-manager/ channels)\n\n"
|
||||
usage
|
||||
exit 3
|
||||
fi
|
||||
else
|
||||
if [[ $3 == "system" ]]; then
|
||||
profile="/nix/var/nix/profiles/system"
|
||||
elif [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
|
||||
profile="/nix/var/nix/profiles/default"
|
||||
else
|
||||
printf "\nError: Do not understand your third argument. Should be one of: (user / system)\n\n"
|
||||
usage
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
printf "OK! \t Keep Gens = $keepGens \t Keep Days = $keepDays\n\n"
|
||||
fi
|
||||
|
||||
printf "Operating on profile: \t $profile\n\n"
|
||||
|
||||
## Runs at the end, to decide whether to delete profiles that match chosen parameters.
|
||||
choose () {
|
||||
local default="$1"
|
||||
local prompt="$2"
|
||||
local answer
|
||||
|
||||
read -p "$prompt" answer
|
||||
[ -z "$answer" ] && answer="$default"
|
||||
|
||||
case "$answer" in
|
||||
[yY1] ) #printf "answered yes!\n"
|
||||
nix-env --delete-generations -p $profile ${!gens[@]}
|
||||
exit 0
|
||||
;;
|
||||
[nN0] ) printf "Ok doing nothing exiting..\n"
|
||||
exit 6;
|
||||
;;
|
||||
* ) printf "%b" "Unexpected answer '$answer'!" >&2
|
||||
exit 7;
|
||||
;;
|
||||
esac
|
||||
} # end of function choose
|
||||
|
||||
# printf "profile = $profile\n\n"
|
||||
## Query nix-env for generations list
|
||||
IFS=$'\n' nixGens=( $(nix-env --list-generations -p $profile | sed 's:^\s*::; s:\s*$::' | tr '\t' ' ' | tr -s ' ') )
|
||||
timeNow=$(date +%s)
|
||||
|
||||
## Get info on oldest generation
|
||||
IFS=' ' read -r -a oldestGenArr <<< "${nixGens[0]}"
|
||||
oldestGen=${oldestGenArr[0]}
|
||||
oldestDate=${oldestGenArr[1]}
|
||||
printf "%-30s %s\n" "oldest generation:" $oldestGen
|
||||
#oldestDate=${nixGens[0]:3:19}
|
||||
printf "%-30s %s\n" "oldest generation created:" $oldestDate
|
||||
oldestTime=$(date -d "$oldestDate" +%s)
|
||||
oldestElapsedSecs=$((timeNow-oldestTime))
|
||||
oldestElapsedMins=$((oldestElapsedSecs/60))
|
||||
oldestElapsedHours=$((oldestElapsedMins/60))
|
||||
oldestElapsedDays=$((oldestElapsedHours/24))
|
||||
printf "%-30s %s\n" "minutes before now:" $oldestElapsedMins
|
||||
printf "%-30s %s\n" "hours before now:" $oldestElapsedHours
|
||||
printf "%-30s %s\n\n" "days before now:" $oldestElapsedDays
|
||||
|
||||
## Get info on current generation
|
||||
for i in "${nixGens[@]}"; do
|
||||
IFS=' ' read -r -a iGenArr <<< "$i"
|
||||
genNumber=${iGenArr[0]}
|
||||
genDate=${iGenArr[1]}
|
||||
if [[ "$i" =~ current ]]; then
|
||||
currentGen=$genNumber
|
||||
printf "%-30s %s\n" "current generation:" $currentGen
|
||||
currentDate=$genDate
|
||||
printf "%-30s %s\n" "current generation created:" $currentDate
|
||||
currentTime=$(date -d "$currentDate" +%s)
|
||||
currentElapsedSecs=$((timeNow-currentTime))
|
||||
currentElapsedMins=$((currentElapsedSecs/60))
|
||||
currentElapsedHours=$((currentElapsedMins/60))
|
||||
currentElapsedDays=$((currentElapsedHours/24))
|
||||
printf "%-30s %s\n" "minutes before now:" $currentElapsedMins
|
||||
printf "%-30s %s\n" "hours before now:" $currentElapsedHours
|
||||
printf "%-30s %s\n\n" "days before now:" $currentElapsedDays
|
||||
fi
|
||||
done
|
||||
|
||||
## Compare oldest and current generations
|
||||
timeBetweenOldestAndCurrent=$((currentTime-oldestTime))
|
||||
elapsedDays=$((timeBetweenOldestAndCurrent/60/60/24))
|
||||
generationsDiff=$((currentGen-oldestGen))
|
||||
|
||||
## Figure out what we should do, based on generations and options
|
||||
if [[ elapsedDays -le keepDays ]]; then
|
||||
printf "All generations are no more than $keepDays days older than current generation. \nOldest gen days difference from current gen: $elapsedDays \n\n\tNothing to do!\n"
|
||||
exit 4;
|
||||
elif [[ generationsDiff -lt keepGens ]]; then
|
||||
printf "Oldest generation ($oldestGen) is only $generationsDiff generations behind current ($currentGen). \n\n\t Nothing to do!\n"
|
||||
exit 5;
|
||||
else
|
||||
printf "\tSomething to do...\n"
|
||||
declare -a gens
|
||||
for i in "${nixGens[@]}"; do
|
||||
IFS=' ' read -r -a iGenArr <<< "$i"
|
||||
genNumber=${iGenArr[0]}
|
||||
genDiff=$((currentGen-genNumber))
|
||||
genDate=${iGenArr[1]}
|
||||
genTime=$(date -d "$genDate" +%s)
|
||||
elapsedSecs=$((timeNow-genTime))
|
||||
genDaysOld=$((elapsedSecs/60/60/24))
|
||||
if [[ genDaysOld -gt keepDays ]] && [[ genDiff -ge keepGens ]]; then
|
||||
gens["$genNumber"]="$genDate, $genDaysOld day(s) old"
|
||||
fi
|
||||
done
|
||||
printf "\nFound the following generation(s) to delete:\n"
|
||||
for K in "${!gens[@]}"; do
|
||||
printf "generation $K \t ${gens[$K]}\n"
|
||||
done
|
||||
printf "\n"
|
||||
choose "y" "Do you want to delete these? [Y/n]: "
|
||||
fi
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from signal import SIGINT, SIGTERM, signal
|
||||
from threading import Event
|
||||
|
||||
from pywayland.client.display import Display
|
||||
from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import (
|
||||
ZwpIdleInhibitManagerV1,
|
||||
)
|
||||
from pywayland.protocol.wayland.wl_compositor import WlCompositor
|
||||
from pywayland.protocol.wayland.wl_registry import WlRegistryProxy
|
||||
from pywayland.protocol.wayland.wl_surface import WlSurface
|
||||
|
||||
|
||||
@dataclass
|
||||
class GlobalRegistry:
|
||||
surface: WlSurface | None = None
|
||||
inhibit_manager: ZwpIdleInhibitManagerV1 | None = None
|
||||
|
||||
|
||||
def handle_registry_global(
|
||||
wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int
|
||||
) -> None:
|
||||
global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry()
|
||||
|
||||
if iface_name == "wl_compositor":
|
||||
compositor = wl_registry.bind(id_num, WlCompositor, version)
|
||||
global_registry.surface = compositor.create_surface() # type: ignore
|
||||
elif iface_name == "zwp_idle_inhibit_manager_v1":
|
||||
global_registry.inhibit_manager = wl_registry.bind(
|
||||
id_num, ZwpIdleInhibitManagerV1, version
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
done = Event()
|
||||
signal(SIGINT, lambda _, __: done.set())
|
||||
signal(SIGTERM, lambda _, __: done.set())
|
||||
|
||||
global_registry = GlobalRegistry()
|
||||
|
||||
display = Display()
|
||||
display.connect()
|
||||
|
||||
registry = display.get_registry() # type: ignore
|
||||
registry.user_data = global_registry
|
||||
registry.dispatcher["global"] = handle_registry_global
|
||||
|
||||
def shutdown() -> None:
|
||||
display.dispatch()
|
||||
display.roundtrip()
|
||||
display.disconnect()
|
||||
|
||||
display.dispatch()
|
||||
display.roundtrip()
|
||||
|
||||
if global_registry.surface is None or global_registry.inhibit_manager is None:
|
||||
print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.")
|
||||
shutdown()
|
||||
sys.exit(1)
|
||||
|
||||
inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore
|
||||
global_registry.surface
|
||||
)
|
||||
|
||||
display.dispatch()
|
||||
display.roundtrip()
|
||||
|
||||
print("Inhibiting idle...")
|
||||
done.wait()
|
||||
print("Shutting down...")
|
||||
|
||||
inhibitor.destroy()
|
||||
|
||||
shutdown()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -285,6 +285,7 @@ $bar_subgroup_bg: $surfaceVariant;
|
||||
@include element_decel;
|
||||
min-height: 1.032rem;
|
||||
min-width: 1.032rem;
|
||||
font-size: 1.032rem;
|
||||
}
|
||||
|
||||
.bar-statusicons {
|
||||
|
||||
@@ -40,14 +40,14 @@ menu {
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
menubar > menuitem {
|
||||
menubar>menuitem {
|
||||
border-radius: 0.545rem;
|
||||
-gtk-outline-radius: 0.545rem;
|
||||
min-width: 13.636rem;
|
||||
min-height: 2.727rem;
|
||||
}
|
||||
|
||||
menu > menuitem {
|
||||
menu>menuitem {
|
||||
padding: 0.4em 1.5rem;
|
||||
background: transparent;
|
||||
transition: 0.2s ease background;
|
||||
@@ -55,11 +55,12 @@ menu > menuitem {
|
||||
-gtk-outline-radius: 0.545rem;
|
||||
}
|
||||
|
||||
menu > menuitem:hover,
|
||||
menu > menuitem:focus {
|
||||
menu>menuitem:hover,
|
||||
menu>menuitem:focus {
|
||||
background-color: mix($surfaceVariant, $onSurfaceVariant, 90%);
|
||||
}
|
||||
menu > menuitem:active {
|
||||
|
||||
menu>menuitem:active {
|
||||
background-color: mix($surfaceVariant, $onSurfaceVariant, 80%);
|
||||
}
|
||||
|
||||
@@ -93,6 +94,33 @@ tooltip {
|
||||
border: 1px solid $onSurfaceVariant;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Emoji Chooser structure
|
||||
// popover
|
||||
// ├── box.emoji-searchbar
|
||||
// │ ╰── entry.search
|
||||
// ╰── box.emoji-toolbar
|
||||
// ├── button.image-button.emoji-section
|
||||
// ├── ...
|
||||
// ╰── button.image-button.emoji-section
|
||||
|
||||
popover {
|
||||
@include elevation-border-softer;
|
||||
padding: 0.681rem;
|
||||
background: $surfaceVariant;
|
||||
color: $onSurfaceVariant;
|
||||
border-radius: 1.159rem;
|
||||
-gtk-outline-radius: 1.159rem;
|
||||
|
||||
animation-name: appear;
|
||||
animation-duration: 40ms;
|
||||
animation-timing-function: ease-out;
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
.configtoggle-box {
|
||||
padding: 0.205rem 0.341rem;
|
||||
border: 0.136rem solid transparent;
|
||||
@@ -145,17 +173,17 @@ tooltip {
|
||||
border: 0.068rem solid $outline;
|
||||
}
|
||||
|
||||
.segment-container > *:first-child {
|
||||
.segment-container>*:first-child {
|
||||
border-top-left-radius: 9999px;
|
||||
border-bottom-left-radius: 9999px;
|
||||
}
|
||||
|
||||
.segment-container > * {
|
||||
.segment-container>* {
|
||||
border-right: 0.068rem solid $outline;
|
||||
padding: 0.341rem 0.682rem;
|
||||
}
|
||||
|
||||
.segment-container > *:last-child {
|
||||
.segment-container>*:last-child {
|
||||
border-right: 0rem solid transparent;
|
||||
border-top-right-radius: 9999px;
|
||||
border-bottom-right-radius: 9999px;
|
||||
@@ -203,4 +231,4 @@ tooltip {
|
||||
|
||||
.gap-h-15 {
|
||||
min-width: 1.023rem;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
.dock-app-icon {
|
||||
min-width: 3.409rem;
|
||||
min-height: 3.409rem;
|
||||
font-size: 3.409rem;
|
||||
}
|
||||
|
||||
.dock-separator {
|
||||
|
||||
@@ -55,12 +55,12 @@
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.txt-badonkers {
|
||||
.txt-gigantic {
|
||||
@include mainfont;
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.txt-tiddies {
|
||||
.txt-massive {
|
||||
@include mainfont;
|
||||
font-size: 2.7273rem;
|
||||
}
|
||||
@@ -127,6 +127,10 @@
|
||||
@include actiontext;
|
||||
}
|
||||
|
||||
.txt-thin {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.txt-semibold {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ $notif_surface: $t_background;
|
||||
@include full-rounding;
|
||||
min-width: 3.409rem;
|
||||
min-height: 3.409rem;
|
||||
font-size: 3.409rem;
|
||||
}
|
||||
|
||||
.notif-icon-material {
|
||||
|
||||
@@ -110,3 +110,9 @@ $osk_key_fontsize: 1.091rem;
|
||||
background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 70%);
|
||||
font-size: $osk_key_fontsize;
|
||||
}
|
||||
|
||||
.osk-key-empty, .osk-key-empty:hover, .osk-key-empty:focus {
|
||||
min-width: $osk_key_width;
|
||||
min-height: $osk_key_height;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -445,15 +445,96 @@ $onChatgpt: $onPrimary;
|
||||
.sidebar-module {
|
||||
@include normal-rounding;
|
||||
@include group-padding;
|
||||
background-color: $t_surface;
|
||||
background-color: $l_l_t_surfaceVariant;
|
||||
padding: 0.682rem;
|
||||
}
|
||||
|
||||
.sidebar-module-btn-arrow {
|
||||
@include full-rounding;
|
||||
@include icon-material;
|
||||
background-color: $t_surfaceVariant;
|
||||
background-color: $l_l_t_surfaceVariant;
|
||||
min-width: 1.705rem;
|
||||
min-height: 1.705rem;
|
||||
|
||||
&:hover {
|
||||
background-color: $hovercolor;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-module-scripts-button {
|
||||
@include full-rounding;
|
||||
@include icon-material;
|
||||
background-color: $l_l_t_surfaceVariant;
|
||||
min-width: 1.705rem;
|
||||
min-height: 1.705rem;
|
||||
|
||||
&:hover {
|
||||
background-color: $hovercolor;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $activecolor;
|
||||
}
|
||||
}
|
||||
|
||||
$colorpicker_rounding: 0.341rem;
|
||||
|
||||
.sidebar-module-colorpicker-wrapper {
|
||||
padding: 0.341rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-cursorwrapper {
|
||||
padding: 0.341rem 0.136rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-hue {
|
||||
min-height: 13.636rem;
|
||||
min-width: 1.091rem;
|
||||
border-radius: $colorpicker_rounding;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-hue-cursor {
|
||||
background-color: $onBackground;
|
||||
border: 0.136rem solid $onBackground;
|
||||
min-height: 0.136rem;
|
||||
margin-top: -0.136rem;
|
||||
border-radius: $colorpicker_rounding;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-wrapper {
|
||||
padding: 0.341rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness {
|
||||
min-height: 13.636rem;
|
||||
min-width: 13.636rem;
|
||||
border-radius: $colorpicker_rounding;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-cursorwrapper {
|
||||
padding: 0.341rem;
|
||||
margin-top: -0.409rem;
|
||||
margin-left: -0.409rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-cursor {
|
||||
@include full-rounding;
|
||||
border: 0.136rem solid white;
|
||||
min-width: 0.682rem;
|
||||
min-height: 0.682rem;
|
||||
margin-top: -0.409rem;
|
||||
margin-left: -0.409rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-result-area {
|
||||
padding: 0.341rem;
|
||||
}
|
||||
|
||||
.sidebar-module-colorpicker-result-box {
|
||||
border-radius: $colorpicker_rounding;
|
||||
min-width: 2.045rem;
|
||||
min-height: 0.682rem;
|
||||
padding: 0.341rem;
|
||||
}
|
||||
|
||||
.sidebar-chat-apiswitcher {
|
||||
@@ -467,6 +548,7 @@ $onChatgpt: $onPrimary;
|
||||
@include full-rounding;
|
||||
min-width: 2.182rem;
|
||||
min-height: 2.182rem;
|
||||
font-size: 1.406rem;
|
||||
color: $onSurface;
|
||||
}
|
||||
|
||||
@@ -642,10 +724,10 @@ $onChatgpt: $onPrimary;
|
||||
.sidebar-chat-welcome-logo {
|
||||
@include full-rounding;
|
||||
@include element_decel;
|
||||
@include icon-material;
|
||||
min-height: 4.773rem;
|
||||
min-width: 4.773rem;
|
||||
@include icon-material;
|
||||
font-size: 2.727rem;
|
||||
font-size: 3.076rem;
|
||||
background-color: $onBackground;
|
||||
color: $background;
|
||||
}
|
||||
@@ -762,9 +844,7 @@ $waifu_image_overlay_transparency: 0.7;
|
||||
@include full-rounding;
|
||||
min-width: 1.875rem;
|
||||
min-height: 1.875rem;
|
||||
background-color: rgba(0,
|
||||
0,
|
||||
0,
|
||||
background-color: rgba(0, 0, 0,
|
||||
$waifu_image_overlay_transparency ); // Fixed cuz on image
|
||||
color: rgba(255, 255, 255, $waifu_image_overlay_transparency);
|
||||
}
|
||||
@@ -776,4 +856,4 @@ $waifu_image_overlay_transparency: 0.7;
|
||||
|
||||
.sidebar-waifu-image-action:active {
|
||||
background-color: rgba(60, 60, 60, $waifu_image_overlay_transparency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Reset
|
||||
* {
|
||||
all: unset;
|
||||
}
|
||||
// *:not(tooltip) { all: unset; }
|
||||
// * {
|
||||
// all: unset;
|
||||
// }
|
||||
*:not(popover) { all: unset; }
|
||||
|
||||
// Colors
|
||||
@import './material'; // Material colors
|
||||
|
||||
@@ -118,8 +118,8 @@ class ChatGPTService extends Service {
|
||||
_assistantPrompt = true;
|
||||
_messages = [];
|
||||
_cycleModels = true;
|
||||
_temperature = 0.9;
|
||||
_requestCount = 0;
|
||||
_temperature = 0.9;
|
||||
_modelIndex = 0;
|
||||
_key = '';
|
||||
_decoder = new TextDecoder();
|
||||
|
||||
@@ -135,8 +135,8 @@ class GeminiService extends Service {
|
||||
_assistantPrompt = true;
|
||||
_messages = [];
|
||||
_cycleModels = true;
|
||||
_temperature = 0.9;
|
||||
_requestCount = 0;
|
||||
_temperature = 0.9;
|
||||
_modelIndex = 0;
|
||||
_key = '';
|
||||
_decoder = new TextDecoder();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
* {
|
||||
*:not(popover) {
|
||||
all: unset; }
|
||||
|
||||
@keyframes flyin-top {
|
||||
@@ -56,11 +56,11 @@
|
||||
text-shadow: 1px 2px 8px rgba(0, 0, 0, 0.69);
|
||||
margin: 10px; }
|
||||
|
||||
.txt-badonkers {
|
||||
.txt-gigantic {
|
||||
font-family: "Rubik", "Geist", "AR One Sans", "Reddit Sans", "Inter", "Roboto", "Ubuntu", "Noto Sans", sans-serif;
|
||||
font-size: 3rem; }
|
||||
|
||||
.txt-tiddies {
|
||||
.txt-massive {
|
||||
font-family: "Rubik", "Geist", "AR One Sans", "Reddit Sans", "Inter", "Roboto", "Ubuntu", "Noto Sans", sans-serif;
|
||||
font-size: 2.7273rem; }
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
.txt-action {
|
||||
color: #cbc0c1; }
|
||||
|
||||
.txt-thin {
|
||||
font-weight: 300; }
|
||||
|
||||
.txt-semibold {
|
||||
font-weight: 500; }
|
||||
|
||||
@@ -486,6 +489,21 @@ tooltip {
|
||||
color: #d6c1c4;
|
||||
border: 1px solid #d6c1c4; }
|
||||
|
||||
popover {
|
||||
border-top: 1px solid rgba(63, 56, 57, 0.121);
|
||||
border-left: 1px solid rgba(63, 56, 57, 0.121);
|
||||
border-right: 1px solid rgba(49, 42, 43, 0.1105);
|
||||
border-bottom: 1px solid rgba(49, 42, 43, 0.1105);
|
||||
padding: 0.681rem;
|
||||
background: #3d3234;
|
||||
color: #d6c1c4;
|
||||
border-radius: 1.159rem;
|
||||
-gtk-outline-radius: 1.159rem;
|
||||
animation-name: appear;
|
||||
animation-duration: 40ms;
|
||||
animation-timing-function: ease-out;
|
||||
animation-iteration-count: 1; }
|
||||
|
||||
.configtoggle-box {
|
||||
padding: 0.205rem 0.341rem;
|
||||
border: 0.136rem solid transparent; }
|
||||
@@ -809,7 +827,8 @@ tooltip {
|
||||
-gtk-outline-radius: 9999px;
|
||||
transition: 300ms cubic-bezier(0, 0.55, 0.45, 1);
|
||||
min-height: 1.032rem;
|
||||
min-width: 1.032rem; }
|
||||
min-width: 1.032rem;
|
||||
font-size: 1.032rem; }
|
||||
|
||||
.bar-statusicons {
|
||||
border-radius: 9999px;
|
||||
@@ -986,7 +1005,8 @@ tooltip {
|
||||
|
||||
.dock-app-icon {
|
||||
min-width: 3.409rem;
|
||||
min-height: 3.409rem; }
|
||||
min-height: 3.409rem;
|
||||
font-size: 3.409rem; }
|
||||
|
||||
.dock-separator {
|
||||
min-width: 0.068rem;
|
||||
@@ -1332,6 +1352,11 @@ tooltip {
|
||||
background-color: rgba(107, 93, 95, 0.31);
|
||||
font-size: 1.091rem; }
|
||||
|
||||
.osk-key-empty, .osk-key-empty:hover, .osk-key-empty:focus {
|
||||
min-width: 2.5rem;
|
||||
min-height: 2.5rem;
|
||||
background-color: transparent; }
|
||||
|
||||
.sidebar-right {
|
||||
transition: 300ms cubic-bezier(0.1, 1, 0, 1);
|
||||
border-top: 1px solid rgba(171, 160, 161, 0.19);
|
||||
@@ -1709,15 +1734,79 @@ tooltip {
|
||||
border-radius: 1.159rem;
|
||||
-gtk-outline-radius: 1.159rem;
|
||||
padding: 0.341rem;
|
||||
background-color: rgba(34, 27, 28, 0.31); }
|
||||
background-color: rgba(61, 50, 52, 0.45);
|
||||
padding: 0.682rem; }
|
||||
|
||||
.sidebar-module-btn-arrow {
|
||||
border-radius: 9999px;
|
||||
-gtk-outline-radius: 9999px;
|
||||
font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined", "Material Symbols Sharp";
|
||||
background-color: rgba(61, 50, 52, 0.31);
|
||||
background-color: rgba(61, 50, 52, 0.45);
|
||||
min-width: 1.705rem;
|
||||
min-height: 1.705rem; }
|
||||
.sidebar-module-btn-arrow:hover {
|
||||
background-color: rgba(128, 128, 128, 0.3); }
|
||||
|
||||
.sidebar-module-scripts-button {
|
||||
border-radius: 9999px;
|
||||
-gtk-outline-radius: 9999px;
|
||||
font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined", "Material Symbols Sharp";
|
||||
background-color: rgba(61, 50, 52, 0.45);
|
||||
min-width: 1.705rem;
|
||||
min-height: 1.705rem; }
|
||||
.sidebar-module-scripts-button:hover {
|
||||
background-color: rgba(128, 128, 128, 0.3); }
|
||||
.sidebar-module-scripts-button:active {
|
||||
background-color: rgba(128, 128, 128, 0.7); }
|
||||
|
||||
.sidebar-module-colorpicker-wrapper {
|
||||
padding: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-cursorwrapper {
|
||||
padding: 0.341rem 0.136rem; }
|
||||
|
||||
.sidebar-module-colorpicker-hue {
|
||||
min-height: 13.636rem;
|
||||
min-width: 1.091rem;
|
||||
border-radius: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-hue-cursor {
|
||||
background-color: #ecdfe0;
|
||||
border: 0.136rem solid #ecdfe0;
|
||||
min-height: 0.136rem;
|
||||
margin-top: -0.136rem;
|
||||
border-radius: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-wrapper {
|
||||
padding: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness {
|
||||
min-height: 13.636rem;
|
||||
min-width: 13.636rem;
|
||||
border-radius: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-cursorwrapper {
|
||||
padding: 0.341rem;
|
||||
margin-top: -0.409rem;
|
||||
margin-left: -0.409rem; }
|
||||
|
||||
.sidebar-module-colorpicker-saturationandlightness-cursor {
|
||||
border-radius: 9999px;
|
||||
-gtk-outline-radius: 9999px;
|
||||
border: 0.136rem solid white;
|
||||
min-width: 0.682rem;
|
||||
min-height: 0.682rem;
|
||||
margin-top: -0.409rem;
|
||||
margin-left: -0.409rem; }
|
||||
|
||||
.sidebar-module-colorpicker-result-area {
|
||||
padding: 0.341rem; }
|
||||
|
||||
.sidebar-module-colorpicker-result-box {
|
||||
border-radius: 0.341rem;
|
||||
min-width: 2.045rem;
|
||||
min-height: 0.682rem;
|
||||
padding: 0.341rem; }
|
||||
|
||||
.sidebar-chat-apiswitcher {
|
||||
border-radius: 9999px;
|
||||
@@ -1731,6 +1820,7 @@ tooltip {
|
||||
-gtk-outline-radius: 9999px;
|
||||
min-width: 2.182rem;
|
||||
min-height: 2.182rem;
|
||||
font-size: 1.406rem;
|
||||
color: #ecdfe0; }
|
||||
|
||||
.sidebar-chat-apiswitcher-icon-enabled {
|
||||
@@ -1879,10 +1969,10 @@ tooltip {
|
||||
border-radius: 9999px;
|
||||
-gtk-outline-radius: 9999px;
|
||||
transition: 300ms cubic-bezier(0, 0.55, 0.45, 1);
|
||||
font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined", "Material Symbols Sharp";
|
||||
min-height: 4.773rem;
|
||||
min-width: 4.773rem;
|
||||
font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined", "Material Symbols Sharp";
|
||||
font-size: 2.727rem;
|
||||
font-size: 3.076rem;
|
||||
background-color: #ecdfe0;
|
||||
color: #110d0e; }
|
||||
|
||||
@@ -2106,7 +2196,8 @@ tooltip {
|
||||
border-radius: 9999px;
|
||||
-gtk-outline-radius: 9999px;
|
||||
min-width: 3.409rem;
|
||||
min-height: 3.409rem; }
|
||||
min-height: 3.409rem;
|
||||
font-size: 3.409rem; }
|
||||
|
||||
.notif-icon-material {
|
||||
background-color: #5c3f45;
|
||||
|
||||
@@ -154,7 +154,7 @@ export default () => {
|
||||
className: 'spacing-h-10 margin-left-10',
|
||||
children: [
|
||||
BarResource('Swap Usage', 'swap_horiz', `free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`),
|
||||
BarResource('CPU Usage', 'settings_motion_mode', `top -bn1 | grep Cpu | awk '{print $2}'`),
|
||||
BarResource('CPU Usage', 'settings_motion_mode', `top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`),
|
||||
]
|
||||
}),
|
||||
setup: (self) => self.hook(Mpris, label => {
|
||||
|
||||
@@ -13,6 +13,13 @@ const BATTERY_LOW = 20;
|
||||
const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`;
|
||||
Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`);
|
||||
|
||||
let WEATHER_CITY = '';
|
||||
try {
|
||||
WEATHER_CITY = GLib.getenv('AGS_WEATHER_CITY');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
const BatBatteryProgress = () => {
|
||||
const _updateProgress = (circprog) => { // Set circular progress value
|
||||
circprog.css = `font-size: ${Math.abs(Battery.percent)}px;`
|
||||
@@ -155,15 +162,24 @@ const BatteryModule = () => Stack({
|
||||
],
|
||||
setup: (self) => self.poll(900000, async (self) => {
|
||||
const WEATHER_CACHE_PATH = WEATHER_CACHE_FOLDER + '/wttr.in.txt';
|
||||
Utils.execAsync('curl ipinfo.io')
|
||||
const updateWeatherForCity = (city) => execAsync(`curl https://wttr.in/${city}?format=j1`)
|
||||
.then(output => {
|
||||
return JSON.parse(output)['city'].toLowerCase();
|
||||
})
|
||||
.then((city) => execAsync(`curl https://wttr.in/${city}?format=j1`)
|
||||
.then(output => {
|
||||
const weather = JSON.parse(output);
|
||||
Utils.writeFile(JSON.stringify(weather), WEATHER_CACHE_PATH)
|
||||
.catch(print);
|
||||
const weather = JSON.parse(output);
|
||||
Utils.writeFile(JSON.stringify(weather), WEATHER_CACHE_PATH)
|
||||
.catch(print);
|
||||
const weatherCode = weather.current_condition[0].weatherCode;
|
||||
const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
|
||||
const temperature = weather.current_condition[0].temp_C;
|
||||
const feelsLike = weather.current_condition[0].FeelsLikeC;
|
||||
const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
|
||||
self.children[0].label = weatherSymbol;
|
||||
self.children[1].label = `${temperature}℃ • Feels like ${feelsLike}℃`;
|
||||
self.tooltipText = weatherDesc;
|
||||
}).catch((err) => {
|
||||
try { // Read from cache
|
||||
const weather = JSON.parse(
|
||||
Utils.readFile(WEATHER_CACHE_PATH)
|
||||
);
|
||||
const weatherCode = weather.current_condition[0].weatherCode;
|
||||
const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
|
||||
const temperature = weather.current_condition[0].temp_C;
|
||||
@@ -172,23 +188,20 @@ const BatteryModule = () => Stack({
|
||||
self.children[0].label = weatherSymbol;
|
||||
self.children[1].label = `${temperature}℃ • Feels like ${feelsLike}℃`;
|
||||
self.tooltipText = weatherDesc;
|
||||
}).catch((err) => {
|
||||
try { // Read from cache
|
||||
const weather = JSON.parse(
|
||||
Utils.readFile(WEATHER_CACHE_PATH)
|
||||
);
|
||||
const weatherCode = weather.current_condition[0].weatherCode;
|
||||
const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
|
||||
const temperature = weather.current_condition[0].temp_C;
|
||||
const feelsLike = weather.current_condition[0].FeelsLikeC;
|
||||
const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
|
||||
self.children[0].label = weatherSymbol;
|
||||
self.children[1].label = `${temperature}℃ • Feels like ${feelsLike}℃`;
|
||||
self.tooltipText = weatherDesc;
|
||||
} catch (err) {
|
||||
print(err);
|
||||
}
|
||||
}));
|
||||
} catch (err) {
|
||||
print(err);
|
||||
}
|
||||
});
|
||||
if (WEATHER_CITY != '' && WEATHER_CITY != null) {
|
||||
updateWeatherForCity(WEATHER_CITY);
|
||||
}
|
||||
else {
|
||||
Utils.execAsync('curl ipinfo.io')
|
||||
.then(output => {
|
||||
return JSON.parse(output)['city'].toLowerCase();
|
||||
})
|
||||
.then(updateWeatherForCity);
|
||||
}
|
||||
}),
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -10,15 +10,8 @@ const SysTrayItem = (item) => Button({
|
||||
className: 'bar-systray-item',
|
||||
child: Icon({
|
||||
hpack: 'center',
|
||||
setup: (self) => {
|
||||
self.hook(item, (self) => self.icon = item.icon);
|
||||
Utils.timeout(1, () => {
|
||||
const styleContext = self.get_parent().get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1); // im too lazy to add another box lol
|
||||
})
|
||||
},
|
||||
icon: item.icon,
|
||||
setup: (self) => self.hook(item, (self) => self.icon = item.icon),
|
||||
}),
|
||||
setup: (self) => self
|
||||
.hook(item, (self) => self.tooltipMarkup = item['tooltip-markup'])
|
||||
|
||||
@@ -21,6 +21,7 @@ const WorkspaceContents = (count = 10) => {
|
||||
attribute: {
|
||||
initialized: false,
|
||||
workspaceMask: 0,
|
||||
workspaceGroup: 0,
|
||||
updateMask: (self) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * NUM_OF_WORKSPACES_SHOWN;
|
||||
// if (self.attribute.initialized) return; // We only need this to run once
|
||||
@@ -46,6 +47,12 @@ const WorkspaceContents = (count = 10) => {
|
||||
setup: (area) => area
|
||||
.hook(Hyprland.active.workspace, (self) => {
|
||||
self.setCss(`font-size: ${(Hyprland.active.workspace.id - 1) % count + 1}px;`);
|
||||
const previousGroup = self.attribute.workspaceGroup;
|
||||
const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / count);
|
||||
if (currentGroup !== previousGroup) {
|
||||
self.attribute.updateMask(self);
|
||||
self.attribute.workspaceGroup = currentGroup;
|
||||
}
|
||||
})
|
||||
.hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces')
|
||||
.on('draw', Lang.bind(area, (area, cr) => {
|
||||
|
||||
@@ -59,12 +59,6 @@ const AppButton = ({ icon, ...rest }) => Widget.Revealer({
|
||||
className: 'dock-app-icon',
|
||||
child: Widget.Icon({
|
||||
icon: icon,
|
||||
setup: (self) => Utils.timeout(1, () => {
|
||||
const styleContext = self.get_parent().get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1);
|
||||
})
|
||||
}),
|
||||
}),
|
||||
overlays: [Widget.Box({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import Indicator from '../../services/indicator.js';
|
||||
import IndicatorValues from './indicatorvalues.js';
|
||||
// import MusicControls from './musiccontrols.js';
|
||||
import MusicControls from './musiccontrols.js';
|
||||
import ColorScheme from './colorscheme.js';
|
||||
import NotificationPopups from './notificationpopups.js';
|
||||
|
||||
@@ -23,7 +23,7 @@ export default (monitor = 0) => Widget.Window({
|
||||
css: 'min-height: 2px;',
|
||||
children: [
|
||||
IndicatorValues(),
|
||||
// MusicControls(),
|
||||
MusicControls(),
|
||||
NotificationPopups(),
|
||||
ColorScheme(),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { Gio, GLib } = imports.gi;
|
||||
const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
@@ -27,8 +27,9 @@ var lastCoverPath = '';
|
||||
|
||||
function isRealPlayer(player) {
|
||||
return (
|
||||
!player.busName.startsWith('org.mpris.MediaPlayer2.firefox') &&
|
||||
!player.busName.startsWith('org.mpris.MediaPlayer2.playerctld')
|
||||
!player.busName.startsWith('org.mpris.MediaPlayer2.firefox') && // Firefox mpris dbus is useless
|
||||
!player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') && // Doesn't have cover art
|
||||
!player.busName.endsWith('.mpd') // Non-instance mpd bus
|
||||
);
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ function getTrackfont(player) {
|
||||
return DEFAULT_MUSIC_FONT;
|
||||
}
|
||||
function trimTrackTitle(title) {
|
||||
if(!title) return '';
|
||||
if (!title) return '';
|
||||
const cleanRegexes = [
|
||||
/【[^】]*】/, // Touhou n weeb stuff
|
||||
/\[FREE DOWNLOAD\]/, // F-777
|
||||
@@ -80,7 +81,7 @@ function trimTrackTitle(title) {
|
||||
|
||||
const TrackProgress = ({ player, ...rest }) => {
|
||||
const _updateProgress = (circprog) => {
|
||||
const player = Mpris.getPlayer();
|
||||
// const player = Mpris.getPlayer();
|
||||
if (!player) return;
|
||||
// Set circular progress (see definition of AnimatedCircProg for explanation)
|
||||
circprog.css = `font-size: ${Math.max(player.position / player.length * 100, 0)}px;`
|
||||
@@ -122,69 +123,123 @@ const TrackArtists = ({ player, ...rest }) => Label({
|
||||
}, 'notify::track-artists'),
|
||||
})
|
||||
|
||||
const CoverArt = ({ player, ...rest }) => Box({
|
||||
...rest,
|
||||
className: 'osd-music-cover',
|
||||
children: [
|
||||
Widget.Overlay({
|
||||
child: Box({ // Fallback
|
||||
className: 'osd-music-cover-fallback',
|
||||
homogeneous: true,
|
||||
children: [Label({
|
||||
className: 'icon-material txt-hugeass',
|
||||
label: 'music_note',
|
||||
})]
|
||||
}),
|
||||
overlays: [ // Real
|
||||
Box({
|
||||
attribute: {
|
||||
'updateCover': (self) => {
|
||||
const player = Mpris.getPlayer();
|
||||
const CoverArt = ({ player, ...rest }) => {
|
||||
const fallbackCoverArt = Box({ // Fallback
|
||||
className: 'osd-music-cover-fallback',
|
||||
homogeneous: true,
|
||||
children: [Label({
|
||||
className: 'icon-material txt-gigantic txt-thin',
|
||||
label: 'music_note',
|
||||
})]
|
||||
});
|
||||
const coverArtDrawingArea = Widget.DrawingArea({ className: 'osd-music-cover-art' });
|
||||
const coverArtDrawingAreaStyleContext = coverArtDrawingArea.get_style_context();
|
||||
const realCoverArt = Box({
|
||||
className: 'osd-music-cover-art',
|
||||
homogeneous: true,
|
||||
children: [coverArtDrawingArea],
|
||||
attribute: {
|
||||
'pixbuf': null,
|
||||
'showImage': (self, imagePath) => {
|
||||
const borderRadius = coverArtDrawingAreaStyleContext.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||
const frameHeight = coverArtDrawingAreaStyleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
const frameWidth = coverArtDrawingAreaStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
let imageHeight = frameHeight;
|
||||
let imageWidth = frameWidth;
|
||||
// Get image dimensions
|
||||
execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath])
|
||||
.then((output) => {
|
||||
const imageDimensions = JSON.parse(output);
|
||||
const imageAspectRatio = imageDimensions.w / imageDimensions.h;
|
||||
const displayedAspectRatio = imageWidth / imageHeight;
|
||||
if (imageAspectRatio >= displayedAspectRatio) {
|
||||
imageWidth = imageHeight * imageAspectRatio;
|
||||
} else {
|
||||
imageHeight = imageWidth / imageAspectRatio;
|
||||
}
|
||||
// Real stuff
|
||||
// TODO: fix memory leak(?)
|
||||
// if (self.attribute.pixbuf) {
|
||||
// self.attribute.pixbuf.unref();
|
||||
// self.attribute.pixbuf = null;
|
||||
// }
|
||||
self.attribute.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(imagePath, imageWidth, imageHeight);
|
||||
|
||||
// Player closed
|
||||
// Note that cover path still remains, so we're checking title
|
||||
if (!player || player.trackTitle == "") {
|
||||
self.css = `background-image: none;`;
|
||||
App.applyCss(`${App.configDir}/style.css`);
|
||||
return;
|
||||
}
|
||||
coverArtDrawingArea.set_size_request(frameWidth, frameHeight);
|
||||
coverArtDrawingArea.connect("draw", (widget, cr) => {
|
||||
// Clip a rounded rectangle area
|
||||
cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI);
|
||||
cr.arc(frameWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI);
|
||||
cr.arc(frameWidth - borderRadius, frameHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI);
|
||||
cr.arc(borderRadius, frameHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI);
|
||||
cr.closePath();
|
||||
cr.clip();
|
||||
// Paint image as bg, centered
|
||||
Gdk.cairo_set_source_pixbuf(cr, self.attribute.pixbuf,
|
||||
frameWidth / 2 - imageWidth / 2,
|
||||
frameHeight / 2 - imageHeight / 2
|
||||
);
|
||||
cr.paint();
|
||||
});
|
||||
}).catch(print)
|
||||
},
|
||||
'updateCover': (self) => {
|
||||
// const player = Mpris.getPlayer(); // Maybe no need to re-get player.. can't remember why I had this
|
||||
// Player closed
|
||||
// Note that cover path still remains, so we're checking title
|
||||
if (!player || player.trackTitle == "") {
|
||||
self.css = `background-image: none;`;
|
||||
App.applyCss(`${App.configDir}/style.css`);
|
||||
return;
|
||||
}
|
||||
|
||||
const coverPath = player.coverPath;
|
||||
const stylePath = `${player.coverPath}${lightDark}${COVER_COLORSCHEME_SUFFIX}`;
|
||||
if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete
|
||||
self.css = `background-image: url('${coverPath}');`;
|
||||
}
|
||||
lastCoverPath = player.coverPath;
|
||||
const coverPath = player.coverPath;
|
||||
const stylePath = `${player.coverPath}${lightDark}${COVER_COLORSCHEME_SUFFIX}`;
|
||||
if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete
|
||||
// Utils.timeout(200, () => { self.css = `background-image: url('${coverPath}');`; });
|
||||
Utils.timeout(200, () => self.attribute.showImage(self, coverPath));
|
||||
}
|
||||
lastCoverPath = player.coverPath;
|
||||
|
||||
// If a colorscheme has already been generated, skip generation
|
||||
if (fileExists(stylePath)) {
|
||||
self.css = `background-image: url('${coverPath}');`;
|
||||
App.applyCss(stylePath);
|
||||
return;
|
||||
}
|
||||
// If a colorscheme has already been generated, skip generation
|
||||
if (fileExists(stylePath)) {
|
||||
// Utils.timeout(200, () => { self.css = `background-image: url('${coverPath}');`; });
|
||||
self.attribute.showImage(self, coverPath)
|
||||
App.applyCss(stylePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate colors
|
||||
execAsync(['bash', '-c',
|
||||
`${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${lightDark}`])
|
||||
.then(() => {
|
||||
exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`)
|
||||
exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`);
|
||||
exec(`sassc ${App.configDir}/scss/_music.scss ${stylePath}`);
|
||||
self.css = `background-image: url('${coverPath}');`;
|
||||
App.applyCss(`${stylePath}`);
|
||||
})
|
||||
.catch(print);
|
||||
},
|
||||
},
|
||||
className: 'osd-music-cover-art',
|
||||
$: [
|
||||
[player, (self) => self.attribute.updateCover(self), 'notify::cover-path']
|
||||
],
|
||||
})
|
||||
]
|
||||
})
|
||||
],
|
||||
})
|
||||
// Generate colors
|
||||
execAsync(['bash', '-c',
|
||||
`${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' > ${App.configDir}/scss/_musicmaterial.scss ${lightDark}`])
|
||||
.then(() => {
|
||||
exec(`wal -i "${player.coverPath}" -n -t -s -e -q ${lightDark}`)
|
||||
exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${App.configDir}/scss/_musicwal.scss`);
|
||||
exec(`sassc ${App.configDir}/scss/_music.scss ${stylePath}`);
|
||||
// self.css = `background-image: url('${coverPath}');`;
|
||||
Utils.timeout(200, () => self.attribute.showImage(self, coverPath));
|
||||
App.applyCss(`${stylePath}`);
|
||||
})
|
||||
.catch(print);
|
||||
},
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(player, (self) => {
|
||||
self.attribute.updateCover(self);
|
||||
}, 'notify::cover-path')
|
||||
,
|
||||
});
|
||||
return Box({
|
||||
...rest,
|
||||
className: 'osd-music-cover',
|
||||
children: [
|
||||
Widget.Overlay({
|
||||
child: fallbackCoverArt,
|
||||
overlays: [realCoverArt],
|
||||
})
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
const TrackControls = ({ player, ...rest }) => Widget.Revealer({
|
||||
revealChild: false,
|
||||
@@ -197,7 +252,7 @@ const TrackControls = ({ player, ...rest }) => Widget.Revealer({
|
||||
children: [
|
||||
Button({
|
||||
className: 'osd-music-controlbtn',
|
||||
onClicked: () => execAsync('playerctl previous').catch(print),
|
||||
onClicked: () => player.previous(),
|
||||
child: Label({
|
||||
className: 'icon-material osd-music-controlbtn-txt',
|
||||
label: 'skip_previous',
|
||||
@@ -205,9 +260,7 @@ const TrackControls = ({ player, ...rest }) => Widget.Revealer({
|
||||
}),
|
||||
Button({
|
||||
className: 'osd-music-controlbtn',
|
||||
onClicked: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"`'])
|
||||
.catch(print)
|
||||
,
|
||||
onClicked: () => player.next(),
|
||||
child: Label({
|
||||
className: 'icon-material osd-music-controlbtn-txt',
|
||||
label: 'skip_next',
|
||||
@@ -215,8 +268,8 @@ const TrackControls = ({ player, ...rest }) => Widget.Revealer({
|
||||
}),
|
||||
],
|
||||
}),
|
||||
setup: (self) => szelf.hook(Mpris, (self) => {
|
||||
const player = Mpris.getPlayer();
|
||||
setup: (self) => self.hook(Mpris, (self) => {
|
||||
// const player = Mpris.getPlayer();
|
||||
if (!player)
|
||||
self.revealChild = false;
|
||||
else
|
||||
@@ -264,7 +317,7 @@ const TrackTime = ({ player, ...rest }) => {
|
||||
children: [
|
||||
Label({
|
||||
setup: (self) => self.poll(1000, (self) => {
|
||||
const player = Mpris.getPlayer();
|
||||
// const player = Mpris.getPlayer();
|
||||
if (!player) return;
|
||||
self.label = lengthStr(player.position);
|
||||
}),
|
||||
@@ -272,7 +325,7 @@ const TrackTime = ({ player, ...rest }) => {
|
||||
Label({ label: '/' }),
|
||||
Label({
|
||||
setup: (self) => self.hook(Mpris, (self) => {
|
||||
const player = Mpris.getPlayer();
|
||||
// const player = Mpris.getPlayer();
|
||||
if (!player) return;
|
||||
self.label = lengthStr(player.length);
|
||||
}),
|
||||
@@ -296,7 +349,7 @@ const PlayState = ({ player }) => {
|
||||
overlays: [
|
||||
Widget.Button({
|
||||
className: 'osd-music-playstate-btn',
|
||||
onClicked: () => execAsync('playerctl play-pause').catch(print),
|
||||
onClicked: () => player.playPause(),
|
||||
child: Widget.Label({
|
||||
justification: 'center',
|
||||
hpack: 'fill',
|
||||
@@ -313,7 +366,7 @@ const PlayState = ({ player }) => {
|
||||
}
|
||||
|
||||
const MusicControlsWidget = (player) => Box({
|
||||
className: 'osd-music spacing-h-20',
|
||||
className: 'osd-music spacing-h-20 test',
|
||||
children: [
|
||||
CoverArt({ player: player, vpack: 'center' }),
|
||||
Box({
|
||||
@@ -344,35 +397,62 @@ const MusicControlsWidget = (player) => Box({
|
||||
]
|
||||
})
|
||||
|
||||
export default () => MarginRevealer({
|
||||
export default () => Revealer({
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 150,
|
||||
revealChild: false,
|
||||
showClass: 'osd-show',
|
||||
hideClass: 'osd-hide',
|
||||
child: Box({
|
||||
setup: (self) => self.hook(Mpris, box => {
|
||||
let foundPlayer = false;
|
||||
|
||||
box.children.forEach(child => {
|
||||
child.destroy();
|
||||
child = null;
|
||||
});
|
||||
Mpris.players.forEach((player, i) => {
|
||||
if (isRealPlayer(player)) {
|
||||
foundPlayer = true;
|
||||
box.children = [MusicControlsWidget(player)];
|
||||
const newInstance = MusicControlsWidget(player);
|
||||
box.add(newInstance);
|
||||
}
|
||||
});
|
||||
|
||||
if (!foundPlayer) {
|
||||
const children = box.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const child = children[i];
|
||||
child.destroy();
|
||||
child = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}, 'notify::players'),
|
||||
}),
|
||||
setup: (self) => self.hook(showMusicControls, (revealer) => {
|
||||
if (showMusicControls.value) revealer.attribute.show();
|
||||
else revealer.attribute.hide();
|
||||
revealer.revealChild = showMusicControls.value;
|
||||
}),
|
||||
})
|
||||
|
||||
// export default () => MarginRevealer({
|
||||
// transition: 'slide_down',
|
||||
// revealChild: false,
|
||||
// showClass: 'osd-show',
|
||||
// hideClass: 'osd-hide',
|
||||
// child: Box({
|
||||
// setup: (self) => self.hook(Mpris, box => {
|
||||
// let foundPlayer = false;
|
||||
// Mpris.players.forEach((player, i) => {
|
||||
// if (isRealPlayer(player)) {
|
||||
// foundPlayer = true;
|
||||
// box.children.forEach(child => {
|
||||
// child.destroy();
|
||||
// child = null;
|
||||
// });
|
||||
// const newInstance = MusicControlsWidget(player);
|
||||
// box.children = [newInstance];
|
||||
// }
|
||||
// });
|
||||
|
||||
// if (!foundPlayer) {
|
||||
// const children = box.get_children();
|
||||
// for (let i = 0; i < children.length; i++) {
|
||||
// const child = children[i];
|
||||
// child.destroy();
|
||||
// child = null;
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// }, 'notify::players'),
|
||||
// }),
|
||||
// setup: (self) => self.hook(showMusicControls, (revealer) => {
|
||||
// if (showMusicControls.value) revealer.attribute.show();
|
||||
// else revealer.attribute.hide();
|
||||
// }),
|
||||
// })
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const { Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
const { Box, EventBox, Button, Revealer } = Widget;
|
||||
const { execAsync, exec } = Utils;
|
||||
const { execAsync } = Utils;
|
||||
import { MaterialIcon } from '../../lib/materialicon.js';
|
||||
import { separatorLine } from '../../lib/separator.js';
|
||||
import { defaultOskLayout, oskLayouts } from '../../data/keyboardlayouts.js';
|
||||
@@ -21,6 +20,18 @@ function releaseAllKeys() {
|
||||
.then(console.log('[OSK] Released all keys'))
|
||||
.catch(print);
|
||||
}
|
||||
class ShiftMode {
|
||||
static Off = new ShiftMode('Off');
|
||||
static Normal = new ShiftMode('Normal');
|
||||
static Locked = new ShiftMode('Locked');
|
||||
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
toString() {
|
||||
return `ShiftMode.${this.name}`;
|
||||
}
|
||||
}
|
||||
var modsPressed = false;
|
||||
|
||||
const topDecor = Box({
|
||||
@@ -76,6 +87,10 @@ const keyboardControls = Box({
|
||||
]
|
||||
})
|
||||
|
||||
var shiftMode = ShiftMode.Off;
|
||||
var shiftButton;
|
||||
var rightShiftButton;
|
||||
var allButtons = [];
|
||||
const keyboardItself = (kbJson) => {
|
||||
return Box({
|
||||
vertical: true,
|
||||
@@ -88,14 +103,32 @@ const keyboardItself = (kbJson) => {
|
||||
className: `osk-key osk-key-${key.shape}`,
|
||||
hexpand: ["space", "expand"].includes(key.shape),
|
||||
label: key.label,
|
||||
attribute:
|
||||
{key: key},
|
||||
setup: (button) => {
|
||||
let pressed = false;
|
||||
allButtons = allButtons.concat(button);
|
||||
if (key.keytype == "normal") {
|
||||
button.connect('pressed', () => { // mouse down
|
||||
execAsync(`ydotool key ${key.keycode}:1`);
|
||||
});
|
||||
button.connect('clicked', () => { // release
|
||||
execAsync(`ydotool key ${key.keycode}:0`);
|
||||
|
||||
if (shiftMode == ShiftMode.Normal) {
|
||||
shiftMode = ShiftMode.Off;
|
||||
if (typeof shiftButton !== 'undefined') {
|
||||
execAsync(`ydotool key 42:0`);
|
||||
shiftButton.toggleClassName('osk-key-active', false);
|
||||
}
|
||||
if (typeof rightShiftButton !== 'undefined') {
|
||||
execAsync(`ydotool key 54:0`);
|
||||
rightShiftButton.toggleClassName('osk-key-active', false);
|
||||
}
|
||||
allButtons.forEach(button => {
|
||||
if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.label;
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (key.keytype == "modkey") {
|
||||
@@ -104,14 +137,53 @@ const keyboardItself = (kbJson) => {
|
||||
execAsync(`ydotool key ${key.keycode}:0`);
|
||||
button.toggleClassName('osk-key-active', false);
|
||||
pressed = false;
|
||||
if (key.keycode == 100) { // Alt Gr button
|
||||
allButtons.forEach(button => { if (typeof button.attribute.key.labelAlt !== 'undefined') button.label = button.attribute.key.label; });
|
||||
}
|
||||
}
|
||||
else {
|
||||
execAsync(`ydotool key ${key.keycode}:1`);
|
||||
button.toggleClassName('osk-key-active', true);
|
||||
pressed = true;
|
||||
if (!(key.keycode == 42 || key.keycode == 54)) pressed = true;
|
||||
else switch (shiftMode.name) { // This toggles the shift button state
|
||||
case "Off": {
|
||||
shiftMode = ShiftMode.Normal;
|
||||
allButtons.forEach(button => { if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.labelShift; })
|
||||
if (typeof shiftButton !== 'undefined') {
|
||||
shiftButton.toggleClassName('osk-key-active', true);
|
||||
}
|
||||
if (typeof rightShiftButton !== 'undefined') {
|
||||
rightShiftButton.toggleClassName('osk-key-active', true);
|
||||
}
|
||||
} break;
|
||||
case "Normal": {
|
||||
shiftMode = ShiftMode.Locked;
|
||||
if (typeof shiftButton !== 'undefined') shiftButton.label = key.labelCaps;
|
||||
if (typeof rightShiftButton !== 'undefined') rightShiftButton.label = key.labelCaps;
|
||||
} break;
|
||||
case "Locked": {
|
||||
shiftMode = ShiftMode.Off;
|
||||
if (typeof shiftButton !== 'undefined') {
|
||||
shiftButton.label = key.label;
|
||||
shiftButton.toggleClassName('osk-key-active', false);
|
||||
}
|
||||
if (typeof rightShiftButton !== 'undefined') {
|
||||
rightShiftButton.label = key.label;
|
||||
rightShiftButton.toggleClassName('osk-key-active', false);
|
||||
}
|
||||
execAsync(`ydotool key ${key.keycode}:0`);
|
||||
|
||||
allButtons.forEach(button => { if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.label; }
|
||||
)};
|
||||
}
|
||||
if (key.keycode == 100) { // Alt Gr button
|
||||
allButtons.forEach(button => { if (typeof button.attribute.key.labelAlt !== 'undefined') button.label = button.attribute.key.labelAlt; });
|
||||
}
|
||||
modsPressed = true;
|
||||
}
|
||||
});
|
||||
if (key.keycode == 42) shiftButton = button;
|
||||
else if (key.keycode == 54) rightShiftButton = button;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// - Active ws hook optimization: only update when moving to next group
|
||||
//
|
||||
const { Gdk, Gtk } = imports.gi;
|
||||
const { Gravity } = imports.gi.Gdk;
|
||||
import { SCREEN_HEIGHT, SCREEN_WIDTH } from '../../imports.js';
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
@@ -48,260 +49,398 @@ function substitute(str) {
|
||||
if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, '-'); // Turn into kebab-case
|
||||
return str;
|
||||
}
|
||||
export default () => {
|
||||
const clientMap = new Map();
|
||||
let workspaceGroup = 0;
|
||||
const ContextMenuWorkspaceArray = ({ label, actionFunc, thisWorkspace }) => Widget.MenuItem({
|
||||
label: `${label}`,
|
||||
setup: (menuItem) => {
|
||||
let submenu = new Gtk.Menu();
|
||||
submenu.className = 'menu';
|
||||
|
||||
const ContextMenuWorkspaceArray = ({ label, actionFunc, thisWorkspace }) => Widget.MenuItem({
|
||||
label: `${label}`,
|
||||
setup: (menuItem) => {
|
||||
let submenu = new Gtk.Menu();
|
||||
submenu.className = 'menu';
|
||||
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
const startWorkspace = offset + 1;
|
||||
const endWorkspace = startWorkspace + NUM_OF_WORKSPACES_SHOWN - 1;
|
||||
for (let i = startWorkspace; i <= endWorkspace; i++) {
|
||||
let button = new Gtk.MenuItem({
|
||||
label: `Workspace ${i}`
|
||||
});
|
||||
button.connect("activate", () => {
|
||||
// execAsync([`${onClickBinary}`, `${thisWorkspace}`, `${i}`]).catch(print);
|
||||
actionFunc(thisWorkspace, i);
|
||||
});
|
||||
submenu.append(button);
|
||||
}
|
||||
menuItem.set_reserve_indicator(true);
|
||||
menuItem.set_submenu(submenu);
|
||||
}
|
||||
})
|
||||
|
||||
const Window = ({ address, at: [x, y], size: [w, h], workspace: { id, name }, class: c, title, xwayland }) => {
|
||||
const revealInfoCondition = (Math.min(w, h) * OVERVIEW_SCALE > 70);
|
||||
if (w <= 0 || h <= 0 || (c === '' && title === '')) return null;
|
||||
if (x + w <= 0) x += (Math.floor(x / SCREEN_WIDTH) * SCREEN_WIDTH);
|
||||
else if (x < 0) { x = 0; w = x + w; }
|
||||
if (y + h <= 0) x += (Math.floor(y / SCREEN_HEIGHT) * SCREEN_HEIGHT);
|
||||
else if (y < 0) { y = 0; h = y + h; }
|
||||
|
||||
if (x >= SCREEN_WIDTH) x %= SCREEN_WIDTH;
|
||||
else if (x + w > SCREEN_WIDTH) w = SCREEN_WIDTH - x;
|
||||
if (y >= SCREEN_HEIGHT) y %= SCREEN_HEIGHT;
|
||||
else if (y + h > SCREEN_HEIGHT) h = SCREEN_HEIGHT - y;
|
||||
|
||||
// title = truncateTitle(title);
|
||||
return Widget.Button({
|
||||
attribute: { x, y },
|
||||
className: 'overview-tasks-window',
|
||||
hpack: 'center',
|
||||
vpack: 'center',
|
||||
onClicked: () => {
|
||||
Hyprland.sendMessage(`dispatch focuswindow address:${address}`);
|
||||
App.closeWindow('overview');
|
||||
},
|
||||
onMiddleClickRelease: () => Hyprland.sendMessage(`dispatch closewindow address:${address}`),
|
||||
onSecondaryClick: (button) => {
|
||||
button.toggleClassName('overview-tasks-window-selected', true);
|
||||
const menu = Widget.Menu({
|
||||
className: 'menu',
|
||||
children: [
|
||||
Widget.MenuItem({
|
||||
child: Widget.Label({
|
||||
xalign: 0,
|
||||
label: "Close (Middle-click)",
|
||||
}),
|
||||
onActivate: () => Hyprland.sendMessage(`dispatch closewindow address:${address}`),
|
||||
}),
|
||||
ContextMenuWorkspaceArray({
|
||||
label: "Dump windows to workspace",
|
||||
actionFunc: dumpToWorkspace,
|
||||
thisWorkspace: Number(id)
|
||||
}),
|
||||
ContextMenuWorkspaceArray({
|
||||
label: "Swap windows with workspace",
|
||||
actionFunc: swapWorkspace,
|
||||
thisWorkspace: Number(id)
|
||||
}),
|
||||
],
|
||||
});
|
||||
menu.connect("deactivate", () => {
|
||||
button.toggleClassName('overview-tasks-window-selected', false);
|
||||
})
|
||||
menu.connect("selection-done", () => {
|
||||
button.toggleClassName('overview-tasks-window-selected', false);
|
||||
})
|
||||
menu.popup_at_pointer(null); // Show the menu at the pointer's position
|
||||
},
|
||||
child: Widget.Box({
|
||||
css: `
|
||||
min-width: ${Math.max(w * OVERVIEW_SCALE - 4, 1)}px;
|
||||
min-height: ${Math.max(h * OVERVIEW_SCALE - 4, 1)}px;
|
||||
`,
|
||||
homogeneous: true,
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
Widget.Icon({
|
||||
icon: substitute(c),
|
||||
size: Math.min(w, h) * OVERVIEW_SCALE / 2.5,
|
||||
}),
|
||||
// TODO: Add xwayland tag instead of just having italics
|
||||
Widget.Revealer({
|
||||
transition: 'slide_down',
|
||||
revealChild: revealInfoCondition,
|
||||
child: Widget.Label({
|
||||
truncate: 'end',
|
||||
className: `${xwayland ? 'txt txt-italic' : 'txt'}`,
|
||||
css: `
|
||||
font-size: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 14.6}px;
|
||||
margin: 0px ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 10}px;
|
||||
`,
|
||||
// If the title is too short, include the class
|
||||
label: (title.length <= 1 ? `${c}: ${title}` : title),
|
||||
})
|
||||
})
|
||||
]
|
||||
})
|
||||
}),
|
||||
tooltipText: `${c}: ${title}`,
|
||||
setup: (button) => {
|
||||
setupCursorHoverGrab(button);
|
||||
|
||||
button.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.MOVE);
|
||||
button.drag_source_set_icon_name(substitute(c));
|
||||
// button.drag_source_set_icon_gicon(icon);
|
||||
|
||||
button.connect('drag-begin', (button) => { // On drag start, add the dragging class
|
||||
button.toggleClassName('overview-tasks-window-dragging', true);
|
||||
});
|
||||
button.connect('drag-data-get', (_w, _c, data) => { // On drag finish, give address
|
||||
data.set_text(address, address.length);
|
||||
button.toggleClassName('overview-tasks-window-dragging', false);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const Workspace = (index) => {
|
||||
const fixed = Gtk.Fixed.new();
|
||||
// const clientMap = new Map();
|
||||
const WorkspaceNumber = (index) => Widget.Label({
|
||||
className: 'overview-tasks-workspace-number',
|
||||
label: `${index}`,
|
||||
css: `
|
||||
margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE * OVERVIEW_WS_NUM_MARGIN_SCALE}px;
|
||||
font-size: ${SCREEN_HEIGHT * OVERVIEW_SCALE * OVERVIEW_WS_NUM_SCALE}px;
|
||||
`,
|
||||
})
|
||||
const widget = Widget.Box({
|
||||
className: 'overview-tasks-workspace',
|
||||
vpack: 'center',
|
||||
css: `
|
||||
min-width: ${SCREEN_WIDTH * OVERVIEW_SCALE}px;
|
||||
min-height: ${SCREEN_HEIGHT * OVERVIEW_SCALE}px;
|
||||
`,
|
||||
children: [Widget.EventBox({
|
||||
hexpand: true,
|
||||
vexpand: true,
|
||||
onPrimaryClick: () => {
|
||||
Hyprland.sendMessage(`dispatch workspace ${index}`)
|
||||
App.closeWindow('overview');
|
||||
},
|
||||
setup: (eventbox) => {
|
||||
eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
|
||||
eventbox.connect('drag-data-received', (_w, _c, _x, _y, data) => {
|
||||
Hyprland.sendMessage(`dispatch movetoworkspacesilent ${index},address:${data.get_text()}`)
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
const startWorkspace = offset + 1;
|
||||
const endWorkspace = startWorkspace + NUM_OF_WORKSPACES_SHOWN - 1;
|
||||
for (let i = startWorkspace; i <= endWorkspace; i++) {
|
||||
let button = new Gtk.MenuItem({
|
||||
label: `Workspace ${i}`
|
||||
});
|
||||
button.connect("activate", () => {
|
||||
// execAsync([`${onClickBinary}`, `${thisWorkspace}`, `${i}`]).catch(print);
|
||||
actionFunc(thisWorkspace, i);
|
||||
overviewTick.setValue(!overviewTick.value);
|
||||
});
|
||||
},
|
||||
child: fixed,
|
||||
})],
|
||||
});
|
||||
widget.clear = () => {
|
||||
fixed.get_children().forEach(ch => ch.destroy());
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
fixed.put(WorkspaceNumber(offset + index), 0, 0);
|
||||
}
|
||||
widget.set = (clientJson) => {
|
||||
// if(clientMap.get(clientJson.address)) clientMap.get(clientJson.address).destroy();
|
||||
const newWindow = Window(clientJson);
|
||||
if (newWindow === null) return;
|
||||
// clientMap.set(clientJson.address, newWindow);
|
||||
fixed.put(newWindow,
|
||||
Math.max(0, newWindow.attribute.x * OVERVIEW_SCALE),
|
||||
Math.max(0, newWindow.attribute.y * OVERVIEW_SCALE)
|
||||
);
|
||||
};
|
||||
// widget.unset = (clientAddress) => {
|
||||
// if(clientMap.get(clientAddress)) {
|
||||
// clientMap.get(clientAddress).destroy();
|
||||
// clientMap.delete(clientAddress);
|
||||
// }
|
||||
// };
|
||||
widget.show = () => {
|
||||
fixed.show_all();
|
||||
}
|
||||
return widget;
|
||||
};
|
||||
|
||||
const arr = (s, n) => {
|
||||
const array = [];
|
||||
for (let i = 0; i < n; i++)
|
||||
array.push(s + i);
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
const OverviewRow = ({ startWorkspace, workspaces, windowName = 'overview' }) => Widget.Box({
|
||||
children: arr(startWorkspace, workspaces).map(Workspace),
|
||||
attribute: {
|
||||
update: (box) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
if (!App.getWindow(windowName).visible) return;
|
||||
execAsync('hyprctl -j clients').then(clients => {
|
||||
const allClients = JSON.parse(clients);
|
||||
const kids = box.get_children();
|
||||
kids.forEach(kid => kid.clear());
|
||||
for (let i = 0; i < allClients.length; i++) {
|
||||
const client = allClients[i];
|
||||
if (offset + startWorkspace <= client.workspace.id &&
|
||||
client.workspace.id <= offset + startWorkspace + workspaces) {
|
||||
kids[client.workspace.id - (offset + startWorkspace)]
|
||||
?.set(client);
|
||||
}
|
||||
}
|
||||
kids.forEach(kid => kid.show());
|
||||
|
||||
}).catch(print);
|
||||
submenu.append(button);
|
||||
}
|
||||
menuItem.set_reserve_indicator(true);
|
||||
menuItem.set_submenu(submenu);
|
||||
}
|
||||
},
|
||||
setup: (box) => box
|
||||
.hook(overviewTick, (box) => box.attribute.update(box))
|
||||
.hook(Hyprland, (box, clientAddress) => {
|
||||
box.attribute.update(box)
|
||||
}, 'client-removed')
|
||||
.hook(Hyprland, (box, clientAddress) => {
|
||||
box.attribute.update(box);
|
||||
}, 'client-added')
|
||||
.hook(Hyprland.active.workspace, (box) => box.attribute.update(box))
|
||||
.hook(App, (box, name, visible) => { // Update on open
|
||||
if (name == 'overview' && visible) box.attribute.update(box);
|
||||
})
|
||||
|
||||
const Window = ({ address, at: [x, y], size: [w, h], workspace: { id, name }, class: c, title, xwayland }, screenCoords) => {
|
||||
const revealInfoCondition = (Math.min(w, h) * OVERVIEW_SCALE > 70);
|
||||
if (w <= 0 || h <= 0 || (c === '' && title === '')) return null;
|
||||
// Non-primary monitors
|
||||
if (screenCoords.x != 0) x -= screenCoords.x;
|
||||
if (screenCoords.y != 0) y -= screenCoords.y;
|
||||
// Other offscreen adjustments
|
||||
if (x + w <= 0) x += (Math.floor(x / SCREEN_WIDTH) * SCREEN_WIDTH);
|
||||
else if (x < 0) { w = x + w; x = 0; }
|
||||
if (y + h <= 0) x += (Math.floor(y / SCREEN_HEIGHT) * SCREEN_HEIGHT);
|
||||
else if (y < 0) { h = y + h; y = 0; }
|
||||
// Truncate if offscreen
|
||||
if (x + w > SCREEN_WIDTH) w = SCREEN_WIDTH - x;
|
||||
if (y + h > SCREEN_HEIGHT) h = SCREEN_HEIGHT - y;
|
||||
|
||||
const appIcon = Widget.Icon({
|
||||
icon: substitute(c),
|
||||
size: Math.min(w, h) * OVERVIEW_SCALE / 2.5,
|
||||
});
|
||||
return Widget.Button({
|
||||
attribute: {
|
||||
address, x, y, w, h, ws: id,
|
||||
updateIconSize: (self) => {
|
||||
appIcon.size = Math.min(self.attribute.w, self.attribute.h) * OVERVIEW_SCALE / 2.5;
|
||||
},
|
||||
},
|
||||
className: 'overview-tasks-window',
|
||||
hpack: 'start',
|
||||
vpack: 'start',
|
||||
css: `
|
||||
margin-left: ${Math.round(x * OVERVIEW_SCALE)}px;
|
||||
margin-top: ${Math.round(y * OVERVIEW_SCALE)}px;
|
||||
margin-right: -${Math.round((x + w) * OVERVIEW_SCALE)}px;
|
||||
margin-bottom: -${Math.round((y + h) * OVERVIEW_SCALE)}px;
|
||||
`,
|
||||
onClicked: (self) => {
|
||||
Hyprland.sendMessage(`dispatch focuswindow address:${address}`);
|
||||
App.closeWindow('overview');
|
||||
},
|
||||
onMiddleClickRelease: () => Hyprland.sendMessage(`dispatch closewindow address:${address}`),
|
||||
onSecondaryClick: (button) => {
|
||||
button.toggleClassName('overview-tasks-window-selected', true);
|
||||
const menu = Widget.Menu({
|
||||
className: 'menu',
|
||||
children: [
|
||||
Widget.MenuItem({
|
||||
child: Widget.Label({
|
||||
xalign: 0,
|
||||
label: "Close (Middle-click)",
|
||||
}),
|
||||
onActivate: () => Hyprland.sendMessage(`dispatch closewindow address:${address}`),
|
||||
}),
|
||||
ContextMenuWorkspaceArray({
|
||||
label: "Dump windows to workspace",
|
||||
actionFunc: dumpToWorkspace,
|
||||
thisWorkspace: Number(id)
|
||||
}),
|
||||
ContextMenuWorkspaceArray({
|
||||
label: "Swap windows with workspace",
|
||||
actionFunc: swapWorkspace,
|
||||
thisWorkspace: Number(id)
|
||||
}),
|
||||
],
|
||||
});
|
||||
menu.connect("deactivate", () => {
|
||||
button.toggleClassName('overview-tasks-window-selected', false);
|
||||
})
|
||||
menu.connect("selection-done", () => {
|
||||
button.toggleClassName('overview-tasks-window-selected', false);
|
||||
})
|
||||
menu.popup_at_widget(button.get_parent(), Gravity.SOUTH, Gravity.NORTH, null); // Show menu below the button
|
||||
button.connect("destroy", () => menu.destroy());
|
||||
},
|
||||
child: Widget.Box({
|
||||
homogeneous: true,
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
appIcon,
|
||||
// TODO: Add xwayland tag instead of just having italics
|
||||
// Widget.Revealer({
|
||||
// transition: 'slide_down',
|
||||
// revealChild: revealInfoCondition,
|
||||
// child: Widget.Label({
|
||||
// truncate: 'end',
|
||||
// className: `${xwayland ? 'txt txt-italic' : 'txt'}`,
|
||||
// css: `
|
||||
// font-size: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 14.6}px;
|
||||
// margin: 0px ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE / 10}px;
|
||||
// `,
|
||||
// // If the title is too short, include the class
|
||||
// label: (title.length <= 1 ? `${c}: ${title}` : title),
|
||||
// })
|
||||
// })
|
||||
]
|
||||
})
|
||||
}),
|
||||
tooltipText: `${c}: ${title}`,
|
||||
setup: (button) => {
|
||||
setupCursorHoverGrab(button);
|
||||
|
||||
button.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.MOVE);
|
||||
button.drag_source_set_icon_name(substitute(c));
|
||||
// button.drag_source_set_icon_gicon(icon);
|
||||
|
||||
button.connect('drag-begin', (button) => { // On drag start, add the dragging class
|
||||
button.toggleClassName('overview-tasks-window-dragging', true);
|
||||
});
|
||||
button.connect('drag-data-get', (_w, _c, data) => { // On drag finish, give address
|
||||
data.set_text(address, address.length);
|
||||
button.toggleClassName('overview-tasks-window-dragging', false);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const Workspace = (index) => {
|
||||
// const fixed = Widget.Fixed({
|
||||
// attribute: {
|
||||
// put: (widget, x, y) => {
|
||||
// fixed.put(widget, x, y);
|
||||
// },
|
||||
// move: (widget, x, y) => {
|
||||
// fixed.move(widget, x, y);
|
||||
// },
|
||||
// }
|
||||
// });
|
||||
const fixed = Widget.Box({
|
||||
attribute: {
|
||||
put: (widget, x, y) => {
|
||||
if (!widget.attribute) return;
|
||||
// Note: x and y are already multiplied by OVERVIEW_SCALE
|
||||
const newCss = `
|
||||
margin-left: ${Math.round(x)}px;
|
||||
margin-top: ${Math.round(y)}px;
|
||||
margin-right: -${Math.round(x + (widget.attribute.w * OVERVIEW_SCALE))}px;
|
||||
margin-bottom: -${Math.round(y + (widget.attribute.h * OVERVIEW_SCALE))}px;
|
||||
`;
|
||||
widget.css = newCss;
|
||||
fixed.pack_start(widget, false, false, 0);
|
||||
},
|
||||
move: (widget, x, y) => {
|
||||
if (!widget) return;
|
||||
if (!widget.attribute) return;
|
||||
// Note: x and y are already multiplied by OVERVIEW_SCALE
|
||||
const newCss = `
|
||||
margin-left: ${Math.round(x)}px;
|
||||
margin-top: ${Math.round(y)}px;
|
||||
margin-right: -${Math.round(x + (widget.attribute.w * OVERVIEW_SCALE))}px;
|
||||
margin-bottom: -${Math.round(y + (widget.attribute.h * OVERVIEW_SCALE))}px;
|
||||
`;
|
||||
widget.css = newCss;
|
||||
},
|
||||
}
|
||||
})
|
||||
,
|
||||
});
|
||||
const WorkspaceNumber = (index) => Widget.Label({
|
||||
className: 'overview-tasks-workspace-number',
|
||||
label: `${index}`,
|
||||
css: `
|
||||
margin: ${Math.min(SCREEN_WIDTH, SCREEN_HEIGHT) * OVERVIEW_SCALE * OVERVIEW_WS_NUM_MARGIN_SCALE}px;
|
||||
font-size: ${SCREEN_HEIGHT * OVERVIEW_SCALE * OVERVIEW_WS_NUM_SCALE}px;
|
||||
`,
|
||||
})
|
||||
const widget = Widget.Box({
|
||||
className: 'overview-tasks-workspace',
|
||||
vpack: 'center',
|
||||
css: `
|
||||
min-width: ${SCREEN_WIDTH * OVERVIEW_SCALE}px;
|
||||
min-height: ${SCREEN_HEIGHT * OVERVIEW_SCALE}px;
|
||||
`,
|
||||
children: [Widget.EventBox({
|
||||
hexpand: true,
|
||||
vexpand: true,
|
||||
onPrimaryClick: () => {
|
||||
Hyprland.sendMessage(`dispatch workspace ${index}`)
|
||||
App.closeWindow('overview');
|
||||
},
|
||||
setup: (eventbox) => {
|
||||
eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
|
||||
eventbox.connect('drag-data-received', (_w, _c, _x, _y, data) => {
|
||||
Hyprland.sendMessage(`dispatch movetoworkspacesilent ${index},address:${data.get_text()}`)
|
||||
overviewTick.setValue(!overviewTick.value);
|
||||
});
|
||||
},
|
||||
child: fixed,
|
||||
})],
|
||||
});
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
fixed.attribute.put(WorkspaceNumber(offset + index), 0, 0);
|
||||
widget.clear = () => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
clientMap.forEach((client, address) => {
|
||||
if (!client || client.ws !== offset + index) return;
|
||||
client.destroy();
|
||||
client = null;
|
||||
clientMap.delete(address);
|
||||
});
|
||||
}
|
||||
widget.set = (clientJson, screenCoords) => {
|
||||
let c = clientMap.get(clientJson.address);
|
||||
if (c) {
|
||||
if (c.attribute?.ws !== clientJson.workspace.id) {
|
||||
c.destroy();
|
||||
c = null;
|
||||
clientMap.delete(clientJson.address);
|
||||
}
|
||||
else if (c) {
|
||||
c.attribute.w = clientJson.size[0];
|
||||
c.attribute.h = clientJson.size[1];
|
||||
c.attribute.updateIconSize(c);
|
||||
fixed.attribute.move(c,
|
||||
Math.max(0, clientJson.at[0] * OVERVIEW_SCALE),
|
||||
Math.max(0, clientJson.at[1] * OVERVIEW_SCALE)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const newWindow = Window(clientJson, screenCoords);
|
||||
if (newWindow === null) return;
|
||||
// clientMap.set(clientJson.address, newWindow);
|
||||
fixed.attribute.put(newWindow,
|
||||
Math.max(0, newWindow.attribute.x * OVERVIEW_SCALE),
|
||||
Math.max(0, newWindow.attribute.y * OVERVIEW_SCALE)
|
||||
);
|
||||
clientMap.set(clientJson.address, newWindow);
|
||||
};
|
||||
widget.unset = (clientAddress) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
let c = clientMap.get(clientAddress);
|
||||
if (!c) return;
|
||||
c.destroy();
|
||||
c = null;
|
||||
clientMap.delete(clientAddress);
|
||||
};
|
||||
widget.show = () => {
|
||||
fixed.show_all();
|
||||
}
|
||||
return widget;
|
||||
};
|
||||
|
||||
const arr = (s, n) => {
|
||||
const array = [];
|
||||
for (let i = 0; i < n; i++)
|
||||
array.push(s + i);
|
||||
|
||||
export default () => Widget.Revealer({
|
||||
revealChild: true,
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 200,
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
className: 'overview-tasks',
|
||||
children: Array.from({ length: NUM_OF_WORKSPACE_ROWS }, (_, index) =>
|
||||
OverviewRow({
|
||||
startWorkspace: 1 + index * NUM_OF_WORKSPACE_COLS,
|
||||
workspaces: NUM_OF_WORKSPACE_COLS,
|
||||
})
|
||||
)
|
||||
}),
|
||||
});
|
||||
return array;
|
||||
};
|
||||
|
||||
const OverviewRow = ({ startWorkspace, workspaces, windowName = 'overview' }) => Widget.Box({
|
||||
children: arr(startWorkspace, workspaces).map(Workspace),
|
||||
attribute: {
|
||||
monitorMap: [],
|
||||
getMonitorMap: (box) => {
|
||||
execAsync('hyprctl -j monitors').then(monitors => {
|
||||
box.attribute.monitorMap = JSON.parse(monitors).reduce((acc, item) => {
|
||||
acc[item.id] = { x: item.x, y: item.y };
|
||||
return acc;
|
||||
}, {});
|
||||
});
|
||||
},
|
||||
update: (box) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
if (!App.getWindow(windowName).visible) return;
|
||||
Hyprland.sendMessage('j/clients').then(clients => {
|
||||
const allClients = JSON.parse(clients);
|
||||
const kids = box.get_children();
|
||||
kids.forEach(kid => kid.clear());
|
||||
// console.log('----------------------------');
|
||||
for (let i = 0; i < allClients.length; i++) {
|
||||
const client = allClients[i];
|
||||
const childID = client.workspace.id - (offset + startWorkspace);
|
||||
if (offset + startWorkspace <= client.workspace.id &&
|
||||
client.workspace.id <= offset + startWorkspace + workspaces) {
|
||||
const screenCoords = box.attribute.monitorMap[client.monitor];
|
||||
if (kids[childID]) {
|
||||
kids[childID].set(client, screenCoords);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// const modID = client.workspace.id % NUM_OF_WORKSPACES_SHOWN;
|
||||
// console.log(`[${startWorkspace} -> ${startWorkspace + workspaces - 1}] ? (${client.workspace.id} == ${modID})`);
|
||||
// // console.log(`[${startWorkspace} -> ${startWorkspace + workspaces}] ? (${modID})`);
|
||||
// if (startWorkspace <= modID && modID < startWorkspace + workspaces) {
|
||||
// console.log('i care');
|
||||
// const clientWidget = clientMap.get(client.address);
|
||||
// console.log(childID, kids[childID], clientWidget);
|
||||
// if (kids[childID] && clientWidget) {
|
||||
// console.log('hmm remove', clientWidget.attribute)
|
||||
// kids[childID].remove(clientWidget);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
kids.forEach(kid => kid.show());
|
||||
}).catch(print);
|
||||
},
|
||||
updateWorkspace: (box, id) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
if (!( // Not in range, ignore
|
||||
offset + startWorkspace <= id &&
|
||||
id <= offset + startWorkspace + workspaces
|
||||
)) return;
|
||||
// if (!App.getWindow(windowName).visible) return;
|
||||
Hyprland.sendMessage('j/clients').then(clients => {
|
||||
const allClients = JSON.parse(clients);
|
||||
const kids = box.get_children();
|
||||
for (let i = 0; i < allClients.length; i++) {
|
||||
const client = allClients[i];
|
||||
if (client.workspace.id != id) continue;
|
||||
const screenCoords = box.attribute.monitorMap[client.monitor];
|
||||
kids[id - (offset + startWorkspace)]?.set(client, screenCoords);
|
||||
}
|
||||
kids[id - (offset + startWorkspace)]?.show();
|
||||
}).catch(print);
|
||||
},
|
||||
},
|
||||
setup: (box) => {
|
||||
box.attribute.getMonitorMap(box);
|
||||
box
|
||||
.hook(overviewTick, (box) => box.attribute.update(box))
|
||||
.hook(Hyprland, (box, clientAddress) => {
|
||||
const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
|
||||
const kids = box.get_children();
|
||||
const client = Hyprland.getClient(clientAddress);
|
||||
if (!client) return;
|
||||
const id = client.workspace.id;
|
||||
|
||||
box.attribute.updateWorkspace(box, id);
|
||||
kids[id - (offset + startWorkspace)]?.unset(clientAddress);
|
||||
}, 'client-removed')
|
||||
.hook(Hyprland, (box, clientAddress) => {
|
||||
const client = Hyprland.getClient(clientAddress);
|
||||
if (!client) return;
|
||||
box.attribute.updateWorkspace(box, client.workspace.id);
|
||||
}, 'client-added')
|
||||
.hook(Hyprland.active.workspace, (box) => {
|
||||
const previousGroup = box.attribute.workspaceGroup;
|
||||
const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN);
|
||||
if (currentGroup !== previousGroup) {
|
||||
box.attribute.update(box);
|
||||
workspaceGroup = currentGroup;
|
||||
}
|
||||
// box.attribute.update(box);
|
||||
})
|
||||
.hook(App, (box, name, visible) => { // Update on open
|
||||
if (name == 'overview' && visible) box.attribute.update(box);
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
return Widget.Revealer({
|
||||
revealChild: true,
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 200,
|
||||
child: Widget.Box({
|
||||
vertical: true,
|
||||
className: 'overview-tasks',
|
||||
children: Array.from({ length: NUM_OF_WORKSPACE_ROWS }, (_, index) =>
|
||||
OverviewRow({
|
||||
startWorkspace: 1 + index * NUM_OF_WORKSPACE_COLS,
|
||||
workspaces: NUM_OF_WORKSPACE_COLS,
|
||||
})
|
||||
)
|
||||
}),
|
||||
});
|
||||
}
|
||||
@@ -38,12 +38,6 @@ export const DirectoryButton = ({ parentPath, name, type, icon }) => {
|
||||
homogeneous: true,
|
||||
child: Widget.Icon({
|
||||
icon: icon,
|
||||
setup: (self) => Utils.timeout(1, () => {
|
||||
const styleContext = self.get_parent().get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1);
|
||||
})
|
||||
}),
|
||||
}),
|
||||
Widget.Label({
|
||||
@@ -112,12 +106,6 @@ export const DesktopEntryButton = (app) => {
|
||||
homogeneous: true,
|
||||
child: Widget.Icon({
|
||||
icon: app.iconName,
|
||||
setup: (self) => Utils.timeout(1, () => {
|
||||
const styleContext = self.get_parent().get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1);
|
||||
})
|
||||
}),
|
||||
}),
|
||||
Widget.Label({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { Gtk } = imports.gi;
|
||||
const { Gdk, Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
@@ -76,7 +76,7 @@ export const SearchAndWindows = () => {
|
||||
child: Widget.Label({
|
||||
className: 'overview-search-prompt txt-small txt',
|
||||
label: 'Type to search'
|
||||
})
|
||||
}),
|
||||
});
|
||||
|
||||
const entryIconRevealer = Widget.Revealer({
|
||||
@@ -217,7 +217,10 @@ export const SearchAndWindows = () => {
|
||||
entry,
|
||||
Widget.Box({
|
||||
className: 'overview-search-icon-box',
|
||||
setup: box => box.pack_start(entryPromptRevealer, true, true, 0),
|
||||
setup: (box) => {
|
||||
box.pack_start(entryPromptRevealer, true, true, 0)
|
||||
// enableClickthrough(box);
|
||||
},
|
||||
}),
|
||||
entryIcon,
|
||||
]
|
||||
@@ -233,10 +236,31 @@ export const SearchAndWindows = () => {
|
||||
}
|
||||
})
|
||||
.on('key-press-event', (widget, event) => { // Typing
|
||||
if (event.get_keyval()[1] >= 32 && event.get_keyval()[1] <= 126 && widget != entry) {
|
||||
Utils.timeout(1, () => entry.grab_focus());
|
||||
entry.set_text(entry.text + String.fromCharCode(event.get_keyval()[1]));
|
||||
entry.set_position(-1);
|
||||
const keyval = event.get_keyval()[1];
|
||||
const modstate = event.get_state()[1];
|
||||
if (modstate & Gdk.ModifierType.CONTROL_MASK) { // Ctrl held
|
||||
if (keyval == Gdk.KEY_b)
|
||||
entry.set_position(Math.max(entry.get_position() - 1, 0));
|
||||
else if (keyval == Gdk.KEY_f)
|
||||
entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length));
|
||||
else if (keyval == Gdk.KEY_n) { // simulate Down arrow
|
||||
entry.get_root_window().simulate_key_press(Gdk.KEY_Down, Gdk.ModifierType.NONE);
|
||||
// entry.get_root_window().simulate_key_release(Gdk.KEY_Down, Gdk.ModifierType.NONE);
|
||||
}
|
||||
else if (keyval == Gdk.KEY_k) { // Delete to end
|
||||
const text = entry.get_text();
|
||||
const pos = entry.get_position();
|
||||
const newText = text.slice(0, pos);
|
||||
entry.set_text(newText);
|
||||
entry.set_position(newText.length);
|
||||
}
|
||||
}
|
||||
else { // Ctrl not held
|
||||
if (keyval >= 32 && keyval <= 126 && widget != entry) {
|
||||
Utils.timeout(1, () => entry.grab_focus());
|
||||
entry.set_text(entry.text + String.fromCharCode(keyval));
|
||||
entry.set_position(-1);
|
||||
}
|
||||
}
|
||||
})
|
||||
,
|
||||
|
||||
@@ -44,6 +44,7 @@ function copyToClipboard(text) {
|
||||
function substituteLang(str) {
|
||||
const subs = [
|
||||
{ from: 'javascript', to: 'js' },
|
||||
{ from: 'bash', to: 'sh' },
|
||||
];
|
||||
|
||||
for (const { from, to } of subs) {
|
||||
@@ -58,7 +59,7 @@ const HighlightedCode = (content, lang) => {
|
||||
const buffer = new GtkSource.Buffer();
|
||||
const sourceView = new GtkSource.View({
|
||||
buffer: buffer,
|
||||
wrap_mode: Gtk.WrapMode.WORD
|
||||
wrap_mode: Gtk.WrapMode.NONE
|
||||
});
|
||||
const langManager = GtkSource.LanguageManager.get_default();
|
||||
let displayLang = langManager.get_language(substituteLang(lang)); // Set your preferred language
|
||||
|
||||
@@ -19,14 +19,6 @@ export const chatGPTTabIcon = Icon({
|
||||
hpack: 'center',
|
||||
className: 'sidebar-chat-apiswitcher-icon',
|
||||
icon: `openai-symbolic`,
|
||||
setup: (self) => Utils.timeout(513, () => { // stupid condition race
|
||||
const styleContext = self.get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
// console.log(Math.round(Math.max(width, height, 1)));
|
||||
self.size = Math.max(width, height, 1) * 116 / 180;
|
||||
// ↑ Why such a specific proportion? See https://openai.com/brand#logos
|
||||
})
|
||||
});
|
||||
|
||||
const ChatGPTInfo = () => {
|
||||
@@ -34,14 +26,6 @@ const ChatGPTInfo = () => {
|
||||
hpack: 'center',
|
||||
className: 'sidebar-chat-welcome-logo',
|
||||
icon: `openai-symbolic`,
|
||||
setup: (self) => Utils.timeout(513, () => { // stupid condition race
|
||||
const styleContext = self.get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
// console.log(Math.round(Math.max(width, height, 1)));
|
||||
self.size = Math.max(width, height, 1) * 116 / 180;
|
||||
// ↑ Why such a specific proportion? See https://openai.com/brand#logos
|
||||
})
|
||||
});
|
||||
return Box({
|
||||
vertical: true,
|
||||
|
||||
@@ -20,12 +20,6 @@ export const geminiTabIcon = Icon({
|
||||
hpack: 'center',
|
||||
className: 'sidebar-chat-apiswitcher-icon',
|
||||
icon: `google-gemini-symbolic`,
|
||||
setup: (self) => Utils.timeout(513, () => { // stupid condition race
|
||||
const styleContext = self.get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1) * 116 / 180;
|
||||
})
|
||||
})
|
||||
|
||||
const GeminiInfo = () => {
|
||||
@@ -33,12 +27,6 @@ const GeminiInfo = () => {
|
||||
hpack: 'center',
|
||||
className: 'sidebar-chat-welcome-logo',
|
||||
icon: `google-gemini-symbolic`,
|
||||
setup: (self) => Utils.timeout(513, () => { // stupid condition race
|
||||
const styleContext = self.get_style_context();
|
||||
const width = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
|
||||
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
|
||||
self.size = Math.max(width, height, 1) * 116 / 180;
|
||||
})
|
||||
});
|
||||
return Box({
|
||||
vertical: true,
|
||||
|
||||
@@ -417,6 +417,14 @@ export const sendMessage = (text) => {
|
||||
true
|
||||
));
|
||||
}
|
||||
else if (text.startsWith('/place')) {
|
||||
const newImage = WaifuImage(['/place']);
|
||||
waifuContent.add(newImage);
|
||||
Utils.timeout(IMAGE_REVEAL_DELAY, () => newImage.attribute.update(
|
||||
DummyTag(400, 600, 'https://placewaifu.com/image/400/600', '#F0A235'),
|
||||
true
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
else WaifuService.fetch(text);
|
||||
|
||||
@@ -13,19 +13,12 @@ import Gemini from '../../services/gemini.js';
|
||||
import { geminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js';
|
||||
import { chatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
|
||||
import { waifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js';
|
||||
const TextView = Widget.subclass(Gtk.TextView, "AgsTextView");
|
||||
import { enableClickthrough } from '../../lib/roundedcorner.js';
|
||||
const TextView = Widget.subclass(Gtk.TextView, "AgsTextView");
|
||||
|
||||
|
||||
const EXPAND_INPUT_THRESHOLD = 30;
|
||||
const APIS = [
|
||||
{
|
||||
name: 'Assistant (ChatGPT 3.5)',
|
||||
sendCommand: chatGPTSendMessage,
|
||||
contentWidget: chatGPTView,
|
||||
commandBar: chatGPTCommands,
|
||||
tabIcon: chatGPTTabIcon,
|
||||
placeholderText: 'Message ChatGPT...',
|
||||
},
|
||||
{
|
||||
name: 'Assistant (Gemini Pro)',
|
||||
sendCommand: geminiSendMessage,
|
||||
@@ -34,6 +27,14 @@ const APIS = [
|
||||
tabIcon: geminiTabIcon,
|
||||
placeholderText: 'Message Gemini...',
|
||||
},
|
||||
{
|
||||
name: 'Assistant (ChatGPT 3.5)',
|
||||
sendCommand: chatGPTSendMessage,
|
||||
contentWidget: chatGPTView,
|
||||
commandBar: chatGPTCommands,
|
||||
tabIcon: chatGPTTabIcon,
|
||||
placeholderText: 'Message ChatGPT...',
|
||||
},
|
||||
{
|
||||
name: 'Waifus',
|
||||
sendCommand: waifuSendMessage,
|
||||
@@ -141,6 +142,7 @@ const chatPlaceholderRevealer = Revealer({
|
||||
transition: 'crossfade',
|
||||
transitionDuration: 200,
|
||||
child: chatPlaceholder,
|
||||
setup: enableClickthrough,
|
||||
});
|
||||
|
||||
const textboxArea = Box({ // Entry area
|
||||
@@ -159,12 +161,20 @@ const textboxArea = Box({ // Entry area
|
||||
const apiContentStack = Stack({
|
||||
vexpand: true,
|
||||
transition: 'slide_left_right',
|
||||
items: APIS.map(api => [api.name, api.contentWidget]),
|
||||
transitionDuration: 160,
|
||||
children: APIS.reduce((acc, api) => {
|
||||
acc[api.name] = api.contentWidget;
|
||||
return acc;
|
||||
}, {}),
|
||||
})
|
||||
|
||||
const apiCommandStack = Stack({
|
||||
transition: 'slide_up_down',
|
||||
items: APIS.map(api => [api.name, api.commandBar]),
|
||||
transitionDuration: 160,
|
||||
children: APIS.reduce((acc, api) => {
|
||||
acc[api.name] = api.commandBar;
|
||||
return acc;
|
||||
}, {}),
|
||||
})
|
||||
|
||||
function switchToTab(id) {
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
const { Box, Button, Label } = Widget;
|
||||
|
||||
export const SidebarModule = ({
|
||||
name,
|
||||
child
|
||||
}) => {
|
||||
return Box({
|
||||
className: 'sidebar-module',
|
||||
vertical: true,
|
||||
children: [
|
||||
Button({
|
||||
child: Box({
|
||||
children: [
|
||||
Label({
|
||||
className: 'txt-small txt',
|
||||
label: `${name}`,
|
||||
}),
|
||||
Box({
|
||||
hexpand: true,
|
||||
}),
|
||||
Label({
|
||||
className: 'sidebar-module-btn-arrow',
|
||||
})
|
||||
]
|
||||
})
|
||||
})
|
||||
]
|
||||
});
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, Button, EventBox, Label, Scrollable } = Widget;
|
||||
import { SidebarModule } from './module.js';
|
||||
|
||||
export const QuickScripts = () => SidebarModule({
|
||||
name: 'Quick scripts',
|
||||
child: Box({
|
||||
})
|
||||
})
|
||||
@@ -30,7 +30,11 @@ let currentTabId = 0;
|
||||
export const contentStack = Stack({
|
||||
vexpand: true,
|
||||
transition: 'slide_left_right',
|
||||
items: contents.map(item => [item.name, item.content]),
|
||||
transitionDuration: 160,
|
||||
children: contents.reduce((acc, item) => {
|
||||
acc[item.name] = item.content;
|
||||
return acc;
|
||||
}, {}),
|
||||
})
|
||||
|
||||
function switchToTab(id) {
|
||||
|
||||
@@ -2,15 +2,18 @@ import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { Box, Button, EventBox, Label, Revealer, Scrollable, Stack } = Widget;
|
||||
const { execAsync, exec } = Utils;
|
||||
import { QuickScripts } from './quickscripts.js';
|
||||
import QuickScripts from './tools/quickscripts.js';
|
||||
import ColorPicker from './tools/colorpicker.js';
|
||||
|
||||
export default Scrollable({
|
||||
hscroll: "never",
|
||||
vscroll: "automatic",
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-10',
|
||||
children: [
|
||||
// QuickScripts(),
|
||||
QuickScripts(),
|
||||
ColorPicker(),
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
// It's weird, I know
|
||||
const { Gio, GLib } = imports.gi;
|
||||
import Service from 'resource:///com/github/Aylur/ags/service.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { exec, execAsync } = Utils;
|
||||
|
||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
|
||||
export class ColorPickerSelection extends Service {
|
||||
static {
|
||||
Service.register(this, {
|
||||
'picked': [],
|
||||
'assigned': ['int'],
|
||||
'hue': [],
|
||||
'sl': [],
|
||||
});
|
||||
}
|
||||
|
||||
_hue = 198;
|
||||
_xAxis = 94;
|
||||
_yAxis = 80;
|
||||
|
||||
get hue() { return this._hue; }
|
||||
set hue(value) {
|
||||
this._hue = clamp(value, 0, 360);
|
||||
this.emit('hue');
|
||||
this.emit('picked');
|
||||
this.emit('changed');
|
||||
}
|
||||
get xAxis() { return this._xAxis; }
|
||||
set xAxis(value) {
|
||||
this._xAxis = clamp(value, 0, 100);
|
||||
this.emit('sl');
|
||||
this.emit('picked');
|
||||
this.emit('changed');
|
||||
}
|
||||
get yAxis() { return this._yAxis; }
|
||||
set yAxis(value) {
|
||||
this._yAxis = clamp(value, 0, 100);
|
||||
this.emit('sl');
|
||||
this.emit('picked');
|
||||
this.emit('changed');
|
||||
}
|
||||
setColorFromHex(hexString, id) {
|
||||
const hsl = hexToHSL(hexString);
|
||||
this._hue = hsl.hue;
|
||||
this._xAxis = hsl.saturation;
|
||||
// this._yAxis = hsl.lightness;
|
||||
this._yAxis = (100 - hsl.saturation / 2) / 100 * hsl.lightness;
|
||||
// console.log(this._hue, this._xAxis, this._yAxis)
|
||||
this.emit('assigned', id);
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.emit('changed');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function hslToRgbValues(h, s, l) {
|
||||
h /= 360;
|
||||
s /= 100;
|
||||
l /= 100;
|
||||
let r, g, b;
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
const hue2rgb = (p, q, t) => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
const to255 = x => Math.round(x * 255);
|
||||
r = to255(r);
|
||||
g = to255(g);
|
||||
b = to255(b);
|
||||
return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`;
|
||||
// return `rgb(${r},${g},${b})`;
|
||||
}
|
||||
export function hslToHex(h, s, l) {
|
||||
h /= 360;
|
||||
s /= 100;
|
||||
l /= 100;
|
||||
let r, g, b;
|
||||
if (s === 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
const hue2rgb = (p, q, t) => {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
};
|
||||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||
const p = 2 * l - q;
|
||||
r = hue2rgb(p, q, h + 1 / 3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1 / 3);
|
||||
}
|
||||
const toHex = x => {
|
||||
const hex = Math.round(x * 255).toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
};
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||
}
|
||||
|
||||
// export function hexToHSL(hex) {
|
||||
// // Remove the '#' if present
|
||||
// hex = hex.replace(/^#/, '');
|
||||
// // Parse the hex value into RGB components
|
||||
// const bigint = parseInt(hex, 16);
|
||||
// const r = (bigint >> 16) & 255;
|
||||
// const g = (bigint >> 8) & 255;
|
||||
// const b = bigint & 255;
|
||||
// // Normalize RGB values to range [0, 1]
|
||||
// const normalizedR = r / 255;
|
||||
// const normalizedG = g / 255;
|
||||
// const normalizedB = b / 255;
|
||||
// // Find the maximum and minimum values
|
||||
// const max = Math.max(normalizedR, normalizedG, normalizedB);
|
||||
// const min = Math.min(normalizedR, normalizedG, normalizedB);
|
||||
// // Calculate the lightness
|
||||
// const lightness = (max + min) / 2;
|
||||
// // If the color is grayscale, set saturation to 0
|
||||
// if (max === min) {
|
||||
// return {
|
||||
// hue: 0,
|
||||
// saturation: 0,
|
||||
// lightness: lightness * 100 // Convert to percentage
|
||||
// };
|
||||
// }
|
||||
// // Calculate the saturation
|
||||
// const d = max - min;
|
||||
// const saturation = lightness > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
// // Calculate the hue
|
||||
// let hue;
|
||||
// if (max === normalizedR) {
|
||||
// hue = ((normalizedG - normalizedB) / d + (normalizedG < normalizedB ? 6 : 0)) * 60;
|
||||
// } else if (max === normalizedG) {
|
||||
// hue = ((normalizedB - normalizedR) / d + 2) * 60;
|
||||
// } else {
|
||||
// hue = ((normalizedR - normalizedG) / d + 4) * 60;
|
||||
// }
|
||||
// return {
|
||||
// hue: Math.round(hue),
|
||||
// saturation: Math.round(saturation * 100), // Convert to percentage
|
||||
// lightness: Math.round(lightness * 100) // Convert to percentage
|
||||
// };
|
||||
// }
|
||||
|
||||
export function hexToHSL(hex) {
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
|
||||
var r = parseInt(result[1], 16);
|
||||
var g = parseInt(result[2], 16);
|
||||
var b = parseInt(result[3], 16);
|
||||
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2;
|
||||
|
||||
if (max == min) {
|
||||
h = s = 0; // achromatic
|
||||
} else {
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch (max) {
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
s = s * 100;
|
||||
s = Math.round(s);
|
||||
l = l * 100;
|
||||
l = Math.round(l);
|
||||
h = Math.round(360 * h);
|
||||
|
||||
return {
|
||||
hue: h,
|
||||
saturation: s,
|
||||
lightness: l
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
// TODO: Make selection update when entry changes
|
||||
const { Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, Button, Entry, EventBox, Icon, Label, Overlay, Scrollable } = Widget;
|
||||
import SidebarModule from './module.js';
|
||||
import { MaterialIcon } from '../../../lib/materialicon.js';
|
||||
import { setupCursorHover } from '../../../lib/cursorhover.js';
|
||||
|
||||
import { ColorPickerSelection, hslToHex, hslToRgbValues, hexToHSL } from './color.js';
|
||||
|
||||
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
|
||||
|
||||
export default () => {
|
||||
const selectedColor = new ColorPickerSelection();
|
||||
function shouldUseBlackColor() {
|
||||
return ((selectedColor.xAxis < 40 || (45 <= selectedColor.hue && selectedColor.hue <= 195)) &&
|
||||
selectedColor.yAxis > 60);
|
||||
}
|
||||
const colorBlack = 'rgba(0,0,0,0.9)';
|
||||
const colorWhite = 'rgba(255,255,255,0.9)';
|
||||
const hueRange = Box({
|
||||
homogeneous: true,
|
||||
className: 'sidebar-module-colorpicker-wrapper',
|
||||
children: [Box({
|
||||
className: 'sidebar-module-colorpicker-hue',
|
||||
css: `background: linear-gradient(to bottom, #ff6666, #ffff66, #66dd66, #66ffff, #6666ff, #ff66ff, #ff6666);`,
|
||||
})],
|
||||
});
|
||||
const hueSlider = Box({
|
||||
vpack: 'start',
|
||||
className: 'sidebar-module-colorpicker-cursorwrapper',
|
||||
css: `margin-top: ${13.636 * selectedColor.hue / 360}rem;`,
|
||||
homogeneous: true,
|
||||
children: [Box({
|
||||
className: 'sidebar-module-colorpicker-hue-cursor',
|
||||
})],
|
||||
setup: (self) => self.hook(selectedColor, () => {
|
||||
const widgetHeight = hueRange.children[0].get_allocated_height();
|
||||
self.setCss(`margin-top: ${13.636 * selectedColor.hue / 360}rem;`)
|
||||
}),
|
||||
});
|
||||
const hueSelector = Box({
|
||||
children: [EventBox({
|
||||
child: Overlay({
|
||||
child: hueRange,
|
||||
overlays: [hueSlider],
|
||||
}),
|
||||
attribute: {
|
||||
clicked: false,
|
||||
setHue: (self, event) => {
|
||||
const widgetHeight = hueRange.children[0].get_allocated_height();
|
||||
const [_, cursorX, cursorY] = event.get_coords();
|
||||
const cursorYPercent = clamp(cursorY / widgetHeight, 0, 1);
|
||||
selectedColor.hue = Math.round(cursorYPercent * 360);
|
||||
}
|
||||
},
|
||||
setup: (self) => self
|
||||
.on('motion-notify-event', (self, event) => {
|
||||
if (!self.attribute.clicked) return;
|
||||
self.attribute.setHue(self, event);
|
||||
})
|
||||
.on('button-press-event', (self, event) => {
|
||||
if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
|
||||
self.attribute.clicked = true;
|
||||
self.attribute.setHue(self, event);
|
||||
})
|
||||
.on('button-release-event', (self) => self.attribute.clicked = false)
|
||||
,
|
||||
})]
|
||||
});
|
||||
const saturationAndLightnessRange = Box({
|
||||
homogeneous: true,
|
||||
children: [Box({
|
||||
className: 'sidebar-module-colorpicker-saturationandlightness',
|
||||
attribute: {
|
||||
update: (self) => {
|
||||
// css: `background: linear-gradient(to right, #ffffff, color);`,
|
||||
self.setCss(`background:
|
||||
linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,1)),
|
||||
linear-gradient(to right, #ffffff, ${hslToHex(selectedColor.hue, 100, 50)});
|
||||
`);
|
||||
},
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(selectedColor, self.attribute.update, 'hue')
|
||||
.hook(selectedColor, self.attribute.update, 'assigned')
|
||||
,
|
||||
})],
|
||||
});
|
||||
const saturationAndLightnessCursor = Box({
|
||||
className: 'sidebar-module-colorpicker-saturationandlightness-cursorwrapper',
|
||||
children: [Box({
|
||||
vpack: 'start',
|
||||
hpack: 'start',
|
||||
homogeneous: true,
|
||||
css: `
|
||||
margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
|
||||
margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
|
||||
`, // Why 13.636rem? see class name in stylesheet
|
||||
attribute: {
|
||||
update: (self) => {
|
||||
const allocation = saturationAndLightnessRange.children[0].get_allocation();
|
||||
self.setCss(`
|
||||
margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
|
||||
margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
|
||||
`); // Why 13.636rem? see class name in stylesheet
|
||||
}
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(selectedColor, self.attribute.update, 'sl')
|
||||
.hook(selectedColor, self.attribute.update, 'assigned')
|
||||
,
|
||||
children: [Box({
|
||||
className: 'sidebar-module-colorpicker-saturationandlightness-cursor',
|
||||
css: `
|
||||
background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
|
||||
border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
|
||||
`,
|
||||
attribute: {
|
||||
update: (self) => {
|
||||
self.setCss(`
|
||||
background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
|
||||
border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
|
||||
`);
|
||||
}
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(selectedColor, self.attribute.update, 'sl')
|
||||
.hook(selectedColor, self.attribute.update, 'hue')
|
||||
.hook(selectedColor, self.attribute.update, 'assigned')
|
||||
,
|
||||
})],
|
||||
})]
|
||||
});
|
||||
const saturationAndLightnessSelector = Box({
|
||||
homogeneous: true,
|
||||
className: 'sidebar-module-colorpicker-saturationandlightness-wrapper',
|
||||
children: [EventBox({
|
||||
child: Overlay({
|
||||
child: saturationAndLightnessRange,
|
||||
overlays: [saturationAndLightnessCursor],
|
||||
}),
|
||||
attribute: {
|
||||
clicked: false,
|
||||
setSaturationAndLightness: (self, event) => {
|
||||
const allocation = saturationAndLightnessRange.children[0].get_allocation();
|
||||
const [_, cursorX, cursorY] = event.get_coords();
|
||||
const cursorXPercent = clamp(cursorX / allocation.width, 0, 1);
|
||||
const cursorYPercent = clamp(cursorY / allocation.height, 0, 1);
|
||||
selectedColor.xAxis = Math.round(cursorXPercent * 100);
|
||||
selectedColor.yAxis = Math.round(100 - cursorYPercent * 100);
|
||||
}
|
||||
},
|
||||
setup: (self) => self
|
||||
.on('motion-notify-event', (self, event) => {
|
||||
if (!self.attribute.clicked) return;
|
||||
self.attribute.setSaturationAndLightness(self, event);
|
||||
})
|
||||
.on('button-press-event', (self, event) => {
|
||||
if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
|
||||
self.attribute.clicked = true;
|
||||
self.attribute.setSaturationAndLightness(self, event);
|
||||
})
|
||||
.on('button-release-event', (self) => self.attribute.clicked = false)
|
||||
,
|
||||
})]
|
||||
});
|
||||
const resultColorBox = Box({
|
||||
className: 'sidebar-module-colorpicker-result-box',
|
||||
homogeneous: true,
|
||||
css: `background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`,
|
||||
children: [Label({
|
||||
className: 'txt txt-small',
|
||||
label: 'Result',
|
||||
}),],
|
||||
attribute: {
|
||||
update: (self) => {
|
||||
self.setCss(`background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`);
|
||||
self.children[0].setCss(`color: ${shouldUseBlackColor() ? colorBlack : colorWhite};`)
|
||||
}
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(selectedColor, self.attribute.update, 'sl')
|
||||
.hook(selectedColor, self.attribute.update, 'hue')
|
||||
.hook(selectedColor, self.attribute.update, 'assigned')
|
||||
,
|
||||
});
|
||||
const ResultBox = ({ colorSystemName, updateCallback, copyCallback }) => Box({
|
||||
children: [
|
||||
Box({
|
||||
vertical: true,
|
||||
hexpand: true,
|
||||
children: [
|
||||
Label({
|
||||
xalign: 0,
|
||||
className: 'txt-tiny',
|
||||
label: colorSystemName,
|
||||
}),
|
||||
Overlay({
|
||||
child: Entry({
|
||||
widthChars: 10,
|
||||
className: 'txt-small techfont',
|
||||
attribute: {
|
||||
id: 0,
|
||||
update: updateCallback,
|
||||
},
|
||||
setup: (self) => self
|
||||
.hook(selectedColor, self.attribute.update, 'sl')
|
||||
.hook(selectedColor, self.attribute.update, 'hue')
|
||||
.hook(selectedColor, self.attribute.update, 'assigned')
|
||||
// .on('activate', (self) => {
|
||||
// const newColor = self.text;
|
||||
// if (newColor.length != 7) return;
|
||||
// selectedColor.setColorFromHex(self.text, self.attribute.id);
|
||||
// })
|
||||
,
|
||||
}),
|
||||
})
|
||||
]
|
||||
}),
|
||||
Button({
|
||||
child: MaterialIcon('content_copy', 'norm'),
|
||||
onClicked: (self) => {
|
||||
copyCallback(self);
|
||||
self.child.label = 'done';
|
||||
Utils.timeout(1000, () => self.child.label = 'content_copy');
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
})
|
||||
]
|
||||
});
|
||||
const resultHex = ResultBox({
|
||||
colorSystemName: 'Hex',
|
||||
updateCallback: (self, id) => {
|
||||
if (id && self.attribute.id === id) return;
|
||||
self.text = hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
|
||||
},
|
||||
copyCallback: () => Utils.execAsync(['wl-copy', `${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}`]),
|
||||
})
|
||||
const resultRgb = ResultBox({
|
||||
colorSystemName: 'RGB',
|
||||
updateCallback: (self, id) => {
|
||||
if (id && self.attribute.id === id) return;
|
||||
self.text = hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
|
||||
},
|
||||
copyCallback: () => Utils.execAsync(['wl-copy', `rgb(${hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))})`]),
|
||||
})
|
||||
const resultHsl = ResultBox({
|
||||
colorSystemName: 'HSL',
|
||||
updateCallback: (self, id) => {
|
||||
if (id && self.attribute.id === id) return;
|
||||
self.text = `${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%`;
|
||||
},
|
||||
copyCallback: () => Utils.execAsync(['wl-copy', `hsl(${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%)`]),
|
||||
})
|
||||
const result = Box({
|
||||
className: 'sidebar-module-colorpicker-result-area spacing-v-5 txt',
|
||||
hexpand: true,
|
||||
vertical: true,
|
||||
children: [
|
||||
resultColorBox,
|
||||
resultHex,
|
||||
resultRgb,
|
||||
resultHsl,
|
||||
]
|
||||
})
|
||||
return SidebarModule({
|
||||
icon: MaterialIcon('colorize', 'norm'),
|
||||
name: 'Color picker',
|
||||
revealChild: false,
|
||||
child: Box({
|
||||
className: 'spacing-h-5',
|
||||
children: [
|
||||
hueSelector,
|
||||
saturationAndLightnessSelector,
|
||||
result,
|
||||
]
|
||||
})
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import { setupCursorHover } from '../../../lib/cursorhover.js';
|
||||
import { MaterialIcon } from '../../../lib/materialicon.js';
|
||||
const { Box, Button, Icon, Label, Revealer } = Widget;
|
||||
|
||||
export default ({
|
||||
icon,
|
||||
name,
|
||||
child,
|
||||
revealChild = true,
|
||||
}) => {
|
||||
const headerButtonIcon = MaterialIcon(revealChild ? 'expand_less' : 'expand_more', 'norm');
|
||||
const header = Button({
|
||||
onClicked: () => {
|
||||
content.revealChild = !content.revealChild;
|
||||
headerButtonIcon.label = content.revealChild ? 'expand_less' : 'expand_more';
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
child: Box({
|
||||
className: 'txt spacing-h-10',
|
||||
children: [
|
||||
icon,
|
||||
Label({
|
||||
className: 'txt-norm',
|
||||
label: `${name}`,
|
||||
}),
|
||||
Box({
|
||||
hexpand: true,
|
||||
}),
|
||||
Box({
|
||||
className: 'sidebar-module-btn-arrow',
|
||||
homogeneous: true,
|
||||
children: [headerButtonIcon],
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
const content = Revealer({
|
||||
revealChild: revealChild,
|
||||
transition: 'slide_down',
|
||||
transitionDuration: 200,
|
||||
child: Box({
|
||||
className: 'margin-top-5',
|
||||
homogeneous: true,
|
||||
children: [child],
|
||||
}),
|
||||
});
|
||||
return Box({
|
||||
className: 'sidebar-module',
|
||||
vertical: true,
|
||||
children: [
|
||||
header,
|
||||
content,
|
||||
]
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
const { Gtk } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
const { execAsync, exec } = Utils;
|
||||
const { Box, Button, EventBox, Icon, Label, Scrollable } = Widget;
|
||||
import SidebarModule from './module.js';
|
||||
import { MaterialIcon } from '../../../lib/materialicon.js';
|
||||
import { setupCursorHover } from '../../../lib/cursorhover.js';
|
||||
|
||||
Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets`);
|
||||
const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2'`).trim();
|
||||
const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' || distroID == 'debian' || distroID == 'zorin' || distroID == 'pop' || distroID == 'raspbian' || distroID == 'kali' || distroID == 'elementary');
|
||||
const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros');
|
||||
const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`);
|
||||
|
||||
const scripts = [
|
||||
{
|
||||
icon: 'nixos-symbolic',
|
||||
name: 'Trim system generations to 5',
|
||||
command: `sudo ${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 system`,
|
||||
enabled: distroID == 'nixos',
|
||||
},
|
||||
{
|
||||
icon: 'nixos-symbolic',
|
||||
name: 'Trim home manager generations to 5',
|
||||
command: `${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 home-manager`,
|
||||
enabled: distroID == 'nixos',
|
||||
},
|
||||
{
|
||||
icon: 'ubuntu-symbolic',
|
||||
name: 'Update packages',
|
||||
command: `sudo apt update && sudo apt upgrade -y`,
|
||||
enabled: isDebianDistro,
|
||||
},
|
||||
{
|
||||
icon: 'fedora-symbolic',
|
||||
name: 'Update packages',
|
||||
command: `sudo dnf upgrade -y`,
|
||||
enabled: distroID == 'fedora',
|
||||
},
|
||||
{
|
||||
icon: 'arch-symbolic',
|
||||
name: 'Update packages',
|
||||
command: `sudo pacman -Syyu`,
|
||||
enabled: isArchDistro,
|
||||
},
|
||||
{
|
||||
icon: 'flatpak-symbolic',
|
||||
name: 'Uninstall unused flatpak packages',
|
||||
command: `flatpak uninstall --unused`,
|
||||
enabled: hasFlatpak,
|
||||
},
|
||||
];
|
||||
|
||||
export default () => SidebarModule({
|
||||
icon: MaterialIcon('code', 'norm'),
|
||||
name: 'Quick scripts',
|
||||
child: Box({
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: scripts.map((script) => {
|
||||
if (!script.enabled) return null;
|
||||
const scriptStateIcon = MaterialIcon('not_started', 'norm');
|
||||
return Box({
|
||||
className: 'spacing-h-5 txt',
|
||||
children: [
|
||||
Icon({
|
||||
className: 'sidebar-module-btn-icon txt-large',
|
||||
icon: script.icon,
|
||||
}),
|
||||
Label({
|
||||
className: 'txt-small',
|
||||
hpack: 'start',
|
||||
hexpand: true,
|
||||
label: script.name,
|
||||
tooltipText: script.command,
|
||||
}),
|
||||
Button({
|
||||
className: 'sidebar-module-scripts-button',
|
||||
child: scriptStateIcon,
|
||||
onClicked: () => {
|
||||
App.closeWindow('sideleft');
|
||||
execAsync([`bash`, `-c`, `foot fish -C "${script.command}"`]).catch(print)
|
||||
.then(() => {
|
||||
scriptStateIcon.label = 'done';
|
||||
})
|
||||
},
|
||||
setup: setupCursorHover,
|
||||
}),
|
||||
],
|
||||
})
|
||||
}),
|
||||
})
|
||||
});
|
||||
@@ -20,7 +20,7 @@ export default (props) => {
|
||||
vertical: true,
|
||||
className: 'spacing-v-5',
|
||||
children: [
|
||||
MaterialIcon('notifications_active', 'badonkers'),
|
||||
MaterialIcon('notifications_active', 'gigantic'),
|
||||
Label({ label: 'No notifications', className: 'txt-small' }),
|
||||
]
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { GLib } = imports.gi;
|
||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
||||
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
|
||||
|
||||
@@ -151,7 +152,7 @@ export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make
|
||||
self.toggleClassName('sidebar-button-active', self.attribute.enabled);
|
||||
if (self.attribute.enabled) {
|
||||
self.attribute.inhibitor = Utils.subprocess(
|
||||
['wayland-idle-inhibitor.py'],
|
||||
[`${App.configDir}/scripts/wayland-idle-inhibitor.py`],
|
||||
(output) => print(output),
|
||||
(err) => logError(err),
|
||||
self,
|
||||
|
||||
@@ -92,7 +92,7 @@ const todoItems = (isDone) => Widget.Scrollable({
|
||||
vpack: 'center',
|
||||
className: 'txt',
|
||||
children: [
|
||||
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'badonkers'),
|
||||
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'gigantic'),
|
||||
Label({ label: `${isDone ? 'Finished tasks will go here' : 'Nothing here!'}` })
|
||||
]
|
||||
})
|
||||
|
||||