Blocks

Header

The header is a primary navigation component that provides quick access to user settings, notifications, and search functionality. It is designed to ensure an intuitive and accessible user experience across all pages.

Introduction

The header enhances navigation by keeping essential controls accessible. It includes user profile options, notifications, layout settings, and a global search bar for quick content discovery.

Code Structure

The .header-container class wraps all header components.

View Mode
                          
HTML
<div class="modal fade search-modal" id="search-modal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body padding-sm text-center"> <div class="input-group search-wrapper"><span class="spinner" id="search-loader"></span><span class="tticon-search input-group-text" id="search-icon"></span> <input class="form-control" id="modal-search-field" type="search" placeholder="بحث في لوحة التحكم.." autocomplete="off" /><span class="close-shortcut">esc</span> </div> <div class="search-results" id="search-results"> <p class="search-results-placeholder" id="search-placeholder">اكتب كلمة البحث في الأعلى.</p> <p class="search-loading" id="search-loading">جاري تحميل البيانات...</p> </div> <ul class="seach-footer"> <li><span class="tticon-hash shortcut-icon"></span><span class="shortcut-label">مفتاحية</span></li> <li><span class="tticon-arrow-up shortcut-icon"></span><span class="tticon-arrow-down shortcut-icon"></span><span class="shortcut-label">الانتقال</span></li> <li><span class="shortcut-text">enter</span><span class="shortcut-label">تنفيذ</span></li> </ul> </div> </div> </div> </div> <header class="header"> <div class="container-fluid"> <div class="header__content"> <button class="header__search-button" type="button" data-bs-toggle="modal" data-bs-target="#search-modal"> <span class="tticon-search search-icon"> </span><span class="search-placeholder">ما الذي تبحث عنه؟</span><span class="search-shortcut">/</span></button> <ul class="header__menu"> <li class="header__menu-item"><a class="header__menu-link" href="layout-01.html"> <span class="tticon-grid-vertical header__menu-icon"></span>تنسيق المنصة</a></li> <li class="header__menu-item"><a class="header__menu-link" href="setting-01.html"> <span class="tticon-gear header__menu-icon"></span>الإعدادات</a></li> </ul> <hr class="header__separator" /> <ul class="header__icon-buttons"> <li class="header__icon-button-item"><a class="header__icon-button-link" href="inbox.html"> <span class="tticon-inbox header__icon-button-icon"></span><span class="header__icon-button-number">4</span></a> </li> <li class="header__icon-button-item"> <div class="dropdown header__notification-menu js-dropdown-overlay"> <button class="header__icon-button-link dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <span class="tticon-lightning header__icon-button-icon"></span><span class="header__icon-button-number">2</span></button><span class="dropdown-menu dropdown-menu-start dropdown-menu-md-center mt-3"><span class="dropdown-header"> <span class="dropdown-title">التنبيهات</span></span> <ul class="nav nav-justified"> <li class="nav-item" role="presentation"> <button class="nav-link js-stop-propagation active" id="read-notifications-tab" data-bs-toggle="pill" data-bs-target="#read-notifications" type="button" role="tab" aria-controls="read-notifications" aria-selected="true">غير مقروءة<span class="nav-link-number">5</span></button> </li> <li class="nav-item" role="presentation"> <button class="nav-link js-stop-propagation" id="unread-notifications-tab" data-bs-toggle="pill" data-bs-target="#unread-notifications" type="button" role="tab" aria-controls="unread-notifications" aria-selected="true">مقروءة<span class="nav-link-number">45</span></button> </li> </ul> <div class="tab-content" id="notifications-tabContent"> <div class="tab-pane fade show active" id="read-notifications" role="tabpanel" aria-labelledby="read-notifications-tab" tabindex="0"> <ul class="header__notification-list"> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-doc-plus-fill header__notification-icon header__notification-icon--primary"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تم اضافة طلب رقم </span><span class="notification-text-white text-english">2410003 </span><span> لـ </span><span class="notification-text-white">“خدمة تحليل البيانات”</span><span>من خلال أحمد الحمشري.</span><span class="text-warning">معرفة المزيد</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">16 </span><span>دقيقة</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-sticker-heart-fill header__notification-icon header__notification-icon--success"></span><span class="header__notification-content"> <span class="header__notification-text"><span>لا تنسى تحديث تفاصيل </span><span class="notification-text-white">حملتك الجديدة.</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">47 </span><span>دقيقة</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-cloud-download-fill header__notification-icon"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تمت عملية </span><span class="notification-text-white">“استخراج البيانات” </span><span>بنجاح</span></span><span class="header__notification-time"><span class="text-english">14/02/2024</span></span></span></a></li> </ul> <button class="mark-all-read-btn">جعل التنبيهات مقروءة</button> </div> <div class="tab-pane fade" id="unread-notifications" role="tabpanel" aria-labelledby="unread-notifications-tab" tabindex="0"> <ul class="header__notification-list header__notification-list--read"> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-doc-plus-fill header__notification-icon header__notification-icon--primary"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تم اضافة طلب رقم </span><span class="notification-text-white text-english">2410003 </span><span> لـ </span><span class="notification-text-white">“خدمة تحليل البيانات”</span><span>من خلال أحمد الحمشري.</span><span class="text-warning">معرفة المزيد</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">16 </span><span>دقيقة</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-sticker-heart-fill header__notification-icon header__notification-icon--success"></span><span class="header__notification-content"> <span class="header__notification-text"><span>لا تنسى تحديث تفاصيل </span><span class="notification-text-white">حملتك الجديدة.</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">47 </span><span>دقيقة</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-user-check-fill header__notification-icon header__notification-icon--primary"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تم تسجيل </span><span class="notification-text-white">حساب مستفيد </span><span>جديد </span><span class="notification-text-white">أسامة الغامدي. </span><span class="text-warning">معرفة المزيد</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">2 </span><span>ساعة</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-cloud-refresh-fill header__notification-icon header__notification-icon--warning"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تم تحديث حالة حملة </span><span class="notification-text-white">“حملة علاج المرضى المحتاجين” </span><span>إلى حالة </span><span class="notification-text-white">معلقة</span></span><span class="header__notification-time"><span>منذ </span><span class="text-english">3 </span><span>ساعات</span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-shield-user-fill header__notification-icon header__notification-icon--success"></span><span class="header__notification-content"> <span class="header__notification-text"><span>الرجاء تحديث </span><span class="notification-text-white">“معلومات حسابك” </span><span>لضمان استمرارية الخدمة.</span></span><span class="header__notification-time"><span class="text-english">10/01/2024 </span></span></span></a></li> <li class="header__notification-item"><a class="header__notification-link" href="#!"> <span class="tticon-cloud-download-fill header__notification-icon"></span><span class="header__notification-content"> <span class="header__notification-text"><span>تمت عملية </span><span class="notification-text-white">“استخراج البيانات” </span><span>بنجاح</span></span><span class="header__notification-time"><span class="text-english">14/02/2024</span></span></span></a></li> </ul> </div> </div> </span> </div> </li> <li class="header__icon-button-item"> <button class="header__icon-button-link" id="js-theme-toggle-btn"><span class="tticon-moon-fill header__icon-button-icon d-light-inline"></span><span class="tticon-sun-fill header__icon-button-icon d-dark-inline"></span></button> </li> </ul> <div class="dropdown header__account-dropdown-menu js-dropdown-overlay"> <button class="dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"><svg xmlns="http://www.w3.org/2000/svg" class="account-avatar default-state" width="32" height="35" viewBox="0 0 32 35" fill="none"> <g filter="url(#filter0_d_5079_3248)"> <mask id="path-1-inside-1_5079_3248" fill="white"> <path fill-rule="evenodd" clip-rule="evenodd" d="M0 9.68396V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9.68396L0 9.68396Z" /> </mask> <path fill-rule="evenodd" clip-rule="evenodd" d="M0 9.68396V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9.68396L0 9.68396Z" fill="url(#paint0_linear_5079_3248)" /> <path d="M0 9.68396L-1.06066 8.6233L-1.5 9.06264V9.68396H0ZM9.68396 0V-1.5H9.06264L8.6233 -1.06066L9.68396 0ZM1.5 23V9.68396H-1.5V23H1.5ZM9 30.5C4.85786 30.5 1.5 27.1421 1.5 23H-1.5C-1.5 28.799 3.20101 33.5 9 33.5V30.5ZM23 30.5H9V33.5H23V30.5ZM30.5 23C30.5 27.1421 27.1421 30.5 23 30.5V33.5C28.799 33.5 33.5 28.799 33.5 23H30.5ZM30.5 9V23H33.5V9H30.5ZM23 1.5C27.1421 1.5 30.5 4.85786 30.5 9H33.5C33.5 3.20101 28.799 -1.5 23 -1.5V1.5ZM9.68396 1.5H23V-1.5H9.68396V1.5ZM8.6233 -1.06066L-1.06066 8.6233L1.06066 10.7446L10.7446 1.06066L8.6233 -1.06066Z" fill="white" fill-opacity="0.34" mask="url(#path-1-inside-1_5079_3248)" /> </g> <g filter="url(#filter1_di_5079_3248)"> <path d="M9.08014 14.5058C9.84013 16.9754 11.6502 18.9946 14.0561 19.7258C16.4215 20.4453 18.9151 19.7022 20.7498 18.0416C21.7797 17.1099 22.4924 15.8456 22.9219 14.5034C23.2367 13.5268 22.5599 12.3073 21.611 12.0809C20.5722 11.8332 19.6368 12.4111 19.3018 13.4561C19.2523 13.6094 19.1984 13.7627 19.1399 13.9113C19.2029 13.7533 19.2658 13.5976 19.3288 13.4396C19.1849 13.7887 19.0162 14.126 18.8161 14.4444C18.7667 14.5223 18.715 14.5978 18.6632 14.6732C18.4609 14.9704 18.9668 14.2935 18.7374 14.5671C18.6228 14.7063 18.5058 14.8431 18.3822 14.9728C18.2585 15.1025 18.1258 15.2205 17.9954 15.3408C17.7593 15.5554 18.3777 15.0577 18.1011 15.2559C18.0292 15.3078 17.9595 15.3597 17.8875 15.4092C17.5997 15.6073 17.2962 15.7724 16.9791 15.914L17.4288 15.7158C17.0038 15.8951 16.5676 16.0201 16.1157 16.0862C16.2821 16.0626 16.4485 16.039 16.6148 16.0154C16.1854 16.072 15.7559 16.0744 15.3265 16.0201L15.8256 16.0909C15.3624 16.0248 14.9172 15.8975 14.4833 15.7111C14.6339 15.7772 14.7823 15.8432 14.933 15.9093C14.6272 15.7701 14.3349 15.605 14.0583 15.4115C13.9864 15.3597 13.9167 15.3078 13.8447 15.2535C13.6648 15.1191 14.2112 15.5696 13.9841 15.3644C13.8514 15.2441 13.721 15.1214 13.5974 14.9917C13.4827 14.8714 13.3748 14.7464 13.2713 14.6143C13.0712 14.3619 13.3118 14.711 13.3725 14.7582C13.3118 14.7133 13.2623 14.5978 13.2174 14.5293C13.015 14.2133 12.8464 13.8783 12.7025 13.5316C12.7654 13.6896 12.8284 13.8453 12.8913 14.0033C12.8216 13.8241 12.7564 13.6424 12.7002 13.4584C12.3989 12.4795 11.3848 11.7459 10.391 12.0832C9.45788 12.3993 8.75635 13.4561 9.08014 14.5058Z" fill="white" /> </g> <defs> <filter id="filter0_d_5079_3248" x="0" y="0" width="32" height="34.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="2.5" /> <feComposite in2="hardAlpha" operator="out" /> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.45 0" /> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5079_3248" /> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5079_3248" result="shape" /> </filter> <filter id="filter1_di_5079_3248" x="9" y="12" width="14" height="10" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="1.2" /> <feComposite in2="hardAlpha" operator="out" /> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" /> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5079_3248" /> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5079_3248" result="shape" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="2" /> <feGaussianBlur stdDeviation="1.5" /> <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" /> <feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.733333 0 0 0 0 0.341176 0 0 0 0.2 0" /> <feBlend mode="normal" in2="shape" result="effect2_innerShadow_5079_3248" /> </filter> <linearGradient id="paint0_linear_5079_3248" x1="14.5" y1="-1.72295e-08" x2="14.5" y2="32" gradientUnits="userSpaceOnUse"> <stop stop-color="var(--tt-header-secondary-100)" /> <stop offset="1" stop-color="var(--tt-header-secondary-300)" /> </linearGradient> </defs> </svg> <svg xmlns="http://www.w3.org/2000/svg" class="account-avatar hover-state" width="32" height="35" viewBox="0 0 32 35" fill="none"> <g filter="url(#filter0_d_5082_3833)"> <mask id="path-1-inside-1_5082_3833" fill="white"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9 0C4.02944 0 0 4.02944 0 9V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9Z" /> </mask> <path fill-rule="evenodd" clip-rule="evenodd" d="M9 0C4.02944 0 0 4.02944 0 9V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9Z" fill="url(#paint0_linear_5082_3833)" /> <path d="M1.5 9C1.5 4.85786 4.85786 1.5 9 1.5V-1.5C3.20101 -1.5 -1.5 3.20101 -1.5 9H1.5ZM1.5 23V9H-1.5V23H1.5ZM9 30.5C4.85786 30.5 1.5 27.1421 1.5 23H-1.5C-1.5 28.799 3.20101 33.5 9 33.5V30.5ZM23 30.5H9V33.5H23V30.5ZM30.5 23C30.5 27.1421 27.1421 30.5 23 30.5V33.5C28.799 33.5 33.5 28.799 33.5 23H30.5ZM30.5 9V23H33.5V9H30.5ZM23 1.5C27.1421 1.5 30.5 4.85786 30.5 9H33.5C33.5 3.20101 28.799 -1.5 23 -1.5V1.5ZM9 1.5H23V-1.5H9V1.5Z" fill="white" fill-opacity="0.34" mask="url(#path-1-inside-1_5082_3833)" /> </g> <g filter="url(#filter1_di_5082_3833)"> <path d="M11.4954 12.7242C11.444 11.5439 12.4216 10.5765 13.6013 10.6402L21.3848 11.0604C23.1175 11.154 23.9172 13.2585 22.6838 14.4791L15.2391 21.8464C14.0057 23.0669 11.9096 22.2453 11.8342 20.5117L11.4954 12.7242Z" fill="white" /> </g> <defs> <filter id="filter0_d_5082_3833" x="0" y="0" width="32" height="34.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="2.5" /> <feComposite in2="hardAlpha" operator="out" /> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.45 0" /> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5082_3833" /> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5082_3833" result="shape" /> </filter> <filter id="filter1_di_5082_3833" x="11.4934" y="10.6372" width="11.7869" height="13.791" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="1.2" /> <feComposite in2="hardAlpha" operator="out" /> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" /> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5082_3833" /> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_5082_3833" result="shape" /> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha" /> <feOffset dy="2" /> <feGaussianBlur stdDeviation="1.5" /> <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" /> <feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.733333 0 0 0 0 0.341176 0 0 0 0.2 0" /> <feBlend mode="normal" in2="shape" result="effect2_innerShadow_5082_3833" /> </filter> <linearGradient id="paint0_linear_5082_3833" x1="14.5" y1="-1.72295e-08" x2="14.5" y2="32" gradientUnits="userSpaceOnUse"> <stop stop-color="var(--tt-header-secondary-100)" /> <stop offset="1" stop-color="var(--tt-header-secondary-300)" /> </linearGradient> </defs> </svg><span class="account-info"><span class="account-title">مدير المنصة</span><span class="account-desc">[email protected]</span></span><span class="tticon-chevron-sm-down account-menu-icon"></span> </button> <ul class="dropdown-menu dropdown-menu-end mt-3"> <li class="dropdown-user"> <span class="dropdown-username">مدير المنصة</span><span class="dropdown-email">[email protected]</span></li> <li><a class="dropdown-item" href="account-01.html"><span class="tticon-user dropdown-icon"></span>تفاصيل الحساب</a></li> <li><a class="dropdown-item" href="#!"><span class="tticon-refresh-dots dropdown-icon"></span>تحديثات المنصة!</a></li> <li><a class="dropdown-item" href="#!"><span class="tticon-question-circle dropdown-icon"></span>مساعدة</a> </li> <li><a class="dropdown-item" href="#!"><span class="tticon-shopping-bag dropdown-icon"></span>متجر التحول التقني</a></li> <li><a class="dropdown-item" href="#!"><span class="tticon-shield-info dropdown-icon"></span>دليل الاستخدام</a></li> <li><a class="dropdown-btn" href="#!">تسجيل الخروج</a></li> </ul> </div> </div> </div> </header>
<!-- Usage Example -->
<DefaultHeader />
 
