
    {zi!                       d Z ddlmZ ddlZddlmZ ddlmZ  ed      ZdZ	dZ
	  G d	 d
e      ZddZddZddZ ej                  d      Z ej                  d      Z	 ddZddZddZddZddZddZddZddZd dZy)!u  design-md → satori 변수 자동 매칭.

resources/design-md/{brand}/DESIGN.md 파싱 결과를 Satori 템플릿에서 사용 가능한
디자인 토큰 dict로 변환한다. 외부 API/LLM 호출은 일절 하지 않으며, 정규식 + 키워드
매칭만 사용한다.
    )annotationsN)Path)	TypedDictz'/home/jay/workspace/resources/design-md
PretendardzPretendard, 'Noto Sans KR'c                  |    e Zd ZU ded<   ded<   ded<   ded<   ded<   ded<   ded<   ded	<   d
ed<   ded<   ded<   y)DesignTokensstrprimary	secondaryaccent
backgroundtext_primarytext_secondaryfont_display	font_bodyzdict[str, int]spacingborder_radius	list[str]shadowN)__name__
__module____qualname____annotations__     >/home/jay/workspace/skills/satori-cardnews/design_md_loader.pyr   r      s?    LNKONr   r   c                   t         | z  dz  }|j                         st        d|        |j                  d      }t	        |      }|st        d|        t        |      }|dgz   d   }|ddgz   }t        |      d	kD  r|d	   n|d   }||t        ||      t        ||      t        ||      d
|r|d   nt        t        |      d	kD  r|d	   n|r|d   nt        dddddt        |      t        |      dS )u   ``resources/design-md/{brand}/DESIGN.md`` 파싱 → satori 변수 dict 반환.

    Raises:
        FileNotFoundError: 브랜드 미존재 시
        ValueError: 필수 토큰 추출 실패 시
    	DESIGN.mdzDESIGN.md not found: zutf-8)encodingzno hex colors found for brand: #0f0f0fr   #171717   z#898989          @   smmdlgxlr
   r   r   r   r   r   r   r   r   r   r   )DESIGN_MD_ROOTexistsFileNotFoundError	read_text_extract_hex_colors
ValueError_extract_fontslen_find_accent_find_bg
_find_text_DEFAULT_FONT_find_radius_find_shadows)brandpathtext
hex_colorsfontsr
   secondary_candidatesr   s           r   load_design_mdrA   )   s    E!K/D;;="7w ?@@>>7>+D$T*J:5'BCC4 EYK'+G%I(>>+.z?Q+>$Q'DXYZD[I z40z40":t4#$)a}!$UaU1X%eAh]2Rr:%d+% r   c                 v    t         j                         sg S t        d t         j                         D              S )u2   사용 가능한 모든 brand 디렉토리 반환.c              3  z   K   | ]3  }|j                         r!|d z  j                         r|j                   5 yw)r   N)is_dirr.   name).0ps     r   	<genexpr>zlist_brands.<locals>.<genexpr>S   s4      88:1{?224 	
s   9;)r-   r.   sortediterdirr   r   r   list_brandsrK   O   s6      "	 '')  r   c                 8    ddddddt         t         ddd	d
ddg dS )uC   잘못된 design-md 입력 시 사용할 fallback 디자인 토큰.r    r!   #3ecf8e#ffffff#111111z#666666r#   r$   r%   r&   r'   8pxr,   )r8   r   r   r   fallback_tokensrQ   Z   s8     !#%"2Rr: r   z(`?(#[0-9a-fA-F]{6}(?:[0-9a-fA-F]{2})?)`?zJ`?(rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(?:\s*,\s*[\d.]+)?\s*\))`?c                    t               }g }t        j                  |       D ]H  }|j                  d      j	                         }||vs'|j                  |       |j                  |       J |S )uX   텍스트에서 #RRGGBB / #RRGGBBAA 색상 추출 (등장 순서 유지, 중복 제거).r"   )set_HEX_PATTERNfinditergrouploweraddappend)r=   seenorderedmatchcolors        r   r1   r1   w   sd    UDG&&t, "A$$&HHUONN5!	"
 Nr   c                   g }t        j                  dt         j                        }|j                  |       D ]5  }t	        |j                  d            }|s ||vs%|j                  |       7 t        j                  dt         j                        }|j                  |       D ]5  }t	        |j                  d            }|s ||vs%|j                  |       7 d| v rt        |vr|j                  dt               |xs t        gS )u   `Primary` / `font` / `typeface` 키워드 근처에서 폰트명 추출.

    Markdown 인용 부호로 감싼 폰트명을 우선 추출하며 한글 1순위 Pretendard 보장.
    zK\*\*(Primary|Monospace|Body|Display|Heading|Secondary)\*\*\s*:?\s*`([^`]+)`   z6font[- ]family\s*:?\s*`?([A-Za-z][A-Za-z0-9 ,'\"-]+)`?r"   r   r   )	recompile
IGNORECASErU   _clean_font_namerV   rY   r8   insert)r=   r?   label_rer\   	font_name	family_res         r   r3   r3      s    
 E zzV
H ""4( $$U[[^4	%/LL#$ 

TVXVcVcdI##D) $$U[[^4	%/LL#$ tU :Q&#]O#r   c                    | j                         j                  d      }|j                  d      d   j                         j                  d      }t        |      dkD  s|sy|S )uO   폰트명에서 fallback 체인을 잘라내고 첫 번째 패밀리만 반환.z`'",r   z'"(    )stripsplitr4   )rawcleanedheads      r   rc   rc      sT    iik'G==a &&(..u5D
4y2~TKr   c                X    t        |d      }|r|S t        |       dk\  r| d   S | r| d   S y)u<   `accent` / `brand` 키워드 근처 색상을 우선 반환.)r   r;   zprimary brand	highlightlink   r_   rM   _find_color_near_keywordsr4   r>   r=   keyword_colors      r   r5   r5      sC    -GM 
:!!}"~r   c                2    t        |d      }|r|S | r| d   S y)uC   `background` / `canvas` / `surface` 키워드 근처 색상 반환.)r   canvaszpage backgroundsurfacer   rN   )rw   rx   s      r   r6   r6      s-    -DM !}r   c                J    t        |d      }|r|S t        |       dk\  r| d   S y)u>   `text` / `foreground` / `body` 키워드 근처 색상 반환.)ztext primaryzprimary text
foregroundz	body textr=      rt   rO   rv   rx   s      r   r7   r7      s6    -QM 
:!!}r   c                X   t        j                  dt         j                        }|j                  |       }|r(|j	                  d      }|j                         r| d}|S t        j                  dt         j                        }|j                  |       }|r|j	                  d       dS y)u,   border-radius 토큰 추출. 기본 ``8px``.z5border[- ]radius\s*:?\s*`?(\d{1,4}(?:px|rem|em|%)?)`?r"   pxzradius[^\d`]*`?(\d{1,4})\s*px`?rP   )r`   ra   rb   searchrV   isdigit)r=   	radius_rer\   valueparen_res        r   r9   r9      s    

SUWUbUbcIT"EA==?gRLEzz<bmmLHOOD!E++a.!$$r   c                b   g }t        j                  dt         j                        }| j                         D ]r  }d|j	                         vr|j                  |      D ]I  }|j                  d      j                         }|s%||vs*t        |      dk  s9|j                  |       K t |dd S )uE   ``box-shadow`` / ``shadow`` 정의 라인에서 그림자 값 추출.z4`((?:rgba?\([^)]+\)|\d[^`]*?)\s*(?:px|em|rem)[^`]*)`r   r"      N   )
r`   ra   rb   
splitlinesrW   rU   rV   rl   r4   rY   )r=   shadows	shadow_reliner\   r   s         r   r:   r:      s    G

RTVTaTabI! &4::<'''- 	&EKKN((*Eg-#e*s2Bu%	&& 2A;r   c                .   |D cg c]  }|j                          }}| j                         D ]_  }|j                         t        fd|D              s(t        j	                  |      }|s@|j                  d      j                         c S  yc c}w )uT   키워드가 포함된 라인에서 가장 먼저 등장하는 hex 색상을 반환.c              3  &   K   | ]  }|v  
 y w)Nr   )rF   kw
line_lowers     r   rH   z,_find_color_near_keywords.<locals>.<genexpr>   s     ?2#?s   r"   N)rW   r   anyrT   r   rV   )r=   keywordsr   lowered_keywordsr   r\   r   s         @r   rw   rw      s    -56r
66! *ZZ\
?.>??##D);;q>''))*  7s   B)r;   r	   returnr   )r   r   )r   r   )r=   r	   r   r   )rn   r	   r   r	   )r>   r   r=   r	   r   r	   )r=   r	   r   r	   )r=   r	   r   ztuple[str, ...]r   z
str | None)__doc__
__future__r   r`   pathlibr   typingr   r-   r8   KOREAN_FALLBACKr   rA   rK   rQ   ra   rT   RGBA_PATTERNr1   r3   rc   r5   r6   r7   r9   r:   rw   r   r   r   <module>r      s    # 	  ?@ . S9 &#L, rzzEFrzzQ 1	$>
	"
r   