mirror of
https://github.com/axzilla/templui.git
synced 2025-02-21 01:13:05 +00:00
feat: add icon component
This commit is contained in:
parent
4fdf078dcc
commit
9693741db0
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,6 @@
|
||||
# lucide icons
|
||||
cmd/icongen/icons
|
||||
|
||||
.DS_Store
|
||||
bin
|
||||
*_templ.go
|
||||
|
4
Makefile
4
Makefile
@ -26,3 +26,7 @@ dev:
|
||||
# Start development server in debug mode - It's needed to start launch.json in VSCode
|
||||
debug:
|
||||
make -j2 templ tailwind
|
||||
|
||||
# Generate Lucid icons
|
||||
generate-icons:
|
||||
go run cmd/icongen/main.go
|
||||
|
@ -628,18 +628,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.static {
|
||||
position: static;
|
||||
}
|
||||
@ -656,10 +644,6 @@ body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sticky {
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.inset-0 {
|
||||
inset: 0px;
|
||||
}
|
||||
@ -783,18 +767,6 @@ body {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mt-auto {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.mt-\[100vh\] {
|
||||
margin-top: 100vh;
|
||||
}
|
||||
|
||||
.mb-5 {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
@ -811,6 +783,10 @@ body {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
@ -835,6 +811,14 @@ body {
|
||||
height: 2.75rem;
|
||||
}
|
||||
|
||||
.h-12 {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-24 {
|
||||
height: 6rem;
|
||||
}
|
||||
@ -843,6 +827,10 @@ body {
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.h-6 {
|
||||
height: 1.5rem;
|
||||
}
|
||||
@ -871,26 +859,6 @@ body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.h-\[calc\(100vh-4rem\)\] {
|
||||
height: calc(100vh - 4rem);
|
||||
}
|
||||
|
||||
.h-5 {
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.h-12 {
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.h-16 {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.h-3 {
|
||||
height: 0.75rem;
|
||||
}
|
||||
|
||||
.\!max-h-\[501px\] {
|
||||
max-height: 501px !important;
|
||||
}
|
||||
@ -899,10 +867,6 @@ body {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.min-h-full {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
@ -911,6 +875,14 @@ body {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.w-24 {
|
||||
width: 6rem;
|
||||
}
|
||||
@ -923,6 +895,10 @@ body {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.w-6 {
|
||||
width: 1.5rem;
|
||||
}
|
||||
@ -935,6 +911,10 @@ body {
|
||||
width: 1.75rem;
|
||||
}
|
||||
|
||||
.w-8 {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.w-\[17rem\] {
|
||||
width: 17rem;
|
||||
}
|
||||
@ -947,34 +927,6 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.w-12 {
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.w-16 {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.w-8 {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.w-auto {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.w-3 {
|
||||
width: 0.75rem;
|
||||
}
|
||||
|
||||
.w-60 {
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.max-w-3xl {
|
||||
max-width: 48rem;
|
||||
}
|
||||
@ -1007,12 +959,12 @@ body {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.shrink-0 {
|
||||
flex-shrink: 0;
|
||||
.shrink {
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
.shrink-0 {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.-translate-x-1\/4 {
|
||||
@ -1077,6 +1029,21 @@ body {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.columns-2 {
|
||||
-moz-columns: 2;
|
||||
columns: 2;
|
||||
}
|
||||
|
||||
.columns-3 {
|
||||
-moz-columns: 3;
|
||||
columns: 3;
|
||||
}
|
||||
|
||||
.columns-4 {
|
||||
-moz-columns: 4;
|
||||
columns: 4;
|
||||
}
|
||||
|
||||
.grid-cols-7 {
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
@ -1093,6 +1060,10 @@ body {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.items-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.items-center {
|
||||
align-items: center;
|
||||
}
|
||||
@ -1157,12 +1128,6 @@ body {
|
||||
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.space-y-8 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-y-reverse: 0;
|
||||
margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
|
||||
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
||||
}
|
||||
|
||||
.divide-y > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-divide-y-reverse: 0;
|
||||
border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse)));
|
||||
@ -1174,14 +1139,6 @@ body {
|
||||
border-color: hsl(var(--border) / var(--tw-divide-opacity));
|
||||
}
|
||||
|
||||
.divide-gray-200\/60 > :not([hidden]) ~ :not([hidden]) {
|
||||
border-color: rgb(229 231 235 / 0.6);
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.\!overflow-hidden {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
@ -1190,10 +1147,6 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.overflow-scroll {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.\!overflow-y-auto {
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
@ -1246,6 +1199,11 @@ body {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.border-blue-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(59 130 246 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-border {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: hsl(var(--border) / var(--tw-border-opacity));
|
||||
@ -1256,9 +1214,9 @@ body {
|
||||
border-color: hsl(var(--destructive) / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-gray-300 {
|
||||
.border-foreground {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
border-color: hsl(var(--foreground) / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-input {
|
||||
@ -1274,21 +1232,6 @@ body {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.border-blue-500 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(59 130 246 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-gray-800 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(31 41 55 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-foreground {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: hsl(var(--foreground) / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.bg-background {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: hsl(var(--background) / var(--tw-bg-opacity));
|
||||
@ -1323,6 +1266,10 @@ body {
|
||||
background-color: hsl(var(--muted) / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-muted\/50 {
|
||||
background-color: hsl(var(--muted) / 0.5);
|
||||
}
|
||||
|
||||
.bg-neutral-200 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
|
||||
@ -1348,10 +1295,6 @@ body {
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-muted\/50 {
|
||||
background-color: hsl(var(--muted) / 0.5);
|
||||
}
|
||||
|
||||
.bg-opacity-50 {
|
||||
--tw-bg-opacity: 0.5;
|
||||
}
|
||||
@ -1360,10 +1303,6 @@ body {
|
||||
--tw-bg-opacity: 0.75;
|
||||
}
|
||||
|
||||
.bg-\[url\(\'\/assets\/img\/grid\.svg\'\)\] {
|
||||
background-image: url('/assets/img/grid.svg');
|
||||
}
|
||||
|
||||
.bg-gradient-to-br {
|
||||
background-image: linear-gradient(to bottom right, var(--tw-gradient-stops));
|
||||
}
|
||||
@ -1378,10 +1317,6 @@ body {
|
||||
--tw-gradient-to: #fff var(--tw-gradient-to-position);
|
||||
}
|
||||
|
||||
.bg-center {
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.fill-current {
|
||||
fill: currentColor;
|
||||
}
|
||||
@ -1412,10 +1347,6 @@ body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.p-3 {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.px-0\.5 {
|
||||
padding-left: 0.125rem;
|
||||
padding-right: 0.125rem;
|
||||
@ -1490,10 +1421,6 @@ body {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pb-8 {
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
|
||||
.pl-6 {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
@ -1506,30 +1433,6 @@ body {
|
||||
padding-top: 1.25rem;
|
||||
}
|
||||
|
||||
.pb-12 {
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.pb-32 {
|
||||
padding-bottom: 8rem;
|
||||
}
|
||||
|
||||
.pt-6 {
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
|
||||
.pt-8 {
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.pb-10 {
|
||||
padding-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.pt-10 {
|
||||
padding-top: 2.5rem;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
@ -1598,8 +1501,8 @@ body {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.uppercase {
|
||||
text-transform: uppercase;
|
||||
.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.leading-6 {
|
||||
@ -1619,6 +1522,11 @@ body {
|
||||
color: rgb(0 0 0 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-blue-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(59 130 246 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-card-foreground {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--card-foreground) / var(--tw-text-opacity));
|
||||
@ -1664,6 +1572,11 @@ body {
|
||||
color: rgb(17 24 39 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-green-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(34 197 94 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-muted-foreground {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--muted-foreground) / var(--tw-text-opacity));
|
||||
@ -1694,11 +1607,6 @@ body {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
@ -1720,14 +1628,6 @@ body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity-90 {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.opacity-70 {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.opacity-80 {
|
||||
opacity: 0.8;
|
||||
}
|
||||
@ -1764,6 +1664,10 @@ body {
|
||||
--tw-ring-offset-color: hsl(var(--background) / 1);
|
||||
}
|
||||
|
||||
.filter {
|
||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||
}
|
||||
|
||||
.backdrop-blur-sm {
|
||||
--tw-backdrop-blur: blur(4px);
|
||||
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
|
||||
@ -1806,6 +1710,10 @@ body {
|
||||
transition-duration: 100ms;
|
||||
}
|
||||
|
||||
.duration-150 {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.duration-200 {
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
@ -1814,10 +1722,6 @@ body {
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
|
||||
.duration-150 {
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.ease-in {
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
||||
}
|
||||
@ -1830,9 +1734,8 @@ body {
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.\[mask-image\:linear-gradient\(180deg\2c white\2c rgba\(255\2c 255\2c 255\2c 0\)\)\] {
|
||||
-webkit-mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
|
||||
mask-image: linear-gradient(180deg,white,rgba(255,255,255,0));
|
||||
.\[contentStart\:end\] {
|
||||
content-start: end;
|
||||
}
|
||||
|
||||
.file\:border-0::file-selector-button {
|
||||
@ -1886,6 +1789,11 @@ body {
|
||||
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-muted:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: hsl(var(--muted) / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-neutral-200:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(229 229 229 / var(--tw-bg-opacity));
|
||||
@ -1899,20 +1807,6 @@ body {
|
||||
background-color: hsl(var(--secondary) / 0.8);
|
||||
}
|
||||
|
||||
.hover\:bg-gray-50:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-accent\/50:hover {
|
||||
background-color: hsl(var(--accent) / 0.5);
|
||||
}
|
||||
|
||||
.hover\:bg-muted:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: hsl(var(--muted) / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-opacity-75:hover {
|
||||
--tw-bg-opacity: 0.75;
|
||||
}
|
||||
@ -1922,6 +1816,11 @@ body {
|
||||
color: hsl(var(--accent-foreground) / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-blue-700:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(29 78 216 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-foreground:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--foreground) / var(--tw-text-opacity));
|
||||
@ -1932,6 +1831,11 @@ body {
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-green-700:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(21 128 61 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hover\:text-neutral-500:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(115 115 115 / var(--tw-text-opacity));
|
||||
@ -1949,17 +1853,6 @@ body {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.hover\:shadow-md:hover {
|
||||
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
.focus\:border-primary:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: hsl(var(--primary) / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:outline-none:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
@ -1980,11 +1873,6 @@ body {
|
||||
--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-primary:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: hsl(var(--primary) / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
.focus\:ring-ring:focus {
|
||||
--tw-ring-opacity: 1;
|
||||
--tw-ring-color: hsl(var(--ring) / var(--tw-ring-opacity));
|
||||
@ -2026,39 +1914,14 @@ body {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:translate-x-1 {
|
||||
--tw-translate-x: 0.25rem;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:translate-x-0 {
|
||||
--tw-translate-x: 0px;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-primary {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--primary) / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-gray-700 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-gray-800 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(31 41 55 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-gray-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-accent-foreground {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--accent-foreground) / var(--tw-text-opacity));
|
||||
.group:hover .group-hover\:translate-x-1 {
|
||||
--tw-translate-x: 0.25rem;
|
||||
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:text-foreground {
|
||||
@ -2066,10 +1929,6 @@ body {
|
||||
color: hsl(var(--foreground) / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:underline {
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
|
||||
.group:hover .group-hover\:opacity-100 {
|
||||
opacity: 1;
|
||||
}
|
||||
@ -2112,11 +1971,6 @@ body {
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark\:text-neutral-400:is(.dark *) {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(163 163 163 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.dark\:file\:text-foreground:is(.dark *)::file-selector-button {
|
||||
--tw-text-opacity: 1;
|
||||
color: hsl(var(--foreground) / var(--tw-text-opacity));
|
||||
@ -2199,18 +2053,10 @@ body {
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.md\:block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.md\:flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.md\:hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.md\:h-40 {
|
||||
height: 10rem;
|
||||
}
|
||||
|
75
cmd/icongen/main.go
Normal file
75
cmd/icongen/main.go
Normal file
@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Icon struct {
|
||||
Name string `json:"name"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
svgDir := "./cmd/icongen/icons"
|
||||
icons := []Icon{}
|
||||
|
||||
err := filepath.Walk(svgDir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if filepath.Ext(path) == ".svg" {
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := strings.TrimSuffix(filepath.Base(path), ".svg")
|
||||
svgContent := extractSVGContent(string(content))
|
||||
if svgContent != "" {
|
||||
icons = append(icons, Icon{Name: name, Content: svgContent})
|
||||
} else {
|
||||
fmt.Printf("Warning: Empty content for icon %s\n", name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error walking the path %v: %v\n", svgDir, err)
|
||||
return
|
||||
}
|
||||
|
||||
generateGoCode(icons)
|
||||
}
|
||||
func extractSVGContent(svgContent string) string {
|
||||
start := strings.Index(svgContent, "<svg")
|
||||
if start == -1 {
|
||||
return ""
|
||||
}
|
||||
contentStart := strings.Index(svgContent[start:], ">") + start + 1
|
||||
end := strings.LastIndex(svgContent, "</svg>")
|
||||
if end == -1 || contentStart >= end {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(svgContent[contentStart:end])
|
||||
}
|
||||
|
||||
func generateGoCode(icons []Icon) {
|
||||
file, err := os.Create("./internals/ui/components/icon_contents.go")
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fmt.Fprintln(file, "package components")
|
||||
fmt.Fprintln(file, "\nvar iconContents = map[string]string{")
|
||||
for _, icon := range icons {
|
||||
if icon.Content != "" {
|
||||
fmt.Fprintf(file, "\t\"%s\": `%s`,\n", icon.Name, icon.Content)
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(file, "}")
|
||||
}
|
@ -28,6 +28,7 @@ func main() {
|
||||
mux.Handle("GET /docs/components/button", templ.Handler(pages.Button()))
|
||||
mux.Handle("GET /docs/components/card", templ.Handler(pages.Card()))
|
||||
mux.Handle("GET /docs/components/datepicker", templ.Handler(pages.Datepicker()))
|
||||
mux.Handle("GET /docs/components/icon", templ.Handler(pages.Icon()))
|
||||
mux.Handle("GET /docs/components/input", templ.Handler(pages.Input()))
|
||||
mux.Handle("GET /docs/components/modal", templ.Handler(pages.Modal()))
|
||||
mux.Handle("GET /docs/components/sheet", templ.Handler(pages.Sheet()))
|
||||
|
@ -53,6 +53,10 @@ var Sections = []Section{
|
||||
Text: "Datepicker",
|
||||
Href: "/docs/components/datepicker",
|
||||
},
|
||||
{
|
||||
Text: "Icon",
|
||||
Href: "/docs/components/icon",
|
||||
},
|
||||
{
|
||||
Text: "Input",
|
||||
Href: "/docs/components/input",
|
||||
|
@ -15,10 +15,10 @@ const (
|
||||
Ghost ButtonVariant = "ghost"
|
||||
Link ButtonVariant = "link"
|
||||
|
||||
Md ButtonSize = "md"
|
||||
Sm ButtonSize = "sm"
|
||||
Lg ButtonSize = "lg"
|
||||
Icon ButtonSize = "icon"
|
||||
Md ButtonSize = "md"
|
||||
Sm ButtonSize = "sm"
|
||||
Lg ButtonSize = "lg"
|
||||
ButtonIcon ButtonSize = "icon"
|
||||
)
|
||||
|
||||
// ButtonProps defines the properties for the Button component.
|
||||
@ -90,7 +90,7 @@ func getSizeClasses(size ButtonSize) string {
|
||||
return "h-9 px-3 rounded-md"
|
||||
case Lg:
|
||||
return "h-11 px-8 rounded-md"
|
||||
case Icon:
|
||||
case ButtonIcon:
|
||||
return "h-10 w-10"
|
||||
default:
|
||||
return "h-10 px-4 py-2 rounded-md"
|
||||
|
@ -2,5 +2,5 @@ package components
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *.templ
|
||||
//go:embed *.templ icon_contents.go
|
||||
var TemplFiles embed.FS
|
||||
|
99
internals/ui/components/icon.templ
Normal file
99
internals/ui/components/icon.templ
Normal file
@ -0,0 +1,99 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IconProps defines the properties for the Icon component.
|
||||
type IconProps struct {
|
||||
Name string // Name of the icon
|
||||
Size string // Size of the icon (default: "24")
|
||||
Color string // Color of the icon (default: "currentColor")
|
||||
Fill string // Fill color of the icon (default: "none")
|
||||
Stroke string // Stroke color of the icon (overrides Color if set)
|
||||
Class string // Additional CSS classes
|
||||
}
|
||||
|
||||
// getSize returns the size of the icon, defaulting to "24" if not specified.
|
||||
func getSize(size string) string {
|
||||
if size == "" {
|
||||
return "24"
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
// getColor returns the color of the icon, defaulting to "currentColor" if not specified.
|
||||
func getColor(color string) string {
|
||||
if color == "" {
|
||||
return "currentColor"
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
// getFill returns the fill color of the icon, defaulting to "none" if not specified.
|
||||
func getFill(fill string) string {
|
||||
if fill == "" {
|
||||
return "none"
|
||||
}
|
||||
return fill
|
||||
}
|
||||
|
||||
// getStroke returns the stroke color, using the specified stroke or falling back to the color.
|
||||
func getStroke(stroke, color string) string {
|
||||
if stroke != "" {
|
||||
return stroke
|
||||
}
|
||||
return getColor(color)
|
||||
}
|
||||
|
||||
// getClasses generates the class string for the icon.
|
||||
func getClasses(name, class string) string {
|
||||
classes := []string{"lucide", "lucide-" + strings.ToLower(name)}
|
||||
if class != "" {
|
||||
classes = append(classes, class)
|
||||
}
|
||||
return strings.Join(classes, " ")
|
||||
}
|
||||
|
||||
// Icon renders a Lucide icon as an SVG element.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// @components.Icon(components.IconProps{
|
||||
// Name: "user",
|
||||
// Size: "24",
|
||||
// Color: "blue",
|
||||
// Fill: "none",
|
||||
// Stroke: "currentColor",
|
||||
// Class: "my-icon-class",
|
||||
// })
|
||||
templ Icon(props IconProps) {
|
||||
if content, ok := iconContents[props.Name]; ok && content != "" {
|
||||
@templ.Raw(fmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" width="%s" height="%s" viewBox="0 0 24 24" fill="%s" stroke="%s" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="%s">%s</svg>`,
|
||||
getSize(props.Size),
|
||||
getSize(props.Size),
|
||||
getFill(props.Fill),
|
||||
getStroke(props.Stroke, props.Color),
|
||||
getClasses(props.Name, props.Class),
|
||||
content))
|
||||
} else {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={ getSize(props.Size) }
|
||||
height={ getSize(props.Size) }
|
||||
viewBox="0 0 24 24"
|
||||
fill={ getFill(props.Fill) }
|
||||
stroke={ getStroke(props.Stroke, props.Color) }
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class={ getClasses(props.Name, props.Class) }
|
||||
>
|
||||
<!-- Fallback for missing icons -->
|
||||
<rect x="0" y="0" width="24" height="24" fill="none" stroke="currentColor"></rect>
|
||||
<line x1="0" y1="0" x2="24" y2="24" stroke="currentColor"></line>
|
||||
<line x1="24" y1="0" x2="0" y2="24" stroke="currentColor"></line>
|
||||
</svg>
|
||||
}
|
||||
}
|
5996
internals/ui/components/icon_contents.go
Normal file
5996
internals/ui/components/icon_contents.go
Normal file
File diff suppressed because it is too large
Load Diff
46
internals/ui/pages/icon.templ
Normal file
46
internals/ui/pages/icon.templ
Normal file
@ -0,0 +1,46 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"github.com/axzilla/goilerplate/internals/ui/components"
|
||||
"github.com/axzilla/goilerplate/internals/ui/layouts"
|
||||
"github.com/axzilla/goilerplate/internals/ui/showcase"
|
||||
)
|
||||
|
||||
templ Icon() {
|
||||
@layouts.DocsLayout() {
|
||||
<div>
|
||||
<div class="mb-16">
|
||||
<h1 class="text-3xl font-bold mb-2">Icon</h1>
|
||||
<p class="mb-4 text-muted-foreground">
|
||||
A wrapper for Lucide Icons with optional settings for size, color, fill, stroke, and custom classes. To use this component, you'll also need the code or component from the "Icon" tab!
|
||||
</p>
|
||||
</div>
|
||||
@components.Tabs(components.TabsProps{
|
||||
Tabs: []components.Tab{
|
||||
{
|
||||
ID: "preview",
|
||||
Title: "Preview",
|
||||
Content: showcase.IconShowcase(),
|
||||
},
|
||||
{
|
||||
ID: "code",
|
||||
Title: "Code",
|
||||
Content: CodeSnippetFromEmbedded("icon.templ", "go", showcase.TemplFiles),
|
||||
},
|
||||
{
|
||||
ID: "component",
|
||||
Title: "Component",
|
||||
Content: CodeSnippetFromEmbedded("icon.templ", "go", components.TemplFiles),
|
||||
},
|
||||
{
|
||||
ID: "icons",
|
||||
Title: "Icons",
|
||||
Content: CodeSnippetFromEmbedded("icon_contents.go", "go", components.TemplFiles),
|
||||
},
|
||||
},
|
||||
TabsContainerClass: "md:w-1/2",
|
||||
ContentContainerClass: "w-full",
|
||||
})
|
||||
</div>
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ templ ButtonShowcase() {
|
||||
@components.Button(components.ButtonProps{Text: "Default"})
|
||||
@components.Button(components.ButtonProps{Text: "Small", Size: components.Sm})
|
||||
@components.Button(components.ButtonProps{Text: "Large", Size: components.Lg})
|
||||
@components.Button(components.ButtonProps{Size: components.Icon}) {
|
||||
@components.Button(components.ButtonProps{Size: components.ButtonIcon}) {
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
|
50
internals/ui/showcase/icon.templ
Normal file
50
internals/ui/showcase/icon.templ
Normal file
@ -0,0 +1,50 @@
|
||||
package showcase
|
||||
|
||||
import "github.com/axzilla/goilerplate/internals/ui/components"
|
||||
|
||||
templ IconShowcase() {
|
||||
<div class="flex justify-center items-center border rounded-md py-16 px-4">
|
||||
<div>
|
||||
<div class="mb-8">
|
||||
<h2 class="font-semibold mb-2">Basic Icons</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@components.Icon(components.IconProps{Name: "user", Size: "24"})
|
||||
@components.Icon(components.IconProps{Name: "house", Size: "24"})
|
||||
@components.Icon(components.IconProps{Name: "settings", Size: "24"})
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<h2 class="font-semibold mb-2">Colored Icons</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@components.Icon(components.IconProps{Name: "heart", Size: "24", Color: "red"})
|
||||
@components.Icon(components.IconProps{Name: "star", Size: "24", Color: "gold"})
|
||||
@components.Icon(components.IconProps{Name: "check", Size: "24", Color: "green"})
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<h2 class="font-semibold mb-2">Filled Icons</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@components.Icon(components.IconProps{Name: "circle", Size: "24", Fill: "blue", Stroke: "blue"})
|
||||
@components.Icon(components.IconProps{Name: "square", Size: "24", Fill: "purple", Stroke: "purple"})
|
||||
@components.Icon(components.IconProps{Name: "triangle", Size: "24", Fill: "orange", Stroke: "orange"})
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<h2 class="font-semibold mb-2">Different Sizes</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@components.Icon(components.IconProps{Name: "house", Size: "16"})
|
||||
@components.Icon(components.IconProps{Name: "house", Size: "24"})
|
||||
@components.Icon(components.IconProps{Name: "house", Size: "32"})
|
||||
@components.Icon(components.IconProps{Name: "house", Size: "48"})
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-8">
|
||||
<h2 class="font-semibold mb-2">Custom Classes</h2>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
@components.Icon(components.IconProps{Name: "arrow-right", Size: "24", Class: "text-blue-500 hover:text-blue-700"})
|
||||
@components.Icon(components.IconProps{Name: "arrow-left", Size: "24", Class: "text-green-500 hover:text-green-700"})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user