<!-- Vue Component Code Block -->
<template>
  <SearchModal v-model="showSearch" />
  <header class="header">
    <div class="container-fluid">
      <div class="header__content">
        <button class="header__search-button" @click="showSearch = true">
          <span class="tticon-search search-icon"> </span
          ><span class="search-placeholder">ما الذي تبحث عنه؟</span
          ><span class="search-shortcut">/</span>
        </button>
        <HeaderNav :routes="routes" />
        <hr class="header__separator" />
        <ul class="header__icon-buttons">
          <HeaderIconButton icon="tticon-inbox" number="4" route="inbox.html" />
          <li class="header__icon-button-item">
            <HeaderNotification />
          </li>
          <li class="header__icon-button-item">
            <button class="header__icon-button-link" @click="toggleTheme">
              <span class="tticon-moon-fill header__icon-button-icon d-light-inline"></span
              ><span class="tticon-sun-fill header__icon-button-icon d-dark-inline"></span>
            </button>
          </li>
        </ul>
        <HeaderAccountArea username="ahmet" email="[email protected]" :routes="userRoutes" />
      </div>
    </div>
  </header>
</template>
 
<script setup>
import { ref, onMounted } from 'vue'
import HeaderAccountArea from './HeaderAccountArea.vue'
import HeaderIconButton from './HeaderIconButton.vue'
import HeaderNav from './HeaderNav.vue'
import HeaderNotification from './HeaderNotification.vue'
import SearchModal from './HeaderSearchModal.vue'
 
