npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mobiwek61menu

v0.0.414

Published

Investigates how to fit a big cascading menu into a small mobile screen using a floating overlay scheme

Downloads

472

Readme

mobiwek61menu, a multi-level menu tailored for mobile screens.

this readme is a first draft and needs work
View working sample app at:
https://mobiwek61.github.io/amhistory/aLincoln1

Github repository of working sample source using this package
more complex examples are here also.
https://github.com/mobiwek61/mobiwek61menu/tree/main/mobiwek61menu_demo/simple-demo
Github repository of source of this package:
https://github.com/mobiwek61/mobiwek61menu
Email of author of this package and demos:
[email protected]

mobi is "mobile", wek61 is "weka" with the "a" shown as hexadecimal. The awkward name is to eliminate possible name clashes with other entities.

this setup and demos have not yet been tested extensively

A project by a React beginner to investigate ways of fitting a big menu into a small mobile screen.

  • The menu can have many levels and extends far beyond the mobile device's physical screen width.
  • Device's screen is a draggable viewport onto the menu. Viewport auto-scrolls to current open submenu.
  • Menu retains state between navigations, includes home button.
  • Immediate font size adjustment.
  • Zoomable content without zooming menu (burger) icon itself.
  • Menu is translucent and floats above current content with no background.
  • Menu system specified by JSON, with possibility of auto-generating menus and dynamic menu generation based on user choices, data feeds, and possibly AI.

Usage of this package in code.

Below are the 2 files which determine menu appearance and actions:

  • The menu structure in below example is defined by DevMenuSpec.js
  • The menu actions and Routes is defined in ReactAppForDevelopment.js

See above repositories for full example code.

DevMenuSpec.js


import React from 'react';
 
const space4=<>&nbsp;&nbsp;&nbsp;&nbsp;</>  // this is JSX. Must be bounded by <> and </>

/** example of creating a reusable menu leaf as a const */
const const_winslowHomerFogWarning = { LEAF:"fog Warning", mwmkey: "winslowHomerFogWarning",
  txtdesc:<>The fisherman is worried he cannot return to the schooner because of impending fog.<br/>
  If he can't get back, he will be lost at sea.<br/>
  From the direction of the swells, the wind and waves are against him.</>,
  mwmtype: "image",
  imgurl:'/jpeg/WIKIMEDIA-Winslow-HomerFogWarning.jpg' 
};

