forked from ruangrupa/lumbung.space
		
	merge filter & frontpage redesign #1
@ -11,6 +11,8 @@
 | 
				
			|||||||
        {{- partial "news-ticker.html" . -}}
 | 
					        {{- partial "news-ticker.html" . -}}
 | 
				
			||||||
        {{- partial "footer.html" . -}}
 | 
					        {{- partial "footer.html" . -}}
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <script src="{{ "js/hugotagsfilter-1.2.2.min.js" | relURL}}"></script>
 | 
				
			||||||
    <script>
 | 
					    <script>
 | 
				
			||||||
        function toggleDescription(id) {
 | 
					        function toggleDescription(id) {
 | 
				
			||||||
            document.querySelector(id).classList.toggle("collapsed");
 | 
					            document.querySelector(id).classList.toggle("collapsed");
 | 
				
			||||||
@ -33,19 +35,84 @@
 | 
				
			|||||||
        if (document.querySelector('[aria-label="Previous"]')) {
 | 
					        if (document.querySelector('[aria-label="Previous"]')) {
 | 
				
			||||||
            document.querySelector('[aria-label="Previous"]').parentElement.classList.add('previous-page-link')
 | 
					            document.querySelector('[aria-label="Previous"]').parentElement.classList.add('previous-page-link')
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // for toggling submenus in mobile navigation drawer
 | 
					 | 
				
			||||||
        let submenuLinks = document.querySelectorAll('.drawer .has-submenu');
 | 
					 | 
				
			||||||
        [...submenuLinks].forEach(submenuLink => {
 | 
					 | 
				
			||||||
            submenuLink.addEventListener('click', function() {
 | 
					 | 
				
			||||||
                submenuLink.querySelector('.submenu').classList.toggle('opened')
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // footer random color
 | 
					        // footer random color
 | 
				
			||||||
        var color = ['orange','green','blue'];
 | 
					        var color = ['orange','green','blue'];
 | 
				
			||||||
		var footer = document.getElementById("footer");
 | 
							var footer = document.getElementById("footer");
 | 
				
			||||||
		var rand = Math.floor(Math.random() * color.length);
 | 
							var rand = Math.floor(Math.random() * color.length);
 | 
				
			||||||
		footer.classList.add(color[rand]);
 | 
							footer.classList.add(color[rand]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // mobile menu
 | 
				
			||||||
 | 
					        document.getElementById("menu-button").onclick=function(){
 | 
				
			||||||
 | 
					            this.classList.toggle("active");
 | 
				
			||||||
 | 
					            document.getElementById("menu").classList.toggle("active");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // mobile menu - submenu
 | 
				
			||||||
 | 
					        submenuLinks = document.querySelectorAll(".has-submenu");
 | 
				
			||||||
 | 
					        [...submenuLinks].forEach((t=>{
 | 
				
			||||||
 | 
					            t.addEventListener("click",(function(){t.querySelector(".submenu").classList.toggle("active")}))
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // mobile mainfilter
 | 
				
			||||||
 | 
					        document.getElementById("filter-link").onclick=function(){document.getElementById("filter").classList.toggle("active")};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // mobile filter
 | 
				
			||||||
 | 
					        filterButtons=document.querySelectorAll(".filter-buttons");
 | 
				
			||||||
 | 
					        [...filterButtons].forEach((t=>{
 | 
				
			||||||
 | 
					            t.addEventListener("click",(function(){t.querySelector(".filter-buttons-dropdown").classList.toggle("active");
 | 
				
			||||||
 | 
					            t.querySelector(".filter-by").classList.toggle("active")}))
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // load more cards
 | 
				
			||||||
 | 
					        document.getElementById("load-more").onclick=function(){
 | 
				
			||||||
 | 
					            document.getElementById('load-more-paginator').click();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // filter config
 | 
				
			||||||
 | 
					        var htfConfig = {
 | 
				
			||||||
 | 
					          filters: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name: 'tags',
 | 
				
			||||||
 | 
					              prefix: 'tag-',
 | 
				
			||||||
 | 
					              buttonClass: 'tag-button',
 | 
				
			||||||
 | 
					              allSelector: '#selectAllTags',
 | 
				
			||||||
 | 
					              attrName: 'data-tags',
 | 
				
			||||||
 | 
					              selectedPrefix: 'stags-',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name: 'section',
 | 
				
			||||||
 | 
					              prefix: 'sect-',
 | 
				
			||||||
 | 
					              buttonClass: 'sect-button',
 | 
				
			||||||
 | 
					              allSelector: '#selectAllSections',
 | 
				
			||||||
 | 
					              attrName: 'data-section',
 | 
				
			||||||
 | 
					              selectedPrefix: 'ssect-',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name: 'contributors',
 | 
				
			||||||
 | 
					              prefix: 'cont-',
 | 
				
			||||||
 | 
					              buttonClass: 'cont-button',
 | 
				
			||||||
 | 
					              allSelector: '#selectAllContributors',
 | 
				
			||||||
 | 
					              attrName: 'data-contributors',
 | 
				
			||||||
 | 
					              selectedPrefix: 'scont-',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              name: 'sources',
 | 
				
			||||||
 | 
					              prefix: 'src-',
 | 
				
			||||||
 | 
					              buttonClass: 'src-button',
 | 
				
			||||||
 | 
					              allSelector: '#selectAllSources',
 | 
				
			||||||
 | 
					              attrName: 'data-sources',
 | 
				
			||||||
 | 
					              selectedPrefix: 'ssrc-',
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					          showItemClass: "show-item",
 | 
				
			||||||
 | 
					          filterItemClass: "filter-item",
 | 
				
			||||||
 | 
					          activeButtonClass: "active",
 | 
				
			||||||
 | 
					          counterSelector: "selectedItemCount",
 | 
				
			||||||
 | 
					          populateCount: true,
 | 
				
			||||||
 | 
					          setDisabledButtonClass: "disable-button"
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					        var htf = new HugoTagsFilter(htfConfig);
 | 
				
			||||||
    </script>
 | 
					    </script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,40 +1,48 @@
 | 
				
			|||||||
{{ define "main" }}
 | 
					{{ define "main" }}
 | 
				
			||||||
  <main>
 | 
					  <main>
 | 
				
			||||||
    <section class='entries'>
 | 
					    <section class='entries'>
 | 
				
			||||||
      <div class="h-feed">
 | 
					      <div class="h-feed">    
 | 
				
			||||||
        {{ range where (.Paginator 13).Pages "Params.hidden" "ne" "true" }}
 | 
					        {{ $range := where .Pages "Params.hidden" "ne" "true" }}
 | 
				
			||||||
 | 
					        {{ $paginator := .Paginate $range }}
 | 
				
			||||||
 | 
					        {{ $pageSize := $paginator.PageSize }}
 | 
				
			||||||
 | 
					        {{ $totalPostsToShow := mul $paginator.PageNumber $pageSize }}
 | 
				
			||||||
 | 
					        {{ range $index, $el := (first $totalPostsToShow $range) }}
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        <div class='post {{if eq .Section "tv"}}tv{{ end }}' {{ if eq $index (sub $totalPostsToShow $pageSize) }}id="newpage"{{ end }}>
 | 
				
			||||||
          {{if eq .Section "tv"}}
 | 
					          {{if eq .Section "tv"}}
 | 
				
			||||||
            {{- partial "video_box.html" . -}}
 | 
					              {{- partial "video_box.html" . -}}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else if eq .Section "events" }}
 | 
					            {{ else if eq .Section "events" }}
 | 
				
			||||||
            {{- partial "partials/calendar_card.html" . -}}
 | 
					              {{- partial "partials/calendar_card.html" . -}}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else if eq .Section "shouts" }}
 | 
					            {{ else if eq .Section "shouts" }}
 | 
				
			||||||
              {{ if in .Params.sources "pen.lumbung.space" }}
 | 
					                {{ if in .Params.sources "pen.lumbung.space" }}
 | 
				
			||||||
                {{- partial "pen_card.html" . -}}
 | 
					                  {{- partial "partials/pen_card.html" . -}}
 | 
				
			||||||
              {{ else }}
 | 
					                {{ else }}
 | 
				
			||||||
                {{- partial "shout_card.html" . -}}
 | 
					                  {{- partial "partials/shout_card.html" . -}}
 | 
				
			||||||
              {{ end }}
 | 
					                {{ end }}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else if eq .Section "social" }}
 | 
					            {{ else if eq .Section "social" }}
 | 
				
			||||||
            {{- partial "social_card.html" . -}}
 | 
					              {{- partial "partials/social_card.html" . -}}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else if eq .Section "publications"}}
 | 
					            {{ else if eq .Section "publications"}}
 | 
				
			||||||
            {{- partial "book_card.html" . -}}
 | 
					              {{- partial "partials/book_card.html" . -}}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else if eq .Section "sounds"}}
 | 
					            {{ else if eq .Section "sounds"}}
 | 
				
			||||||
            {{- partial "sounds_card.html" . -}}
 | 
					              {{- partial "sounds_card.html" . -}}
 | 
				
			||||||
        
 | 
					
 | 
				
			||||||
          {{ else }}
 | 
					            {{ else }}
 | 
				
			||||||
            {{- partial "card.html" . -}}
 | 
					              {{- partial "card.html" . -}}
 | 
				
			||||||
        
 | 
					            {{ end }}
 | 
				
			||||||
          {{ end }}  
 | 
					        </div>
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
      <nav class="pagination-container">
 | 
					      <div class="page-nav">
 | 
				
			||||||
        {{ template "_internal/pagination.html" . }}
 | 
					        {{ if and (gt $paginator.TotalPages 1) ($paginator.HasNext) }}
 | 
				
			||||||
      </nav>
 | 
					          <a id="load-more-paginator" class="nextpage" href="{{ $paginator.Next.URL }}#newpage">load more</a>
 | 
				
			||||||
 | 
					        {{ end }}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </section>
 | 
				
			||||||
  </main>
 | 
					  </main>
 | 
				
			||||||
{{ end }}
 | 
					{{ end }}
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
{{ define "main" }}
 | 
					{{ define "main" }}
 | 
				
			||||||
 | 
					 | 
				
			||||||
  <main>
 | 
					  <main>
 | 
				
			||||||
    <section class='entries'>
 | 
					    <section class='entries'>
 | 
				
			||||||
      
 | 
					      
 | 
				
			||||||
@ -42,9 +41,8 @@
 | 
				
			|||||||
      
 | 
					      
 | 
				
			||||||
      <div class="page-nav">
 | 
					      <div class="page-nav">
 | 
				
			||||||
        {{ if and (gt $paginator.TotalPages 1) ($paginator.HasNext) }}
 | 
					        {{ if and (gt $paginator.TotalPages 1) ($paginator.HasNext) }}
 | 
				
			||||||
          <a class="nextpage" href="{{ $paginator.Next.URL }}#newpage">Next Page</a>
 | 
					          <a id="load-more-paginator" class="nextpage" href="{{ $paginator.Next.URL }}#newpage">load more</a>
 | 
				
			||||||
        {{ end }}
 | 
					        {{ end }}
 | 
				
			||||||
        <a class="nextpage load-all-trigger" href="{{ $paginator.Last.URL }}">Load all</a>
 | 
					 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div class="lumbung-radio-player" onclick="window.open('https://lumbungradio.stationofcommons.org', 'Lumbung Radio', 'height=800,width=450')">
 | 
					      <div class="lumbung-radio-player" onclick="window.open('https://lumbungradio.stationofcommons.org', 'Lumbung Radio', 'height=800,width=450')">
 | 
				
			||||||
@ -54,8 +52,6 @@
 | 
				
			|||||||
        <span>lumbung radio</span>
 | 
					        <span>lumbung radio</span>
 | 
				
			||||||
        <img src="/img/lumbung-radio-logo.png" alt="" height="30">
 | 
					        <img src="/img/lumbung-radio-logo.png" alt="" height="30">
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      
 | 
					 | 
				
			||||||
          
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    </section>
 | 
					    </section>
 | 
				
			||||||
  </main>
 | 
					  </main>
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,7 @@
 | 
				
			|||||||
	<div class="filter-container">
 | 
						<div class="filter-container">
 | 
				
			||||||
		<div class="filter-information">
 | 
							<div class="filter-information">
 | 
				
			||||||
			<div><span id="selectedItemCount"></span> Cards</div>
 | 
								<div><span id="selectedItemCount"></span> Cards</div>
 | 
				
			||||||
 | 
								<div id="load-more">load more cards</div>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
		<div class="filter-buttons-container">
 | 
							<div class="filter-buttons-container">
 | 
				
			||||||
			<div class="filter-buttons">
 | 
								<div class="filter-buttons">
 | 
				
			||||||
 | 
				
			|||||||
@ -18,9 +18,4 @@
 | 
				
			|||||||
	<div class="f-credits">
 | 
						<div class="f-credits">
 | 
				
			||||||
		<a href="https://panduan.lumbung.space/share/684ea8a2-bc47-4111-acf2-f88a200b640f">Imprint</a> - <a href="https://panduan.lumbung.space/share/8a742222-2561-4d67-a9f1-6c7c4fe8bead">Privacy Policy</a> - <a href="https://panduan.lumbung.space/share/507566f6-6b7e-402e-bfd4-034feebdcba6">Glossary</a> - <a href="https://panduan.lumbung.space/share/ef6f6638-856d-4c9a-ab89-d82af567aba4">Terms of Use</a>
 | 
							<a href="https://panduan.lumbung.space/share/684ea8a2-bc47-4111-acf2-f88a200b640f">Imprint</a> - <a href="https://panduan.lumbung.space/share/8a742222-2561-4d67-a9f1-6c7c4fe8bead">Privacy Policy</a> - <a href="https://panduan.lumbung.space/share/507566f6-6b7e-402e-bfd4-034feebdcba6">Glossary</a> - <a href="https://panduan.lumbung.space/share/ef6f6638-856d-4c9a-ab89-d82af567aba4">Terms of Use</a>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</footer>
 | 
					</footer>
 | 
				
			||||||
 | 
					 | 
				
			||||||
<script src="{{ "js/hugotagsfilter-1.2.2.min.js" | relURL}}"></script>
 | 
					 | 
				
			||||||
<script>
 | 
					 | 
				
			||||||
document.getElementById("menu-button").onclick=function(){this.classList.toggle("active"),document.getElementById("menu").classList.toggle("active")},submenuLinks=document.querySelectorAll(".has-submenu"),[...submenuLinks].forEach((t=>{t.addEventListener("click",(function(){t.querySelector(".submenu").classList.toggle("active")}))})),filterButtons=document.querySelectorAll(".filter-buttons"),[...filterButtons].forEach((t=>{t.addEventListener("click",(function(){t.querySelector(".filter-buttons-dropdown").classList.toggle("active"),t.querySelector(".filter-by").classList.toggle("active")}))})),document.getElementById("filter-link").onclick=function(){document.getElementById("filter").classList.toggle("active")};var htfConfig={filters:[{name:"tags",prefix:"tag-",buttonClass:"tag-button",allSelector:"#selectAllTags",attrName:"data-tags",selectedPrefix:"stags-"},{name:"section",prefix:"sect-",buttonClass:"sect-button",allSelector:"#selectAllSections",attrName:"data-section",selectedPrefix:"ssect-"},{name:"contributors",prefix:"cont-",buttonClass:"cont-button",allSelector:"#selectAllContributors",attrName:"data-contributors",selectedPrefix:"scont-"},{name:"sources",prefix:"src-",buttonClass:"src-button",allSelector:"#selectAllSources",attrName:"data-sources",selectedPrefix:"ssrc-"}],showItemClass:"show-item",filterItemClass:"filter-item",activeButtonClass:"active",counterSelector:"selectedItemCount",populateCount:!0,setDisabledButtonClass:"disable-button"},htf=new HugoTagsFilter(htfConfig);
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
@ -7,7 +7,7 @@
 | 
				
			|||||||
</header>
 | 
					</header>
 | 
				
			||||||
<div class="menu-row">
 | 
					<div class="menu-row">
 | 
				
			||||||
    <nav id="menu" class="menu">
 | 
					    <nav id="menu" class="menu">
 | 
				
			||||||
        <img class="menu-dot" src="/img/black-dot.svg" alt="black dot">
 | 
					        <a href="#"><img class="menu-dot" src="/img/black-dot.svg" alt="black dot"></a>
 | 
				
			||||||
        <ul>
 | 
					        <ul>
 | 
				
			||||||
            <li><a href="/timeline/">harvest</a></li>
 | 
					            <li><a href="/timeline/">harvest</a></li>
 | 
				
			||||||
            {{/*  <li><a href="/about/">about</a></li>  */}}
 | 
					            {{/*  <li><a href="/about/">about</a></li>  */}}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
<div class='social card {{ range .Params.tags }}{{ if or (eq . "lumbungkios") (eq . "lumbunggallery")}}{{.}}{{ end }}{{ end }} filter-item' data-section="{{ .Section }}" data-sources='{{- partial "data/sources.html" . -}}' data-contributors='{{- partial "data/contributors.html" . -}}' data-tags='{{- partial "data/tags.html" . -}}'>
 | 
					<div class='social card {{ range .Params.tags }}{{ if or (eq . "lumbungkios") (eq . "lumbungkiosproducts")}}lumbungkios{{else if  (eq . "lumbunggallery")}}{{.}}{{ end }}{{ end }} filter-item' data-section="{{ .Section }}" data-sources='{{- partial "data/sources.html" . -}}' data-contributors='{{- partial "data/contributors.html" . -}}' data-tags='{{- partial "data/tags.html" . -}}'>
 | 
				
			||||||
  <article class="h-entry social">
 | 
					  <article class="h-entry social">
 | 
				
			||||||
    <header>
 | 
					    <header>
 | 
				
			||||||
      {{ $postPermalink := .Permalink}}
 | 
					      {{ $postPermalink := .Permalink}}
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/*Main Stuff*/
 | 
					/*Main Stuff*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					html {
 | 
				
			||||||
 | 
					    scroll-behavior: smooth;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
body {
 | 
					body {
 | 
				
			||||||
    font-size: 21px;
 | 
					    font-size: 21px;
 | 
				
			||||||
    font-family: Gudea, sans-serif;
 | 
					    font-family: Gudea, sans-serif;
 | 
				
			||||||
@ -127,15 +132,15 @@ a {
 | 
				
			|||||||
    max-width: 400px;
 | 
					    max-width: 400px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.card:nth-child(even) {
 | 
					.post:nth-child(even) {
 | 
				
			||||||
    transform: rotate(-1deg);
 | 
					    transform: rotate(-1deg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.card:nth-child(odd) {
 | 
					.post:nth-child(odd) {
 | 
				
			||||||
    transform: rotate(1deg);
 | 
					    transform: rotate(1deg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.card:nth-child(5) {
 | 
					.post:nth-child(5) {
 | 
				
			||||||
    transform: rotate(2deg);
 | 
					    transform: rotate(2deg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1178,6 +1183,12 @@ li.page-item:after {
 | 
				
			|||||||
    width: 15%;
 | 
					    width: 15%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#load-more {
 | 
				
			||||||
 | 
					    font-size: 0.8rem;
 | 
				
			||||||
 | 
					    text-decoration: underline;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.filter-buttons-container {
 | 
					.filter-buttons-container {
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
@ -2117,6 +2128,9 @@ input:checked + label + .description {
 | 
				
			|||||||
    .filter-information {
 | 
					    .filter-information {
 | 
				
			||||||
        width: 100%;
 | 
					        width: 100%;
 | 
				
			||||||
        margin-bottom: 15px;
 | 
					        margin-bottom: 15px;
 | 
				
			||||||
 | 
					        display: flex;
 | 
				
			||||||
 | 
					        align-items: center;
 | 
				
			||||||
 | 
					        justify-content: space-between;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .filter-buttons-container {
 | 
					    .filter-buttons-container {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user