// Search Modal state
const showSearch = ref(false)
 
// Theme logic
const theme = ref('light')
 
function getCurrentTheme() {
  const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  return localStorage.getItem('tts.theme') || systemTheme
}
 
function loadTheme(t) {
  document.documentElement.setAttribute('color-scheme', t)
  theme.value = t
}
 
function toggleTheme() {
  const newTheme = theme.value === 'light' ? 'dark' : 'light'
  localStorage.setItem('tts.theme', newTheme)
  loadTheme(newTheme)
}
 
onMounted(() => {
  loadTheme(getCurrentTheme())
})
 
// Navigation & user routes
const routes = ref([
  { to: 'layout-01.html', icon: 'tticon-grid-vertical', label: 'تنسيق المنصة' },
  { to: 'setting-01.html', icon: 'tticon-gear', label: 'الإعدادات' },
])
 
const userRoutes = ref([
  { to: 'layout-01.html', icon: 'tticon-user', label: 'تفاصيل الحساب' },
  { to: 'setting-01.html', icon: 'tticon-refresh-dots', label: 'تحديثات المنصة' },
  { to: 'layout-01.html', icon: 'tticon-question-circle', label: 'مساعدة' },
  { to: 'setting-01.html', icon: 'tticon-shopping-bag', label: 'متجر التحول التقني' },
  { to: 'setting-01.html', icon: 'tticon-shield-info', label: 'دليل الاستخدام' },
])
</script>
 
