]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/site-sidebar.tsx
f4081737edf3dcf80fff5b49fbef09647722aa62
[lemmy-ui.git] / src / shared / components / home / site-sidebar.tsx
1 import { Component, linkEvent } from "inferno";
2 import { PersonView, Site, SiteAggregates } from "lemmy-js-client";
3 import { i18n } from "../../i18next";
4 import { mdToHtml } from "../../utils";
5 import { Badges } from "../common/badges";
6 import { BannerIconHeader } from "../common/banner-icon-header";
7 import { Icon } from "../common/icon";
8 import { PersonListing } from "../person/person-listing";
9
10 interface SiteSidebarProps {
11   site: Site;
12   showLocal: boolean;
13   counts?: SiteAggregates;
14   admins?: PersonView[];
15   isMobile?: boolean;
16 }
17
18 interface SiteSidebarState {
19   collapsed: boolean;
20 }
21
22 export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
23   state: SiteSidebarState = {
24     collapsed: false,
25   };
26
27   constructor(props: any, context: any) {
28     super(props, context);
29   }
30
31   render() {
32     return (
33       <div className="accordion">
34         <section
35           id="sidebarInfo"
36           className="card border-secondary mb-3 overflow-hidden"
37         >
38           <header
39             className="card-header d-flex align-items-center"
40             id="sidebarInfoHeader"
41           >
42             {this.siteName()}
43             {!this.state.collapsed && (
44               <BannerIconHeader banner={this.props.site.banner} />
45             )}
46           </header>
47
48           <div
49             id="sidebarInfoBody"
50             className="collapse show"
51             aria-labelledby="sidebarInfoHeader"
52           >
53             <div className="card-body">{this.siteInfo()}</div>
54           </div>
55         </section>
56       </div>
57     );
58   }
59
60   siteName() {
61     return (
62       <>
63         <h5 className="mb-0 d-inline">{this.props.site.name}</h5>
64         {!this.props.isMobile && (
65           <button
66             type="button"
67             className="btn btn-sm"
68             onClick={linkEvent(this, this.handleCollapseSidebar)}
69             aria-label={
70               this.state.collapsed ? i18n.t("expand") : i18n.t("collapse")
71             }
72             data-tippy-content={
73               this.state.collapsed ? i18n.t("expand") : i18n.t("collapse")
74             }
75             data-bs-toggle="collapse"
76             data-bs-target="#sidebarInfoBody"
77             aria-expanded="true"
78             aria-controls="sidebarInfoBody"
79           >
80             {this.state.collapsed ? (
81               <Icon icon="plus-square" classes="icon-inline" />
82             ) : (
83               <Icon icon="minus-square" classes="icon-inline" />
84             )}
85           </button>
86         )}
87       </>
88     );
89   }
90
91   siteInfo() {
92     const site = this.props.site;
93     return (
94       <div>
95         {site.description && <h6>{site.description}</h6>}
96         {site.sidebar && this.siteSidebar(site.sidebar)}
97         {this.props.counts && <Badges counts={this.props.counts} />}
98         {this.props.admins && this.admins(this.props.admins)}
99       </div>
100     );
101   }
102
103   siteSidebar(sidebar: string) {
104     return (
105       <div className="md-div" dangerouslySetInnerHTML={mdToHtml(sidebar)} />
106     );
107   }
108
109   admins(admins: PersonView[]) {
110     return (
111       <ul className="mt-1 list-inline small mb-0">
112         <li className="list-inline-item">{i18n.t("admins")}:</li>
113         {admins.map(av => (
114           <li key={av.person.id} className="list-inline-item">
115             <PersonListing person={av.person} />
116           </li>
117         ))}
118       </ul>
119     );
120   }
121
122   handleCollapseSidebar(i: SiteSidebar) {
123     i.setState({ collapsed: !i.state.collapsed });
124   }
125 }