const mobiwekMenuJSONexample_1 = 
    { REV:'simple example', 
      // schema wont work here because not a JSON file..     "$schema": "./TestJsonASchema.json", // visual studio code way of custom schema
      DD_MENU_HEAD:[
      { LEAF:"About", mwmkey: "about_app", mwmtype:"mwtypNull" },
      { BRANCH:"American History", mwmkey:"amhistory", items: [
        { LEAF:"Abraham Lincoln Photo", mwmkey: "aLincoln1",
          mwmtype: "image", 
          txtdesc:<>Anthony, Edward and Brady, Mathew B. 1860 https://www.loc.gov/item/2021669449/<br/></>, 
          gotfrom:'https://tile.loc.gov/image-services/iiif/service:gdc:gdcwdl:wd:l_:01:50:2:wdl_01502:icon966301/full/pct:50/0/default.jpg',
          imgurl:'/jpeg/LOC-AbeLincoln.jpg'
        },
        { BRANCH:"aircraft", mwmkey:"aircraft", items:[
          { LEAF:<>space shuttle<br/>{space4}Introduction</>, mwmkey:"spaceShuttleIntro", mwmtype:"reactRoute", 
            clickMeLink:"spaceShuttleTransport", clickMeLink2:"spaceShuttleOrbit" },
          { LEAF:<>space shuttle<br/>{space4}transport</>, mwmkey:"spaceShuttleTransport", mwmtype:"image",
            txtdesc:<>from https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Shuttle_Carrier_Aircraft_transporting_Discovery_departs_Kennedy_Space_Center.jpg<br/></>,
            imgurl:'/jpeg/hist/aerospace/WIKIMEDIA-spaceShuttleTransport.jpg' },
          { LEAF:<>space shuttle<br/>{space4}orbit</>, mwmkey:"spaceShuttleOrbit", mwmtype:"image", 
              txtdesc:<>from https://commons.wikimedia.org/wiki/File:STS007-32-1702.jpg<br/>
              This file is in the public domain in the United States because it was solely created by NASA.
              <br/>Image is unenhanced, original Kodachrome I guess. Shows just how old it is.</>, 
              imgurl:'/jpeg/hist/aerospace/WIKIMEDIA-spaceShuttleOrbit.jpg' }
        ]},
        { BRANCH:"Ben Franklin", mwmkey:"benFranklin", items: [
          { LEAF:"Speed Of Ships", mwmkey: "speedOfShips",
                  mwmtype: "handwriting", 
                  txtdesc:<>Benjamin Franklin technical notes about ships<br/>Benjamin Franklin Papers: Series III, 1728-1841; Miscellaneous material; 1728-1783 (vol. 31)<br/>from https://www.loc.gov/resource/mss21451.mss21451-012_00093_00422/?sp=114</>, 
                  imgurl:'/jpeg/hist/benFranklin/LOC-benFranklinSpeedOfShips.jpg' 
          },
          { LEAF:"Ship diagram", mwmkey: "shipDiagram",
                  mwmtype: "handwriting", 
                  txtdesc:<>diagram of sailing ship and wind direction<br/>Benjamin Franklin Papers: Series III, 1728-1841; Miscellaneous material; 1784-1841 , undated (vol. 32)<br/>from https://www.loc.gov/resource/mss21451.mss21451-012_00423_00602/?sp=3</>, 
                  imgurl:'/jpeg/hist/benFranklin/LOC-benFranklin_sailingShipDiagram.jpg' 
          },
        ]},
      ]}, // END OF BRANCH amhistory
      { BRANCH:"x15 Spaceplane", mwmkey:"x15", items:[
        { LEAF:"x15 Intro", mwmkey:"x15", mwmtype:"mwtypNull", clickMeLink:"x15image" },
        { LEAF:<>picture of<br/>x15</>, mwmkey:"x15image", mwmtype:"image", 
           txtdesc:<>from https://www.edwards.af.mil/News/Photos/igphoto/2001667598/</>, 
           imgurl:'/jpeg/hist/aerospace/WIKIMEDIA-X-15_flying.jpg' }
      ]},
      const_winslowHomerFogWarning, 
    ]};
    
    export { mobiwekMenuJSONexample_1 }

ReactAppForDevelopment.js

import React, { useEffect, useState } from 'react';
import { BrowserRouter, Route, Routes, Outlet, useParams,  useNavigate, useLocation } from "react-router-dom";
import { mobiwekMenuJSONexample_1 } from  "./DevMenuSpec";
import devProjCSS from './devProject.module.css'

import { findJsonObjectByFullPath, validateMwMenu,
    MediaPictureWithInfo,  MobiWekMenuFrame, MobiWekPageWrapper } 
    //from '../../../src/PackageTreeEntry'; // coders of the package do it this way. use this when developing the package
     from 'mobiwek61menu'; // Users of package do it this way. use this when the package has been "npm installed"'ed. 