<!-- HeaderAccountArea Component Code Block -->
<template>
  <div class="dropdown header__account-dropdown-menu js-dropdown-overlay">
    <button class="dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        class="account-avatar default-state"
        width="32"
        height="35"
        viewBox="0 0 32 35"
        fill="none"
      >
        <g filter="url(#filter0_d_5079_3248)">
          <mask id="path-1-inside-1_5079_3248" fill="white">
            <path
              fill-rule="evenodd"
              clip-rule="evenodd"
              d="M0 9.68396V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9.68396L0 9.68396Z"
            />
          </mask>
          <path
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M0 9.68396V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9.68396L0 9.68396Z"
            fill="url(#paint0_linear_5079_3248)"
          />
          <path
            d="M0 9.68396L-1.06066 8.6233L-1.5 9.06264V9.68396H0ZM9.68396 0V-1.5H9.06264L8.6233 -1.06066L9.68396 0ZM1.5 23V9.68396H-1.5V23H1.5ZM9 30.5C4.85786 30.5 1.5 27.1421 1.5 23H-1.5C-1.5 28.799 3.20101 33.5 9 33.5V30.5ZM23 30.5H9V33.5H23V30.5ZM30.5 23C30.5 27.1421 27.1421 30.5 23 30.5V33.5C28.799 33.5 33.5 28.799 33.5 23H30.5ZM30.5 9V23H33.5V9H30.5ZM23 1.5C27.1421 1.5 30.5 4.85786 30.5 9H33.5C33.5 3.20101 28.799 -1.5 23 -1.5V1.5ZM9.68396 1.5H23V-1.5H9.68396V1.5ZM8.6233 -1.06066L-1.06066 8.6233L1.06066 10.7446L10.7446 1.06066L8.6233 -1.06066Z"
            fill="white"
            fill-opacity="0.34"
            mask="url(#path-1-inside-1_5079_3248)"
          />
        </g>
        <g filter="url(#filter1_di_5079_3248)">
          <path
            d="M9.08014 14.5058C9.84013 16.9754 11.6502 18.9946 14.0561 19.7258C16.4215 20.4453 18.9151 19.7022 20.7498 18.0416C21.7797 17.1099 22.4924 15.8456 22.9219 14.5034C23.2367 13.5268 22.5599 12.3073 21.611 12.0809C20.5722 11.8332 19.6368 12.4111 19.3018 13.4561C19.2523 13.6094 19.1984 13.7627 19.1399 13.9113C19.2029 13.7533 19.2658 13.5976 19.3288 13.4396C19.1849 13.7887 19.0162 14.126 18.8161 14.4444C18.7667 14.5223 18.715 14.5978 18.6632 14.6732C18.4609 14.9704 18.9668 14.2935 18.7374 14.5671C18.6228 14.7063 18.5058 14.8431 18.3822 14.9728C18.2585 15.1025 18.1258 15.2205 17.9954 15.3408C17.7593 15.5554 18.3777 15.0577 18.1011 15.2559C18.0292 15.3078 17.9595 15.3597 17.8875 15.4092C17.5997 15.6073 17.2962 15.7724 16.9791 15.914L17.4288 15.7158C17.0038 15.8951 16.5676 16.0201 16.1157 16.0862C16.2821 16.0626 16.4485 16.039 16.6148 16.0154C16.1854 16.072 15.7559 16.0744 15.3265 16.0201L15.8256 16.0909C15.3624 16.0248 14.9172 15.8975 14.4833 15.7111C14.6339 15.7772 14.7823 15.8432 14.933 15.9093C14.6272 15.7701 14.3349 15.605 14.0583 15.4115C13.9864 15.3597 13.9167 15.3078 13.8447 15.2535C13.6648 15.1191 14.2112 15.5696 13.9841 15.3644C13.8514 15.2441 13.721 15.1214 13.5974 14.9917C13.4827 14.8714 13.3748 14.7464 13.2713 14.6143C13.0712 14.3619 13.3118 14.711 13.3725 14.7582C13.3118 14.7133 13.2623 14.5978 13.2174 14.5293C13.015 14.2133 12.8464 13.8783 12.7025 13.5316C12.7654 13.6896 12.8284 13.8453 12.8913 14.0033C12.8216 13.8241 12.7564 13.6424 12.7002 13.4584C12.3989 12.4795 11.3848 11.7459 10.391 12.0832C9.45788 12.3993 8.75635 13.4561 9.08014 14.5058Z"
            fill="white"
          />
        </g>
        <defs>
          <filter
            id="filter0_d_5079_3248"
            x="0"
            y="0"
            width="32"
            height="34.5"
            filterUnits="userSpaceOnUse"
            color-interpolation-filters="sRGB"
          >
            <feFlood flood-opacity="0" result="BackgroundImageFix" />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="2.5" />
            <feComposite in2="hardAlpha" operator="out" />
            <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.45 0" />
            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5079_3248" />
            <feBlend
              mode="normal"
              in="SourceGraphic"
              in2="effect1_dropShadow_5079_3248"
              result="shape"
            />
          </filter>
          <filter
            id="filter1_di_5079_3248"
            x="9"
            y="12"
            width="14"
            height="10"
            filterUnits="userSpaceOnUse"
            color-interpolation-filters="sRGB"
          >
            <feFlood flood-opacity="0" result="BackgroundImageFix" />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="1.2" />
            <feComposite in2="hardAlpha" operator="out" />
            <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5079_3248" />
            <feBlend
              mode="normal"
              in="SourceGraphic"
              in2="effect1_dropShadow_5079_3248"
              result="shape"
            />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="2" />
            <feGaussianBlur stdDeviation="1.5" />
            <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
            <feColorMatrix
              type="matrix"
              values="0 0 0 0 1 0 0 0 0 0.733333 0 0 0 0 0.341176 0 0 0 0.2 0"
            />
            <feBlend mode="normal" in2="shape" result="effect2_innerShadow_5079_3248" />
          </filter>
          <linearGradient
            id="paint0_linear_5079_3248"
            x1="14.5"
            y1="-1.72295e-08"
            x2="14.5"
            y2="32"
            gradientUnits="userSpaceOnUse"
          >
            <stop stop-color="var(--tt-header-secondary-100)" />
            <stop offset="1" stop-color="var(--tt-header-secondary-300)" />
          </linearGradient>
        </defs>
      </svg>
      <svg
        xmlns="http://www.w3.org/2000/svg"
        class="account-avatar hover-state"
        width="32"
        height="35"
        viewBox="0 0 32 35"
        fill="none"
      >
        <g filter="url(#filter0_d_5082_3833)">
          <mask id="path-1-inside-1_5082_3833" fill="white">
            <path
              fill-rule="evenodd"
              clip-rule="evenodd"
              d="M9 0C4.02944 0 0 4.02944 0 9V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9Z"
            />
          </mask>
          <path
            fill-rule="evenodd"
            clip-rule="evenodd"
            d="M9 0C4.02944 0 0 4.02944 0 9V23C0 27.9706 4.02944 32 9 32H23C27.9706 32 32 27.9706 32 23V9C32 4.02944 27.9706 0 23 0H9Z"
            fill="url(#paint0_linear_5082_3833)"
          />
          <path
            d="M1.5 9C1.5 4.85786 4.85786 1.5 9 1.5V-1.5C3.20101 -1.5 -1.5 3.20101 -1.5 9H1.5ZM1.5 23V9H-1.5V23H1.5ZM9 30.5C4.85786 30.5 1.5 27.1421 1.5 23H-1.5C-1.5 28.799 3.20101 33.5 9 33.5V30.5ZM23 30.5H9V33.5H23V30.5ZM30.5 23C30.5 27.1421 27.1421 30.5 23 30.5V33.5C28.799 33.5 33.5 28.799 33.5 23H30.5ZM30.5 9V23H33.5V9H30.5ZM23 1.5C27.1421 1.5 30.5 4.85786 30.5 9H33.5C33.5 3.20101 28.799 -1.5 23 -1.5V1.5ZM9 1.5H23V-1.5H9V1.5Z"
            fill="white"
            fill-opacity="0.34"
            mask="url(#path-1-inside-1_5082_3833)"
          />
        </g>
        <g filter="url(#filter1_di_5082_3833)">
          <path
            d="M11.4954 12.7242C11.444 11.5439 12.4216 10.5765 13.6013 10.6402L21.3848 11.0604C23.1175 11.154 23.9172 13.2585 22.6838 14.4791L15.2391 21.8464C14.0057 23.0669 11.9096 22.2453 11.8342 20.5117L11.4954 12.7242Z"
            fill="white"
          />
        </g>
        <defs>
          <filter
            id="filter0_d_5082_3833"
            x="0"
            y="0"
            width="32"
            height="34.5"
            filterUnits="userSpaceOnUse"
            color-interpolation-filters="sRGB"
          >
            <feFlood flood-opacity="0" result="BackgroundImageFix" />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="2.5" />
            <feComposite in2="hardAlpha" operator="out" />
            <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.45 0" />
            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5082_3833" />
            <feBlend
              mode="normal"
              in="SourceGraphic"
              in2="effect1_dropShadow_5082_3833"
              result="shape"
            />
          </filter>
          <filter
            id="filter1_di_5082_3833"
            x="11.4934"
            y="10.6372"
            width="11.7869"
            height="13.791"
            filterUnits="userSpaceOnUse"
            color-interpolation-filters="sRGB"
          >
            <feFlood flood-opacity="0" result="BackgroundImageFix" />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="1.2" />
            <feComposite in2="hardAlpha" operator="out" />
            <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" />
            <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_5082_3833" />
            <feBlend
              mode="normal"
              in="SourceGraphic"
              in2="effect1_dropShadow_5082_3833"
              result="shape"
            />
            <feColorMatrix
              in="SourceAlpha"
              type="matrix"
              values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
              result="hardAlpha"
            />
            <feOffset dy="2" />
            <feGaussianBlur stdDeviation="1.5" />
            <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
            <feColorMatrix
              type="matrix"
              values="0 0 0 0 1 0 0 0 0 0.733333 0 0 0 0 0.341176 0 0 0 0.2 0"
            />
            <feBlend mode="normal" in2="shape" result="effect2_innerShadow_5082_3833" />
          </filter>
          <linearGradient
            id="paint0_linear_5082_3833"
            x1="14.5"
            y1="-1.72295e-08"
            x2="14.5"
            y2="32"
            gradientUnits="userSpaceOnUse"
          >
            <stop stop-color="var(--tt-header-secondary-100)" />
            <stop offset="1" stop-color="var(--tt-header-secondary-300)" />
          </linearGradient>
        </defs>
      </svg>
      <span class="account-info"
        ><span class="account-title">{{ username }}</span
        ><span class="account-desc">{{ email }}</span></span
      ><span class="tticon-chevron-sm-down account-menu-icon"></span>
    </button>
    <ul class="dropdown-menu dropdown-menu-end mt-3">
      <li class="dropdown-user">
        <span class="dropdown-username">{{ username }}</span
        ><span class="dropdown-email">{{ email }}</span>
      </li>
      <li v-for="(item, index) in routes" :key="index">
        <router-link class="dropdown-item" :to="item.to">
          <span class="dropdown-icon" :class="item.icon"></span>{{ item.label }}
        </router-link>
      </li>
      <li><a class="dropdown-btn" href="javascript:" @click="doLogout()">تسجيل الخروج</a></li>
    </ul>
  </div>
</template>
 
<script setup>
defineProps({
  username: String,
  email: String,
  routes: Array,
})
 
const doLogout = () => {
  alert('تم تسجيل الخروج بنجاح!')
}
</script>
 
<!-- HeaderIconButton Component Code Block -->
<template>
  <li class="header__icon-button-item">
    <router-link class="header__icon-button-link" :to="route">
      <span class="header__icon-button-icon" :class="icon"></span>
      <span class="header__icon-button-number">{{ number }}</span>
    </router-link>
  </li>
</template>
 
<script setup>
defineProps({
  icon: String,
  number: String,
  route: Object,
})
</script>
 
<!-- HeaderNav Component Code Block -->
<template>
  <ul class="header__menu">
    <li v-for="(route, index) in routes" :key="index" class="header__menu-item">
      <router-link class="header__menu-link" :to="route.to">
        <span :class="['header__menu-icon', route.icon]"></span>
        {{ route.label }}
      </router-link>
    </li>
  </ul>
</template>
 
<script setup>
defineProps({
  routes: {
    type: Array,
    default: () => [],
  },
})
</script>
 
<!-- HeaderNotification Component Code Block -->
<template>
  <div class="dropdown header__notification-menu" :class="{ show: dropdownOpen }">
    <button class="header__icon-button-link dropdown-toggle" type="button" @click="toggleDropdown">
      <span class="tticon-lightning header__icon-button-icon"></span>
      <span class="header__icon-button-number">{{ unreadCount }}</span>
    </button>
 
    <span
      class="dropdown-menu dropdown-menu-start dropdown-menu-md-center mt-3"
      :class="{ show: dropdownOpen }"
    >
      <span class="dropdown-header">
        <span class="dropdown-title">التنبيهات</span>
      </span>
 
      <ul class="nav nav-justified">
        <li class="nav-item" role="presentation">
          <button
            class="nav-link js-stop-propagation"
            :class="{ active: activeTab === 'unread' }"
            @click="activeTab = 'unread'"
          >
            غير مقروءة
            <span class="nav-link-number">{{ unread.length }}</span>
          </button>
        </li>
        <li class="nav-item" role="presentation">
          <button
            class="nav-link js-stop-propagation"
            :class="{ active: activeTab === 'read' }"
            @click="activeTab = 'read'"
          >
            مقروءة
            <span class="nav-link-number">{{ read.length }}</span>
          </button>
        </li>
      </ul>
 
      <div class="tab-content" id="notifications-tabContent">
        <div
          v-if="activeTab === 'unread'"
          class="tab-pane fade show active"
          id="read-notifications"
          role="tabpanel"
          tabindex="0"
        >
          <ul class="header__notification-list">
            <HeaderNotificationItem
              v-for="(notif, index) in unread"
              :key="'unread-' + index"
              :notification="notif"
            />
          </ul>
          <button class="mark-all-read-btn" @click="markAllAsRead">جعل التنبيهات مقروءة</button>
        </div>
 
        <div
          v-if="activeTab === 'read'"
          class="tab-pane fade show active"
          id="unread-notifications"
          role="tabpanel"
          tabindex="0"
        >
          <ul class="header__notification-list header__notification-list--read">
            <HeaderNotificationItem
              v-for="(notif, index) in read"
              :key="'read-' + index"
              :notification="notif"
            />
          </ul>
        </div>
      </div>
    </span>
  </div>
