Răsfoiți Sursa

Studio app icons: Stories, Drupal, Elasticsearch, Facebook, GitHub, LinkedIn

Stories gets the flattened Lucide image-play glyph on green. The five
integrations carry their thesvg.org marks on the white plate.

The artwork mode of the generator now applies transform attributes when
it samples shapes for the bounds and the shadow (the Facebook and GitHub
sources are drawn through matrix and scale transforms), and keeps group
attributes that change how shapes draw while dropping ids and classes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Andrey Yasko 1 lună în urmă
părinte
comite
bf57635643

Fișier diff suprimat deoarece este prea mare
+ 6 - 25
modules/boonex/drupal_connect/template/images/icons/std-icon.svg


Fișier diff suprimat deoarece este prea mare
+ 5 - 18
modules/boonex/elasticsearch/template/images/icons/std-icon.svg


Fișier diff suprimat deoarece este prea mare
+ 5 - 7
modules/boonex/facebook_connect/template/images/icons/std-icon.svg


Fișier diff suprimat deoarece este prea mare
+ 0 - 5
modules/boonex/github/template/images/icons/std-icon.svg


+ 10 - 24
modules/boonex/linkedin_connect/template/images/icons/std-icon.svg

@@ -1,30 +1,16 @@
-<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_1006_8400)">
-<path d="M160 0C281.326 0 320 38.6737 320 160C320 281.326 281.326 320 160 320C38.6736 320 0 281.326 0 160C0 38.6737 38.6736 0 160 0Z" fill="url(#paint0_linear_1006_8400)"/>
-<path d="M160 2C220.573 2 259.85 11.6833 284.083 35.9168C308.317 60.1504 318 99.4272 318 160C318 220.573 308.317 259.85 284.083 284.083C259.85 308.317 220.573 318 160 318C99.4272 318 60.1504 308.317 35.9168 284.083C11.6833 259.85 2 220.573 2 160C2 99.4272 11.6833 60.1504 35.9168 35.9168C60.1504 11.6833 99.4272 2 160 2Z" stroke="#0F172A" stroke-opacity="0.2" stroke-width="4"/>
-<g clip-path="url(#clip1_1006_8400)">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M160 50C243.412 50 270 76.5882 270 160C270 243.412 243.412 270 160 270C143.995 270 130.082 269.021 118.048 266.85C112.267 265.807 109.048 259.651 109.617 253.804C109.878 251.12 110 248.19 110 245C110 218.46 101.54 210 75 210C71.8096 210 68.8804 210.122 66.1958 210.383C60.3487 210.952 54.1935 207.733 53.1503 201.952C50.9789 189.918 50 176.005 50 160C50 76.5882 76.5881 50 160 50ZM196.398 210H219V163.57C219 143.925 207.864 134.426 192.309 134.426C176.747 134.426 170.198 146.545 170.198 146.545V136.667H148.417V210H170.198V171.504C170.198 161.19 174.946 155.052 184.034 155.052C192.388 155.052 196.398 160.95 196.398 171.504V210ZM109 113.532C109 121.005 115.012 127.064 122.431 127.064C129.851 127.064 135.859 121.005 135.859 113.532C135.859 106.059 129.851 100 122.431 100C115.012 100 109 106.059 109 113.532ZM133.897 210H111.184V136.667H133.897V210Z" fill="url(#paint1_linear_1006_8400)"/>
-<path d="M75 220C93.9572 220 100 226.043 100 245C100 263.957 93.9572 270 75 270C56.0428 270 50 263.957 50 245C50 226.043 56.0428 220 75 220Z" fill="url(#paint2_linear_1006_8400)"/>
+<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="80" height="80" fill="url(#paint0_linear_linkedin)"/>
+<g transform="translate(15.000 15.000) scale(0.19531)">
+<svg:path xmlns:svg="http://www.w3.org/2000/svg" d="M218.123 218.127h-37.931v-59.403c0-14.165-.253-32.4-19.728-32.4-19.756 0-22.779 15.434-22.779 31.369v60.43h-37.93V95.967h36.413v16.694h.51a39.907 39.907 0 0 1 35.928-19.733c38.445 0 45.533 25.288 45.533 58.186l-.016 67.013ZM56.955 79.27c-12.157.002-22.014-9.852-22.016-22.009-.002-12.157 9.851-22.014 22.008-22.016 12.157-.003 22.014 9.851 22.016 22.008A22.013 22.013 0 0 1 56.955 79.27m18.966 138.858H37.95V95.967h37.97v122.16ZM237.033.018H18.89C8.58-.098.125 8.161-.001 18.471v219.053c.122 10.315 8.576 18.582 18.89 18.474h218.144c10.336.128 18.823-8.139 18.966-18.474V18.454c-.147-10.33-8.635-18.588-18.966-18.453" fill="#0A66C2" />
 </g>
+<g transform="translate(15.000 16.000) scale(0.19531)">
+<path fill-rule="evenodd" fill="black" fill-opacity="0.1" d="M237.03 0.02 L18.18 0.02 L17.24 0.07 L16.32 0.16 L15.39 0.31 L14.48 0.49 L13.58 0.72 L12.68 1.00 L11.80 1.32 L10.95 1.69 L10.11 2.09 L9.28 2.55 L8.50 3.03 L7.72 3.57 L6.98 4.14 L6.26 4.74 L5.58 5.38 L4.92 6.06 L4.37 6.69 L3.84 7.34 L3.35 8.02 L2.88 8.73 L2.44 9.45 L2.04 10.20 L1.67 10.96 L1.34 11.73 L1.05 12.51 L0.79 13.31 L0.56 14.13 L0.38 14.94 L0.22 15.78 L0.11 16.62 L0.04 17.47 L0.00 18.30 L-0.00 237.52 L0.03 238.49 L0.12 239.44 L0.25 240.37 L0.43 241.31 L0.66 242.24 L0.93 243.14 L1.24 244.02 L1.61 244.90 L2.02 245.76 L2.48 246.61 L2.97 247.42 L3.51 248.21 L4.08 248.96 L4.69 249.69 L5.35 250.39 L6.03 251.06 L6.68 251.63 L7.33 252.15 L8.01 252.65 L8.72 253.12 L9.44 253.55 L10.18 253.95 L10.95 254.32 L11.71 254.65 L12.50 254.95 L13.29 255.21 L14.11 255.43 L14.93 255.62 L15.77 255.77 L16.60 255.88 L17.45 255.96 L18.28 255.99 L237.35 256.00 L238.31 255.97 L239.28 255.89 L240.23 255.77 L241.17 255.59 L242.09 255.37 L243.01 255.10 L243.92 254.78 L244.82 254.42 L245.69 254.00 L246.54 253.55 L247.36 253.05 L248.16 252.51 L248.92 251.93 L249.67 251.30 L250.39 250.64 L251.05 249.95 L251.62 249.30 L252.15 248.65 L252.65 247.97 L253.11 247.26 L253.55 246.54 L253.95 245.79 L254.32 245.03 L254.65 244.26 L254.95 243.48 L255.21 242.68 L255.43 241.86 L255.62 241.03 L255.77 240.19 L255.89 239.36 L255.96 238.51 L256.00 237.67 L256.00 18.45 L255.97 17.66 L255.90 16.77 L255.79 15.89 L255.63 15.00 L255.43 14.13 L255.20 13.28 L254.92 12.42 L254.59 11.59 L254.23 10.77 L253.84 9.97 L253.39 9.18 L252.92 8.43 L252.41 7.69 L251.86 6.98 L251.28 6.29 L250.67 5.63 L250.02 5.01 L249.35 4.41 L248.65 3.85 L247.92 3.32 L247.18 2.83 L246.41 2.37 L245.62 1.96 L244.80 1.57 L243.97 1.23 L243.13 0.93 L242.27 0.67 L241.39 0.45 L240.51 0.28 L239.60 0.14 L238.68 0.05 L237.66 0.00 L237.03 0.00 Z"/>
 </g>
 <defs>
-<linearGradient id="paint0_linear_1006_8400" x1="160" y1="0" x2="160" y2="320" gradientUnits="userSpaceOnUse">
-<stop stop-color="#F8FAFC"/>
-<stop offset="1" stop-color="#E2E8F0"/>
+<linearGradient id="paint0_linear_linkedin" x1="40" y1="0" x2="40" y2="80" gradientUnits="userSpaceOnUse">
+<stop stop-color="#F3F4F6"/>
+<stop offset="1" stop-color="#E5E7EB"/>
 </linearGradient>
-<linearGradient id="paint1_linear_1006_8400" x1="160" y1="50" x2="160" y2="270" gradientUnits="userSpaceOnUse">
-<stop stop-color="#60A5FA"/>
-<stop offset="1" stop-color="#2563EB"/>
-</linearGradient>
-<linearGradient id="paint2_linear_1006_8400" x1="75" y1="220" x2="75" y2="270" gradientUnits="userSpaceOnUse">
-<stop stop-color="#FB923C"/>
-<stop offset="1" stop-color="#EA580C"/>
-</linearGradient>
-<clipPath id="clip0_1006_8400">
-<rect width="320" height="320" fill="white"/>
-</clipPath>
-<clipPath id="clip1_1006_8400">
-<rect width="240" height="240" fill="white" transform="translate(40 40)"/>
-</clipPath>
+
 </defs>
 </svg>

Fișier diff suprimat deoarece este prea mare
+ 2 - 7
modules/boonex/stories/template/images/icons/std-icon.svg


+ 49 - 4
scripts/studio_icon_from_lucide.py

@@ -52,6 +52,7 @@ ICONS = [
     ('modules/boonex/ads/template/images/icons/std-icon.svg', 'ads', 'green', 'scan-square', 80),
     ('modules/boonex/workspaces/template/images/icons/std-icon.svg', 'workspaces', 'red', 'target', 80),
     ('modules/boonex/videos/template/images/icons/std-icon.svg', 'videos', 'green', 'tv-minimal-play', 80),
+    ('modules/boonex/stories/template/images/icons/std-icon.svg', 'stories', 'green', 'image-play', 80),
 ]
 
 # Brand artwork on the white plate: the source SVG's shapes are copied as they are (fills, gradients), scaled to
@@ -70,6 +71,11 @@ ART = [
     # ('modules/boonex/mailchimp/template/images/icons/std-icon.svg', 'mailchimp', '<thesvg.org mailchimp default.svg>', (), ('#FFE01B', '#EAC900'), '#241C15'),
     # ('modules/boonex/stripe_connect/template/images/icons/std-icon.svg', 'stripe_connect', '<thesvg.org stripe default.svg>', (), ('#6F68FF', '#4F48D9'), 'white', 52),
     # ('modules/boonex/snipcart/template/images/icons/std-icon.svg', 'snipcart', '<snipcart.com logo, wordmark path id=wordmark>', ('wordmark',), ('#475569', '#1E293B'), '#FACC15'),
+    # ('modules/boonex/drupal_connect/template/images/icons/std-icon.svg', 'drupal', '<thesvg.org drupal default.svg>', ()),
+    # ('modules/boonex/elasticsearch/template/images/icons/std-icon.svg', 'elasticsearch', '<thesvg.org elasticsearch default.svg>', ()),
+    # ('modules/boonex/facebook_connect/template/images/icons/std-icon.svg', 'facebook', '<thesvg.org facebook default.svg>', ()),
+    # ('modules/boonex/github/template/images/icons/std-icon.svg', 'github', '<thesvg.org github default.svg>', ()),
+    # ('modules/boonex/linkedin_connect/template/images/icons/std-icon.svg', 'linkedin', '<thesvg.org linkedin default.svg>', ()),
 ]
 
 STROKE = 2.0      # Lucide stroke width, in its 24-unit space
@@ -186,6 +192,35 @@ def icon(uid, plate, d, size):
 '''
 
 
+def parse_transform(t):
+    """An SVG transform attribute as a 3x3 affine matrix (row-major, last row 0 0 1)."""
+    m = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0]
+    for name, args in re.findall(r'(matrix|translate|scale|rotate)\s*\(([^)]*)\)', t or ''):
+        v = [float(x) for x in re.findall(r'-?\d*\.?\d+(?:e-?\d+)?', args)]
+        if name == 'matrix':
+            n = [v[0], v[2], v[4], v[1], v[3], v[5]]
+        elif name == 'translate':
+            n = [1, 0, v[0], 0, 1, v[1] if len(v) > 1 else 0]
+        elif name == 'scale':
+            n = [v[0], 0, 0, 0, v[1] if len(v) > 1 else v[0], 0]
+        else:
+            a = math.radians(v[0])
+            n = [math.cos(a), -math.sin(a), 0, math.sin(a), math.cos(a), 0]
+        m = [m[0] * n[0] + m[1] * n[3], m[0] * n[1] + m[1] * n[4], m[0] * n[2] + m[1] * n[5] + m[2],
+             m[3] * n[0] + m[4] * n[3], m[3] * n[1] + m[4] * n[4], m[3] * n[2] + m[4] * n[5] + m[5]]
+    return m
+
+
+def compose(a, b):
+    """a then b applied to a point means point -> a(b(point)): the parent's matrix times the child's."""
+    return [a[0] * b[0] + a[1] * b[3], a[0] * b[1] + a[1] * b[4], a[0] * b[2] + a[1] * b[5] + a[2],
+            a[3] * b[0] + a[4] * b[3], a[3] * b[1] + a[4] * b[4], a[3] * b[2] + a[4] * b[5] + a[5]]
+
+
+def apply_transform(m, pts):
+    return [(m[0] * x + m[1] * y + m[2], m[3] * x + m[4] * y + m[5]) for x, y in pts]
+
+
 def art_icon(uid, src, skip, plate='white', fill=None, width=ART_WIDTH, size=80):
     """The artwork scaled to `width` and centred on the plate, its united outline as the shadow. `fill` recolours every
     shape (a one-colour mark or wordmark on its brand plate); otherwise a fill set on the source's root is passed down."""
@@ -205,12 +240,14 @@ def art_icon(uid, src, skip, plate='white', fill=None, width=ART_WIDTH, size=80)
     root_fill = fill or root.attrib.get('fill')
     xs, ys = [], []
 
-    def walk(el):
+    def walk(el, ctm):
         tag = el.tag.split('}')[-1]
-        if tag in ('style', 'defs'):
+        if tag in ('style', 'defs', 'title', 'desc'):
             return
         if el.attrib.get('class') in skip or el.attrib.get('id') in skip:
             return
+        if el.attrib.get('transform'):
+            ctm = parse_transform(el.attrib['transform']) if ctm is None else compose(ctm, parse_transform(el.attrib['transform']))
         d = element_to_d(el)
         if d:
             for cls in el.attrib.pop('class', '').split():
@@ -221,17 +258,25 @@ def art_icon(uid, src, skip, plate='white', fill=None, width=ART_WIDTH, size=80)
             elif root_fill and 'fill' not in el.attrib:
                 el.set('fill', root_fill)
             for pts in sample(d):
+                if ctm:
+                    pts = apply_transform(ctm, pts)
                 if len(pts) > 2:
                     polys.append(Polygon(pts).buffer(0))
                     xs.extend(x for x, _ in pts)
                     ys.extend(y for _, y in pts)
             inner.append(ET.tostring(el, encoding='unicode'))
             return
+        # a group keeps the attributes that change how its shapes draw (transform, clip, opacity, paint); ids and classes go
+        attrs = {k: v for k, v in el.attrib.items() if k not in ('id', 'class')}
+        if attrs:
+            inner.append('<g ' + ' '.join(f'{k}="{v}"' for k, v in attrs.items()) + '>')
         for c in el:
-            walk(c)
+            walk(c, ctm)
+        if attrs:
+            inner.append('</g>')
 
     for el in list(root):
-        walk(el)
+        walk(el, None)
     x0, x1, y0, y1 = min(xs), max(xs), min(ys), max(ys)
     s = width / (x1 - x0)
     tx, ty = (size - (x1 - x0) * s) / 2 - x0 * s, (size - (y1 - y0) * s) / 2 - y0 * s

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff