Sfoglia il codice sorgente

refactor: enhance api demo app mobile experience (#4929)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Amr Bashir 3 anni fa
parent
commit
725236cea0

File diff suppressed because it is too large
+ 0 - 0
examples/api/dist/assets/index.css


File diff suppressed because it is too large
+ 0 - 0
examples/api/dist/assets/index.js


+ 1 - 1
examples/api/src-tauri/Cargo.toml

@@ -7,7 +7,7 @@ rust-version = "1.57"
 license = "Apache-2.0 OR MIT"
 
 [build-dependencies]
-tauri-build = { path = "../../../core/tauri-build", features = ["isolation", "codegen"] }
+tauri-build = { path = "../../../core/tauri-build", features = ["codegen", "isolation"] }
 
 [dependencies]
 serde_json = "1.0"

+ 112 - 21
examples/api/src/App.svelte

@@ -36,6 +36,9 @@
     onMessage(`File drop: ${JSON.stringify(event.payload)}`)
   })
 
+  const userAgent = navigator.userAgent.toLowerCase()
+  const isMobile = userAgent.includes('android') || userAgent.includes('iphone')
+
   const views = [
     {
       label: 'Welcome',
@@ -47,12 +50,12 @@
       component: Communication,
       icon: 'i-codicon-radio-tower'
     },
-    {
+    !isMobile && {
       label: 'CLI',
       component: Cli,
       icon: 'i-codicon-terminal'
     },
-    {
+    !isMobile && {
       label: 'Dialog',
       component: Dialog,
       icon: 'i-codicon-multiple-windows'
@@ -67,17 +70,17 @@
       component: Http,
       icon: 'i-ph-globe-hemisphere-west'
     },
-    {
+    !isMobile && {
       label: 'Notifications',
       component: Notifications,
       icon: 'i-codicon-bell-dot'
     },
-    {
+    !isMobile && {
       label: 'Window',
       component: Window,
       icon: 'i-codicon-window'
     },
-    {
+    !isMobile && {
       label: 'Shortcuts',
       component: Shortcuts,
       icon: 'i-codicon-record-keys'
@@ -87,12 +90,12 @@
       component: Shell,
       icon: 'i-codicon-terminal-bash'
     },
-    {
+    !isMobile && {
       label: 'Updater',
       component: Updater,
       icon: 'i-codicon-cloud-download'
     },
-    {
+    !isMobile && {
       label: 'Clipboard',
       component: Clipboard,
       icon: 'i-codicon-clippy'
@@ -146,13 +149,13 @@
   // dark/light
   let isDark
   onMount(() => {
-    isDark = localStorage.getItem('theme') == 'dark'
+    isDark = localStorage && localStorage.getItem('theme') == 'dark'
     applyTheme(isDark)
   })
   function applyTheme(isDark) {
     const html = document.querySelector('html')
     isDark ? html.classList.add('dark') : html.classList.remove('dark')
-    localStorage.setItem('theme', isDark ? 'dark' : '')
+    localStorage && localStorage.setItem('theme', isDark ? 'dark' : '')
   }
   function toggleDark() {
     isDark = !isDark
@@ -218,14 +221,82 @@
   onMount(async () => {
     isWindows = (await os.platform()) === 'win32'
   })
+
+  // mobile
+  let isSideBarOpen = false
+  let sidebar
+  let sidebarToggle
+  let isDraggingSideBar = false
+  let draggingStartPosX = 0
+  let draggingEndPosX = 0
+  const clamp = (min, num, max) => Math.min(Math.max(num, min), max)
+
+  function toggleSidebar(sidebar, isSideBarOpen) {
+    sidebar.style.setProperty(
+      '--translate-x',
+      `${isSideBarOpen ? '0' : '-18.75'}rem`
+    )
+  }
+
+  onMount(() => {
+    sidebar = document.querySelector('#sidebar')
+    sidebarToggle = document.querySelector('#sidebarToggle')
+
+    document.addEventListener('click', (e) => {
+      if (sidebarToggle.contains(e.target)) {
+        isSideBarOpen = !isSideBarOpen
+      } else if (isSideBarOpen && !sidebar.contains(e.target)) {
+        isSideBarOpen = false
+      }
+    })
+
+    document.addEventListener('touchstart', (e) => {
+      if (sidebarToggle.contains(e.target)) return
+
+      const x = e.touches[0].clientX
+      if ((0 < x && x < 20 && !isSideBarOpen) || isSideBarOpen) {
+        isDraggingSideBar = true
+        draggingStartPosX = x
+      }
+    })
+
+    document.addEventListener('touchmove', (e) => {
+      if (isDraggingSideBar) {
+        const x = e.touches[0].clientX
+        draggingEndPosX = x
+        const delta = (x - draggingStartPosX) / 10
+        sidebar.style.setProperty(
+          '--translate-x',
+          `-${clamp(0, isSideBarOpen ? 0 - delta : 18.75 - delta, 18.75)}rem`
+        )
+      }
+    })
+
+    document.addEventListener('touchend', () => {
+      if (isDraggingSideBar) {
+        const delta = (draggingEndPosX - draggingStartPosX) / 10
+        isSideBarOpen = isSideBarOpen ? delta > -(18.75 / 2) : delta > 18.75 / 2
+      }
+
+      isDraggingSideBar = false
+    })
+  })
+
+  $: {
+    const sidebar = document.querySelector('#sidebar')
+    if (sidebar) {
+      toggleSidebar(sidebar, isSideBarOpen)
+    }
+  }
 </script>
 
+<!-- custom titlebar for Windows -->
 {#if isWindows}
   <div
     class="w-screen select-none h-8 pl-2 flex justify-between items-center absolute text-primaryText dark:text-darkPrimaryText"
     data-tauri-drag-region
   >
-    <span class="text-darkPrimaryText">Tauri API Validation</span>
+    <span class="lt-sm:pl-10 text-darkPrimaryText">Tauri API Validation</span>
     <span
       class="
       h-100%
@@ -272,12 +343,27 @@
   </div>
 {/if}
 
+<!-- Sidebar toggle, only visible on small screens -->
+<div
+  id="sidebarToggle"
+  class="z-2000 display-none lt-sm:flex justify-center items-center absolute top-2 left-2 w-8 h-8 rd-8
+            bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark"
+>
+  {#if isSideBarOpen}
+    <span class="i-codicon-close animate-duration-300ms animate-fade-in" />
+  {:else}
+    <span class="i-codicon-menu animate-duration-300ms animate-fade-in" />
+  {/if}
+</div>
+
 <div
   class="flex h-screen w-screen overflow-hidden children-pt8 children-pb-2 text-primaryText dark:text-darkPrimaryText"
 >
   <aside
-    class="w-75 {isWindows
-      ? 'bg-darkPrimaryLighter/60'
+    id="sidebar"
+    class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999
+     {isWindows
+      ? 'bg-darkPrimaryLighter/60 lt-sm:bg-darkPrimaryLighter'
       : 'bg-darkPrimaryLighter'} transition-colors-250 overflow-hidden grid select-none px-2"
   >
     <img
@@ -332,19 +418,24 @@
       class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1"
     >
       {#each views as view}
-        <a
-          href="##"
-          class="nv {selected === view ? 'nv_selected' : ''}"
-          on:click={() => select(view)}
-        >
-          <div class="{view.icon} mr-2" />
-          <p>{view.label}</p></a
-        >
+        {#if view}
+          <a
+            href="##"
+            class="nv {selected === view ? 'nv_selected' : ''}"
+            on:click={() => {
+              select(view)
+              isSideBarOpen = false
+            }}
+          >
+            <div class="{view.icon} mr-2" />
+            <p>{view.label}</p></a
+          >
+        {/if}
       {/each}
     </div>
   </aside>
   <main
-    class="flex-1 bg-primary dark:bg-darkPrimary transition-colors-250 grid grid-rows-[2fr_auto]"
+    class="flex-1 bg-primary dark:bg-darkPrimary transition-transform transition-colors-250 grid grid-rows-[2fr_auto]"
   >
     <div class="px-5 overflow-hidden grid grid-rows-[auto_1fr]">
       <h1>{selected.label}</h1>

+ 11 - 0
examples/api/src/app.css

@@ -28,3 +28,14 @@ code {
 code.code-block {
   padding: 0.5rem;
 }
+
+#sidebar {
+  width: 18.75rem;
+}
+
+@media screen and (max-width: 640px) {
+  #sidebar {
+    --translate-x: -18.75rem;
+    transform: translateX(var(--translate-x));
+  }
+}

+ 1 - 1
examples/api/src/views/Window.svelte

@@ -236,7 +236,7 @@
   {/if}
   {#if windowMap[selectedWindow]}
     <br />
-    <div>
+    <div class="flex flex-wrap gap-2">
       <button
         class="btn"
         title="Unminimizes after 2 seconds"

+ 12 - 9
examples/api/unocss.config.js

@@ -3,7 +3,7 @@ import {
   presetIcons,
   presetUno,
   extractorSvelte,
-  presetWebFonts,
+  presetWebFonts
 } from 'unocss'
 
 export default defineConfig({
@@ -43,7 +43,6 @@ export default defineConfig({
   },
   preflights: [
     {
-
       getCSS: ({ theme }) => `
     ::-webkit-scrollbar-thumb {
       background-color: ${theme.colors.accent};
@@ -86,13 +85,17 @@ export default defineConfig({
     'note-red':
       'note bg-red-700/10 dark:bg-red-700/10 after:bg-red-700 dark:after:bg-red-700',
     input:
-      'h-10 flex items-center outline-none border-none p-2 rd-1 shadow-md bg-primaryLighter dark:bg-darkPrimaryLighter text-primaryText dark:text-darkPrimaryText',
+      'h-10 flex items-center outline-none border-none p-2 rd-1 shadow-md bg-primaryLighter dark:bg-darkPrimaryLighter text-primaryText dark:text-darkPrimaryText'
   },
-  presets: [presetUno(), presetIcons(), presetWebFonts({
-    fonts: {
-      sans: 'Rubik',
-      mono: ['Fira Code', 'Fira Mono:400,700'],
-    }
-  })],
+  presets: [
+    presetUno(),
+    presetIcons(),
+    presetWebFonts({
+      fonts: {
+        sans: 'Rubik',
+        mono: ['Fira Code', 'Fira Mono:400,700']
+      }
+    })
+  ],
   extractors: [extractorSvelte]
 })

Some files were not shown because too many files changed in this diff