</template>
 
<script setup>
import { ref, computed } from 'vue'
import HeaderNotificationItem from './HeaderNotificationItem.vue'
 
const dropdownOpen = ref(false)
const activeTab = ref('unread')
 
const unread = ref([
  {
    icon: 'tticon-doc-plus-fill',
    color: 'primary',
    message: 'تم اضافة طلب رقم 2410003 لـ “خدمة تحليل البيانات” من خلال أحمد الحمشري.',
    extra: 'معرفة المزيد',
    time: 'منذ 16 دقيقة',
  },
  {
    icon: 'tticon-sticker-heart-fill',
    color: 'success',
    message: 'لا تنسى تحديث تفاصيل حملتك الجديدة.',
    time: 'منذ 47 دقيقة',
  },
  {
    icon: 'tticon-cloud-download-fill',
    color: '',
    message: 'تمت عملية “استخراج البيانات” بنجاح',
    time: '14/02/2024',
  },
])
 
const read = ref([
  {
    icon: 'tticon-doc-plus-fill',
    color: 'primary',
    message: 'تم اضافة طلب رقم 2410003 لـ “خدمة تحليل البيانات” من خلال أحمد الحمشري.',
    extra: 'معرفة المزيد',
    time: 'منذ 16 دقيقة',
  },
  {
    icon: 'tticon-sticker-heart-fill',
    color: 'success',
    message: 'لا تنسى تحديث تفاصيل حملتك الجديدة.',
    time: 'منذ 47 دقيقة',
  },
  {
    icon: 'tticon-user-check-fill',
    color: 'primary',
    message: 'تم تسجيل حساب مستفيد جديد أسامة الغامدي.',
    extra: 'معرفة المزيد',
    time: 'منذ 2 ساعة',
  },
  {
    icon: 'tticon-cloud-refresh-fill',
    color: 'warning',
    message: 'تم تحديث حالة حملة “حملة علاج المرضى المحتاجين” إلى حالة معلقة',
    time: 'منذ 3 ساعات',
  },
  {
    icon: 'tticon-shield-user-fill',
    color: 'success',
    message: 'الرجاء تحديث “معلومات حسابك” لضمان استمرارية الخدمة.',
    time: '10/01/2024',
  },
  {
    icon: 'tticon-cloud-download-fill',
    color: '',
    message: 'تمت عملية “استخراج البيانات” بنجاح',
    time: '14/02/2024',
  },
])
 
