1+ // @ts -ignore
2+ import styleInline from './styles/app.css?inline' ;
3+ import { updateLastCloseTime } from './updateLastCloseTime' ;
4+
5+
6+ export class Banner extends HTMLElement {
7+ #banner: HTMLTemplateElement | null = null ;
8+ #_observer: MutationObserver | null = null ;
9+ lang : string = 'en' ;
10+ constructor ( ) {
11+ super ( ) ;
12+ this . attachShadow ( { mode : 'open' } ) ;
13+ this . addSponsorListener ( ) ; // 添加这行
14+ }
15+
16+ addSponsorCloseListener ( ) {
17+
18+ }
19+ addSponsorListener ( ) {
20+ this . shadowRoot ?. addEventListener ( 'click' , ( e ) => {
21+ const target = e . target as HTMLElement ;
22+ if ( target . matches ( '.sponsor-btn' ) ) {
23+ const modal = document . querySelector ( 'sponsor-modal' ) as HTMLElement ;
24+ modal . setAttribute ( 'visible' , 'true' ) ;
25+ }
26+ if ( target . matches ( '.close-icon' ) ) {
27+ updateLastCloseTime ( ) ;
28+ // 销毁整个 web component
29+ this . remove ( ) ;
30+ document . querySelector ( 'sponsor-banner' ) ?. remove ( ) ;
31+ }
32+ } ) ;
33+ }
34+
35+ getMainContent ( lang : string = 'en' ) {
36+ if ( lang === 'zh-Hans' ) {
37+ return `
38+ <div class="sponsor-message">
39+ 如果这个项目对你 <span>有帮助</span>,您可以 <button class="sponsor-btn">赞助</button> 我们来帮助项目更好地发展!
40+ </div>
41+ `
42+ }
43+ return `
44+ <div class="sponsor-message">
45+ If this project helps you <span>in any way</span>, you can <button class="sponsor-btn">sponsor</button> us to help the project grow better!
46+ </div>
47+ `
48+ }
49+
50+ connectedCallback ( ) {
51+ const style = document . createElement ( 'style' ) ;
52+ style . innerHTML = styleInline + styleInline ;
53+
54+ const rootTemplate = document . createElement ( 'template' ) ;
55+ rootTemplate . innerHTML = this . template ( ) ;
56+ this . #banner = rootTemplate
57+ this . shadowRoot ! . appendChild ( style ) ;
58+ this . shadowRoot ! . appendChild ( this . #banner. content . cloneNode ( true ) ) ;
59+ this . renderContent ( ) ;
60+ this . observeLanguage ( ) ;
61+ }
62+ template ( ) {
63+ return `
64+ <div id="vhp-widget-sponsor-banner-root" class="vhp-widget-sponsor-banner-root">
65+ <div class="vhp-widget-sponsor-thumbnail">
66+ <strong class="main">-</strong>
67+ </div>
68+ <div style="cursor: pointer;" class="close-icon">
69+ <svg width="1em" height="1em" viewBox="0 0 24 24" class="bi bi-x close-icon" fill="white" xmlns="http://www.w3.org/2000/svg">
70+ <path d="M6.225 4.811a1 1 0 00-1.414 1.414L10.586 12 4.81 17.775a1 1 0 101.414 1.414L12 13.414l5.775 5.775a1 1 0 001.414-1.414L13.414 12l5.775-5.775a1 1 0 00-1.414-1.414L12 10.586 6.225 4.81z"/>
71+ </svg>
72+ </div>
73+ </div>
74+ `
75+ }
76+
77+ renderContent ( ) {
78+ this . lang = document . documentElement . getAttribute ( 'lang' ) ?? 'en-US' ;
79+ // 修改 main 里面的内容
80+ const main = this . shadowRoot ! . querySelector ( '.main' ) as HTMLElement ;
81+ main . innerHTML = this . getMainContent ( this . lang ) ;
82+ }
83+
84+
85+ // observe html language
86+ observeLanguage ( ) {
87+ const observer = new MutationObserver ( ( mutationsList ) => {
88+ for ( const mutation of mutationsList ) {
89+ if ( mutation . type === 'attributes' && mutation . attributeName === 'lang' ) {
90+ const lang = document . documentElement . getAttribute ( 'lang' ) ;
91+ if ( lang ) {
92+ this . renderContent ( )
93+ }
94+ }
95+ }
96+ } ) ;
97+
98+ // 开始观察 HTML 元素
99+ observer . observe ( document . documentElement , {
100+ attributes : true ,
101+ attributeFilter : [ 'lang' ]
102+ } ) ;
103+
104+ // 存储 observer 以便后续清理
105+ this . #_observer = observer ;
106+ }
107+
108+
109+ disconnectedCallback ( ) {
110+ // 组件销毁时清理 observer
111+ if ( this . #_observer) {
112+ this . #_observer. disconnect ( ) ;
113+ }
114+ }
115+ }
0 commit comments