function ReactAppForDevelopment() {
  /* !!! useEffect() !!! is React's lifecycle event, like onLoad(), onRefresh() etc. */
  useEffect(() => { console.log('ReactAppForDevelopment useEffect')  }, []); 
  const theMobiwekMenu = mobiwekMenuJSONexample_1
  var errorJSX = validateMwMenu(theMobiwekMenu) // not really up to date anymore
  if (errorJSX !== null) return(errorJSX) 
  // get "css variable" from css file using getComputedStyle().  
  var cssVariableFromCSSfile_fontsizeA = 
        getComputedStyle(document.body).getPropertyValue('--fontSizeA')
  {/* the code below has parts which looks like HTML is actually JSX. One big difference is when css
      style is specified, things like margin-bottom become marginBottom (camelcase) and the value
      appears in quotes. Also note the double brackets around css. */}
  return (
    <BrowserRouter>
      <Routes>
          <Route path='/' // this route always taken. Serves as menu frame for content
              //       ^ all routes hit this one because its /
              element=
                  {<div id='reactRouterTopRoute' className='eatZoomGesture'
                        style={{ fontSize:cssVariableFromCSSfile_fontsizeA}} >
                      {/* "Outlet" below says to include content in nested component */}
                      <Mobiwek61MenuTop mwmenuRoot={theMobiwekMenu}  pageContent={<Outlet/>} />
                  </div>} 
          >
            {/* within JSX, call "function" to setup routes. Note unusual syntax of enclosing inside {}  */}
            { SetupRoutes_A() }
        </Route> 
      </Routes>
    </BrowserRouter>
  );

  /** sets up React routes for this application */
  function SetupRoutes_A() {
    return(<>
    {/* // this wildcard route gets hit only when no other sibling routes get hit */}
    <Route path='*' 
        element={<HandleByFullPathToFindMenuEntry mwmenuRoot={theMobiwekMenu} />} 
    />
    <Route path='about_app' element={ < Do_about_app /> } />
    {/* this route send "itemKey" as a parameter to the Aircraft component.
    itemKey could be "/x15/x15image" or "/x15/x15". Aircraft component decides what action to take */}
    <Route path='x15/:itemKey' 
        element={ <Aircraft/>}  
    />
    <Route path='amhistory' element={<Outlet/>} >
        <Route path='aircraft/:itemKey' element={ <Aircraft/> }  />
    </Route>
    </>)
  }

  /** 1) Sets up mobiwekmenu whose branches and leaves are specified by props.mwmenuRoot
   *  2) Sets up callback function which gets invoked when a leaf is clicked.
   *     Typically calls navigate() to point browser to new location indicated by what was clicked,
   *     but also check for special things like 'resetMenu'.
   *  3) I'm called inside a <Route/> tag so I get to use useNavigate(). Else error occurs
   */
  function Mobiwek61MenuTop(props) {
    const navigate = useNavigate();
    return(<>
      <MobiWekMenuFrame
          appTitle="MENU-DEMO"
          mobiwekMenuJSON_A={ props.mwmenuRoot }  
          menuCallBackPtr={ ReactAppForDevelopmentMenuCallbackFn }  
          overflowCSS="hidden" //"scroll" // leads to div "divPageContentInFrameHelper" having this property
          {...props}     />
      </>)
    /**
     * Callback function for menu LEAF choice
     * @param mwmkeyFullPath unique mwmkey as defined in menuspec "theMobiwekMenu" includes hierarchy ie: workshopTools/power/saw/chainsaw
     * @param innerText label of menu button
     * @param fontSearchUrlParam ie: "?mwmfont=24.3px"
     * to access from window:  "new URLSearchParams(window.location.search).get('mwmfont')"
     */
    function ReactAppForDevelopmentMenuCallbackFn(mwmkeyFullPath, innerText, fontSearchUrlParam) {
          console.log('LEAF CLICKED--   mwmkey: ' + mwmkeyFullPath + ' label: ' +  innerText.replaceAll('\n', '\\n') + ' fontSearchUrlParam ' + fontSearchUrlParam)
          // console.log(' zzb ' + new URLSearchParams(window.location.search).get('mwmfont'))
          if (mwmkeyFullPath === 'resetMenu') mwmkeyFullPath = '/'
          if (mwmkeyFullPath === '/Home') mwmkeyFullPath = '/'
          navigate(mwmkeyFullPath + fontSearchUrlParam); 
    }
  }

  /** "about" page */
  function Do_about_app(props) {
    useEffect(() => { 
      // The MobiWekPageWrapper component which wraps this component does CSS overflow "none" to accommodate
      // zoomable scrollable images. This "page" is just html, so add scrolling as follows:
      document.querySelector("#divPageContentInFrameHelper").style.overflow = "scroll";
    }, []); 
    
    // JSX multi classname: <div className={devProjCSS.divInMiddle + ' ' + devProjCSS.textShadowB}   
    return(<div style={{ margin:'10vh 5px 5px 5px', padding:'5px',border:'3px solid #cccccc'}}>
        <div style={{ marginBottom:'20px', color:'#ffff00'}}>This is a demo of mobiwek61menu. </div>
        mobiwek61menu is an <b>npm package</b> which implements a floating overlay menu. <br/>
        It is an experimental project to:
        <ul>
          <li>fit a large cascading menu onto a mobile screen</li>
          <li>provide variable font size with one click</li>
          <li>present user with a simple interface</li>
          <li>present menu while minimally obscuring content, which may be artwork.</li>
          <li>display zoomable images of historically significant handwriting to assist readability</li>
          <li>present info button to display information and a qr code to that menu location</li>
        </ul>
        <div style={{ marginBottom:'20px', color:'#ffff00'}}>Related resources</div>
        <ul>
          <li>npm package location: <a style={{color:'#32ffbc'}} href='https://www.npmjs.com/package/mobiwek61menu'><>https://www.npmjs.com/package/mobiwek61menu</></a></li>
          <li>provide variable font size with one click</li>
          <li>another line</li><li>another line</li><li>another line</li><li>another line</li><li>another line</li>
        </ul>
    </div>)
  }

  /** depending of parameters, show specific webpage. If no match, decide if image is shown */
  function Aircraft() {
      var params = useParams();
      // if (true) return(<>hello</>)
      // obtain matching menu leaf (a JSON object) in theMobiwekMenu tree, as indicated by fullUrlPath 
      var fullUrlPath = useLocation().pathname;
      var mwmkeyLeaf = findJsonObjectByFullPath(theMobiwekMenu, fullUrlPath)
      if (params.itemKey === 'x15') { 
        console.log("Aircraft() handler,  x15 page"); 
        return MobiWekPageWrapper(Page_x15_spaceplane(mwmkeyLeaf))
        //return page_x15_spaceplane(mwmkeyLeaf);
      }
      if (params.itemKey === 'spaceShuttleIntro') {
        console.log("Aircraft() handler, spaceShuttleIntro page"); 
        return MobiWekPageWrapper(Page_spaceShuttle(mwmkeyLeaf));
        //return Page_spaceShuttle(mwmkeyLeaf)
      }
      // if leaf is an image, just give to MediaPictureWithInfo()
      if (mwmkeyLeaf.mwmtype === 'image') {
        console.log("Aircraft() handler, just am image"); 
        return MediaPictureWithInfo(mwmkeyLeaf) 
      }
      // get here only if there is a problem
      return (<>ExperimentalAircraft no handler found</>)
  }

  /** custom page for x15. Includes clickable image to navigate to image display page. */
  function Page_x15_spaceplane(mwmkeyLeaf) {
    const navigate = useNavigate();
    return <div><h1>x15 Spaceplane</h1><br/>first winged vehicle designed to go outside the atmosphere<br/>
        <div style={{border: 'solid 0px red', display: 'inline-block'}} 
             onClick={ () => { const nav = getNavigateDir();
               navigate(nav.locationDir + '/' + mwmkeyLeaf.clickMeLink + nav.fontSuffix)}} >
        <img style={{border: 'solid 5px white', borderRadius:'48px', margin:'5vw', width:'70vw' }} 
            src='/jpeg/hist/aerospace/WIKIMEDIA-X-15_flying.jpg' alt='x15'
        /></div></div>
  }

  /** pulls apart window.location to get current folder and get font-suffix thing.
   *  Otherwise navigate tries to go to subfolder of current url.
   *  Please let me know if there is a builtin way of doing this.  */
  function getNavigateDir() {
    var locationDir = window.location.pathname; 
    locationDir = locationDir.substring(0, locationDir.lastIndexOf("/") );
    const fontSuffix = window.location.search // ie: '?mwmfont=22.2px' .. need to stick back onto end
    return { 'locationDir': locationDir, 'fontSuffix': fontSuffix }
  }

  /** custom page for space shuttle */
  function Page_spaceShuttle(mwmkeyLeaf) {
    const navigate = useNavigate();
    //  useEffect(() => { 
    //   // document.querySelector('#clkImgA').addEventListener('click', () => { console.log('evtlisten')})
    // }, []); 
    return <div>
        <h1>Space Shuttle</h1>
        First spacecraft designed with flying wings (maybe)<br/>
        {/* image is not clickable so wrap in a div  */}
        <div style={{border: 'solid 0px red', display: 'inline-block'}} 
             onClick={ () => { const nav = getNavigateDir();
               navigate(nav.locationDir + '/' + mwmkeyLeaf.clickMeLink + nav.fontSuffix)}} >
          <img style={{border: 'solid 5px white', borderRadius:'48px', margin:'5vw', width:'70vw' }} 
              src='/jpeg/hist/aerospace/WIKIMEDIA-spaceShuttleTransport.jpg' 
              alt='space shuttle transported' />
        </div><br/>Space shuttle transported on 747
        <div onClick={ () => { const nav = getNavigateDir(); 
                navigate(nav.locationDir + '/' + mwmkeyLeaf.clickMeLink2 + nav.fontSuffix)}} >
          <img id='clkImgA' style={{border: 'solid 5px white', borderRadius:'48px', margin:'5vw', width:'70vw' }} 
              src='/jpeg/hist/aerospace/WIKIMEDIA-spaceShuttleOrbit.jpg' alt='space shuttle in orbit'/>
        </div>
        <br/>Space shuttle in orbit
        
        </div>
  }

    /**
     * Router handler uses router full path to find matching menu entry in menu object.
     * it then examines mwmtype of menu entry to direct to proper handler.
     * @param props.mwmenuRoot head of JSON menu structure to search for node having fullPath
     */
    function HandleByFullPathToFindMenuEntry(props) {
      // var fullUrlPath = useParams()["*"]; // works only for <Route path='*' element=...
      var fullUrlPath = useLocation().pathname 
      // SAVE to test error message: 
      // fullUrlPath = fullUrlPath + 'zzz' // to test things
      // fullUrlPath = 'LibCongress/pictszzzz/gwoodAmericanGothic'
      var mwmkeyLeaf = findJsonObjectByFullPath(props.mwmenuRoot, fullUrlPath)
      //console.log('found ' + mwmkeyLeaf.mwmkey + '  path ' + fullUrlPath)
      if (mwmkeyLeaf.error !== undefined) {
          console.log('WARNING ' + fullUrlPath + ' path not found in menu JSON object. mwmkeyLeaf.error: ' + mwmkeyLeaf.error)
          return(<span className={devProjCSS.divInMiddle + ' ' + devProjCSS.textShadowB} ><br/>
          No route set for path <br/>"{ fullUrlPath }" not found<br/>This url is probably for testing the menu display and is not
          a bug. </span>)
      }
      
      if (mwmkeyLeaf.imgurl !== undefined) 
          return MediaPictureWithInfo(mwmkeyLeaf)
      // if not just show a message
      // following shows how JSX mixes variables with markuup and styles. A bit weird looking.
      const redHi = { background:'#ff00001f', overflowWrap: 'anywhere' }
      return(<div className={devProjCSS.divInMiddle + ' ' + devProjCSS.textShadowB}
                style={{ ...redHi, margin:'0 7vw 0 7vw', width:"inherit", left:'2vw'}} > {/* WOW bing ai got this answer! */}
          This menu leaf is probably test menu data with no handler setup, and is not a bug.
          <br/><code>function HandleByFullPathToFindMenuEntry(). </code><br/> fullUrlPath: { fullUrlPath } 
          <br/>mwmkey: {mwmkeyLeaf.mwmkey}<br/> 
        </div>)
    }
}

export { ReactAppForDevelopment };