const unreadCount = computed(() => unread.value.length)
 
function toggleDropdown() {
  dropdownOpen.value = !dropdownOpen.value
}
 
function markAllAsRead() {
  read.value = [...unread.value, ...read.value]
  unread.value = []
  activeTab.value = 'read'
}
</script>
 
<style scoped>
@media (min-width: 768px) {
  .dropdown-menu-md-center.show {
    transform: inherit !important;
  }
}
</style>
 
<!-- SearchModal Component Code Block -->
 
<template>
  <Transition name="fade">
    <div v-if="modelValue" class="modal-backdrop show" @click.self="close">
      <div class="modal-dialog search-modal">
        <div class="modal-content">
          <div class="modal-body padding-sm text-center">
            <div class="input-group search-wrapper">
              <span class="spinner" v-if="loading"></span>
              <span class="tticon-search input-group-text"></span>
              <input
                class="form-control"
                type="search"
                placeholder="بحث في لوحة التحكم.."
                autocomplete="off"
                v-model="searchQuery"
                @keydown.esc="close"
              />
              <span class="close-shortcut">esc</span>
            </div>
 
            <div class="search-results">
              <p class="search-results-placeholder" v-if="!searchQuery && !loading">
                اكتب كلمة البحث في الأعلى.
              </p>
              <p class="search-loading" v-if="loading">جاري تحميل البيانات...</p>
 
              <ul v-if="results.length">
                <li v-for="result in results" :key="result.id">
                  {{ result.title }}
                </li>
              </ul>
            </div>
 
            <ul class="seach-footer">
              <li>
                <span class="tticon-hash shortcut-icon"></span>
                <span class="shortcut-label">مفتاحية</span>
              </li>
              <li>
                <span class="tticon-arrow-up shortcut-icon"></span>
                <span class="tticon-arrow-down shortcut-icon"></span>
                <span class="shortcut-label">الانتقال</span>
              </li>
              <li>
                <span class="shortcut-text">enter</span>
                <span class="shortcut-label">تنفيذ</span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </Transition>
</template>
 
<script setup>
import { ref, watch, defineEmits } from 'vue'
 
defineProps({
  modelValue: Boolean,
})
 
const emit = defineEmits(['update:modelValue'])
 
const searchQuery = ref('')
const loading = ref(false)
const results = ref([])
 
watch(searchQuery, async (newQuery) => {
  if (!newQuery) {
    results.value = []
    return
  }
 
  loading.value = true
 
  // Simulate API call here
  await new Promise((resolve) => setTimeout(resolve, 500))
 
  results.value = [
    { id: 1, title: `نتيجة لـ "${newQuery}"` },
    { id: 2, title: `عن "${newQuery}"` },
  ]
  // then
  loading.value = false
})
 
function close() {
  emit('update:modelValue', false)
}
</script>
 
<style scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
.modal-backdrop {
  background-color: rgba(0, 0, 0, 0.5);
  position: fixed;
  inset: 0;
  z-index: 1050;
  display: flex;
  align-items: center;
  justify-content: center;
}
.modal-backdrop.show {
  opacity: 1;
}
</style>
 
Last updated 3 months ago