r/webdev - [Cybersecurity Lesson] Auto-complete scams. What are they? How to detect them?
Strategy

[Cybersecurity Lesson] Auto-complete scams. What are they? H…


r/webdev - [Cybersecurity Lesson] Auto-complete scams. What are they? How to detect them?

TL:DR some hackers will have billing, address HTML forms hidden so that you will provide them without explicit consent. This is a live demo built by u/anttiviljami

To avoid this phishing-risk, you can turn off the autofill settings in your browser.The bug’s been known since forever but I only learned how the auto-fill works. It’s basically a guessing game based on important name tags in HTML.

However, some mischievous hackers would have off-center, or block hidden or set as none; to grab sensitive data. E.g. Phone# containers that are off center using HTML

<p style=”margin-left:-1000px”> <label for cc, phone number etc….> </p>

You can instantiate it as hidden or you can even add one in-line CSS styling that throws it out of the scope of browser. To test, style=”margin-left:-1000px” to any element/ on this page and see what happens.

Now HTML / css can be modified by javascript to hide and show elements or even instantiate them hidden

document.getElementById("okButton")
        .addEventListener("click", function() {
  document.getElementById("name").hidden = true;
  document.getElementById("address").hidden = false;
}, false);

Notice how the address will be hidden on the click of ok Agree?

<div id="cc" class="panel">
  <h1>Welcome to change.bs!</h1>
  <p>By clicking "OK" you agree to sign a petition!</p>
  <button class="button" id="okButton">OK</button>
  <p>  <label for="name">Name</label><br>  <input id="name" name="name" type="text" placeholder="Your Name"></p>
  <p style="display:none;">  <label for="address">Name</label><br>  <input id="address" name="address" type="text"></p>
</div>

In essence, it’s a Tom&Jerry. How well can hackers hide important fields using code obfuscation? You can do it with JQuery, or probably any other framework because the more layer, will mean harder detection, but this is just my speculation.

The official to autocomplete words suggested by HTML. However, each browser is a different implementation since I believe Firefox is NOT susceptible because the autocomplete mechanism is per field, not for everything.

Now question for more experienced users.

r/webdev - [Cybersecurity Lesson] Auto-complete scams. What are they? How to detect them?

I can give a Pastebin of the entire DOM-tree once I remove IID/PID?

I have had a test-proctoring website ask me for CC information in autocomplete when all they displayed were first and last name fields? Is there something more, or is that an honest mistake from sites? Because I couldn’t find anything “incriminating”, but I’m still a noob…



Source link

r/web_design - Website Design Proposal Template (Word and PDF)
Strategy

Website Design Proposal Template (Word and PDF) : web_design


Website design proposals are used to pitch web desing services to prospective clients. It captures details about a webmaster approach, services, and payment terms, and shows clients that you take your work seriously and are thorough in your approach. A website proposal gives you more credibility and ultimately increases your chance of securing a job.
Website Proposal Template – Elements & Template here is a simple three-page website proposal template with its key elements explained.

r/web_design - Website Design Proposal Template (Word and PDF)

Website Proposal Template (image)



Source link

gif of matrix transforms updating with dev tools open
Strategy

Making a lil’ me – Part 1.


I’m so excited to have finally launched my website.

This was one of my favourite bits to make by far. A little animated me that responds to the cursor position.

See the Pen lil’ me. by Cassie Evans (@cassie-codes) on CodePen.

In this post we’ll cover how to get values from the mouse movement and plug them into an animation.

This is my favourite thing about SVG animation. Not mouse movement in particular, but interactivity. Exporting animation as an mp4 is cool and all. But you can’t play with it.

Animating on the web opens up so many cool possibilities!

If you’re the kind of person who learns best by digging into the code, then just go ahead and fork that pen, have fun!


Still here? 😊 Cool beans, let’s go through it together.

I use Greensock for all my SVG animation. There are a few reasons for this. Firstly, it gives you more control and is super fun to use. But more importantly, as browsers implement the SVG spec differently, animating can get a bit messy. The team at Greensock put a lot of effort into harmonizing behavior across browsers.

Under the hood though, Greensock is just a really performant property manipulator. It will manipulate (pretty much) whatever value you want to change. In this case it’s updating the values in a matrix transform. Check this out.

gif of matrix transforms updating with dev tools open

Cool right! Greensock is great at this kind of thing, but there’s a lot going on in this pen, so let’s break it down into chunks and focus on one bit at a time. First up, the mouse interaction. We’ll come back to Greensock in a bit!

Mouse movement fun! permalink

So, there’s another way we can modify values in CSS with Javascript. CSS custom properties!

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

Let’s walk through the process. The goal is to get the x and y position of the cursor as we move our mouse about, and then we can use those values to update some custom properties.

In the previous gif Greensock is using matrix transforms, which are more performant. But we’re going to use transform: translate(x,y) for this as it’s a tad more readable, and we can use percentage values.

First up, we declare some custom properties for the x and y values and then use those custom properties in place of regular property values in our transform.

:root {
--mouse-x: 0;
--mouse-y: 0;
}

.pointer {
transform: translate(var(--mouse-x), var(--mouse-y));
}

Then we need to get our mouse coordinates. We can do this by listening to the mouse movement and getting the mouse’s coordinates with clientX and clientY

We’ll assign those values to some global variables so that we can access them in another function later.

let xPosition;
let yPosition;


function updateMouseCoords(event) {
xPosition = event.clientX;
yPosition = event.clientY;
}
window.addEventListener('mousemove', updateMouseCoords);

Now we’ve got our coordinates, lets use them to update our custom properties and move our pointer around!

😇 When animating things on the web it’s important to pay attention to performance. We can’t know for sure how many times a users mouse event will fire as it’s implementation specific. If it fires more than 60 times per second (which is the average refresh rate for most browsers) we’ll end up with unnecessary computation. So to avoid burning up everyone’s laptop fans and melting their CPU we can use requestAnimationFrame

Request animation frame allows us to make smoother, browser optimized animations. If the user changes tabs, the animation will stop and give the CPU a break. You call the function once to start, and then it recusively calls itself.

⚠️ This is a great way to crash your browser if you get some code wrong!

function movePointer() {

requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

Right now, the x and y position we’re getting back from event.clientX and event.clientY are pixel values, this isn’t really useful to us. If we plug them straight into our custom properties we could end up transforming our pointer hundreds of pixels off in one direction.

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

We need to convert those pixel values into percentages of the window height and width.

Let’s define some global variables for the window width and height and work out the percentage values.

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;

function percentage(partialValue, totalValue) {
return (100 * partialValue) / totalValue;
}

function movePointer() {
x = percentage(xPosition, windowWidth);
y = percentage(yPosition, windowHeight);

window.requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

This will give us a range from 0 – 100, which would just move our pointer downwards and to the right, so we can shift the range by subtracting 50.

Once we’ve got our nice centralised range, we can plug it into our custom properties using setProperty()

let windowHeight = window.innerHeight;
let windowWidth = window.innerWidth;

function percentage(partialValue, totalValue) {
return (100 * partialValue) / totalValue;
}

function movePointer() {


x = percentage(xPosition, windowWidth) - 50;
y = percentage(yPosition, windowHeight) - 50;


document.documentElement.style.setProperty('--mouse-x', `${x}%`);
document.documentElement.style.setProperty('--mouse-y', `${y}%`);

window.requestAnimationFrame(movePointer);
}
requestAnimationFrame(movePointer);

The user might resize the browser, so it’s good to check for that.


function updateWindowSize() {
windowHeight = window.innerHeight;
windowWidth = window.innerWidth;
}
window.addEventListener('resize', updateWindowSize);

We can also avoid unnecessary calculations when the mouse position hasn’t changed by storing past x and y positions and comparing them to the new positions.

let xPosition;
let yPosition;

let storedXPosition;
let storedYPosition;

function movePointer() {
window.requestAnimationFrame(movePointer);

if (storedXPosition === xPosition && storedYPosition === yPosition) return;




storedXPosition = xPosition;
storedYPosition = yPosition;
}

😇 another super important bit is checking whether the user has a preference set in their OS for reduced motion. Some people have vestibular disorders and get mega quesy when looking at animations.

I pop this check at the start of all my animation functions, and return out if necessary.

const safeToAnimate = window.matchMedia('(prefers-reduced-motion: no-preference)')
.matches;

if (!safeToAnimate) return;

See the Pen Mouse movement demo by Cassie Evans (@cassie-codes) on CodePen.

What about Greensock?! permalink

Let’s see how we can do the same thing using Greensock! First we have to include the core library, if you’re on codepen, you can go to your pen settings and search for greensock.

pen settings on codepen

Now we’ve got the GSAP library in our pen, we can take advantage of gsap.ticker()

The greensock ticker is like the heartbeat of the GSAP engine – under the hood it uses requestAnimationFrame, just like we were using, but if that isn’t supported, the ticker automatically falls back to using a regular setTimeout() loop.

So rather than calling our function with request animation frame, we would do this…

function movePointer() {

}

gsap.ticker.add(movePointer);

Aside from making structuring animation itself more intuitive, Greensock provides a load of super cool utility functions that make your life easier. Remember all that work we did to get a nice usable range? Chuck that all in the bin. Look what we can do now!


let mapWidth;
let mapHeight;
function setMaps() {
mapWidth = gsap.utils.mapRange(0, innerWidth, -50, 50);
mapHeight = gsap.utils.mapRange(0, innerHeight, -50, 50);
}
window.addEventListener('resize', setMaps);
setMaps();

Now we can listen to the mouse movement, feed clientX and clientY into mapWidth, and we’ll get back a value within the range we’ve set!

let xPosition;
let yPosition;


function updateMouseCoords(event) {
xPosition = mapWidth(event.clientX);
yPosition = mapWidth(event.clientY);
}
window.addEventListener('mousemove', updateMouseCoords);

So tidy and concise!

Instead of updating CSS custom properties, we’re going to use a Greensock tween. A Tween is what does all the animation work, as I said at the start, it’s like a high-performance property manipulator.

A tween takes in two parameters

The targets, which are the object(s) whose properties you want to animate. Greensock uses document.querySelectorAll() internally so we can use any CSS selector we would use in CSS, or a direct reference to an element.

And the vars, an object containing all the properties/values you want to animate, along with any special properties like delay, ease, or duration.

function movePointer() {
gsap.to(pointer, {
xPercent: xPosition,
yPercent: yPosition,
ease: 'none'


});
}

gsap.ticker.add(movePointer);

I’ve added a couple more easing equations in here so you can change them out and see what a difference it can make to the movement.

See the Pen Mouse movement demo – GSAP – easing by Cassie Evans (@cassie-codes) on CodePen.

If you want to focus more on performance than easing you can use gsap.quickSetter to update the transforms. Creating a quickSetter function can boost performance around 50% – 250%!



const xSet = gsap.quickSetter(pointer, 'x', '%');
const ySet = gsap.quickSetter(pointer, 'y', '%');

function movePointer() {
xSet(xPosition);
ySet(yPosition);
}

gsap.ticker.add(movePointer);

See the Pen Mouse movement demo – GSAP by Cassie Evans (@cassie-codes) on CodePen.

Thanks for reading!

Next up – lets apply this to a SVG and fake some three dimensional movement!

(check back in for the next article in a couple of days!)

Got any questions about this article? Just pop me a message!





Source link

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.
Strategy

Keep getting Unexpected token


Hello everyone, I have an ajax method that builds an html table with the data received from a php parser file. Whenever the button is pressed on the html, the method is triggered sending a request to the php file. For some reason, whenever the method is triggered, I keep receiving Unexpected token < in JSON at position 0 error in the console. What do you think could be the problem, even though the data sent back is formatted as JSON? Thanks a lot!

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.

homeDataParser.php

r/webdev - Keep getting Unexpected token < in JSON at position 0 error. Not sure what to do.

home.html

P.S. Screens of the php and the html file is added to the post.



Source link

Screenshot of a Lighthouse audit showing a score of 100 out of 100.
Strategy

Make Jamstack Slow? Challenge Accepted.


“Jamstack is slowwwww.” That’s not something you hear often, right? Especially, when one of the main selling points of Jamstack is performance. But yeah, it’s true that even a Jamstack site can suffer hits to performance just like any other site. 

Don’t think that by choosing Jamstack you no longer have to think about performance. Jamstack can be fast — really fast — but you have to make the right choices. Let’s see if we can spot some of the poor decisions that can lead to a “slow” Jamstack site.

To do that, we’re going to build a really slow Gatsby site. Seems strange right? Why would we intentionally do that!? It’s the sort of thing where, if we make it, then perhaps we can gain a better understanding of what affects Jamstack performance and how to avoid bottlenecks.

We will use continuous performance testing and Google Lighthouse to audit every change. This will highlight the importance of testing every code change. Our site will start with a top Lighthouse performance score of 100. From there, we will make changes until it scores a mere 17. It is easier to do than you might think!

Let’s get started!

Creating our Jamstack site

We are going to use Gatsby for our test site. Let’s start by installing the Gatsby CLI installed:

npm install -g gatsby-cli

We can up a new Gatsby site using this command:

gatsby new slow-jamstack

Let’s cd into the new slow-jamstack project directory and start the development server:

cd slow-jamstack
gatsby develop

To add Lighthouse to the mix, we need a Gatsby production build. We can use Vercel to host the site, giving Lighthouse a way to runs its tests. That requires installing the Vercel command-line tool and logging in:

npm install -g vercel-cli
vercel

This will create the site in Vercel and put it on a live server. Here’s the example I’ve already set up that we’ll use for testing.

We’ve gotta use Chrome to access directly from DevTools and run a performance audit. No surprise here, the default Gatsby site is fast:

Screenshot of a Lighthouse audit showing a score of 100 out of 100.

A score of 100 is the fastest you can get. Let’s see what we can do to slow it down.

Slow CSS

CSS frameworks are great. They can do a lot of heavy lifting for you. When deciding on a CSS framework use one that is modular or employs CSS-in-JS so that the only CSS you need is what’s loaded.

But let’s make the bad decision to reach for an entire framework just to style a button component. In fact, let’s even grab the heaviest framework while we’re at it. These are the sizes of some popular frameworks:

Framework CSS Size (gzip)
Bootstrap 68kb (12kb)
Bulma 73kb (10kb)
Foundation 30kb (7kb)
Milligram 10kb (3kb)
Pure 17kb (4kb)
SemanticUI 146kb (20kb)
UIKit 33kb (6kb)

Alright, SemanticUI it is! The “right” way to load this framework would be to use a Sass or Less package, which would allow us to choose the parts of the framework we need. The wrong way would be to load all the CSS and JavaScript files in the <head> of the HTML. That’s what we’ll do with the full SemanticUI stylesheet. Plus, we’re going to link up jQuery because it’s a SemanticUI dependency.

We want these files to load in the head so let’s jump into the html.js file. This is not available in the src directory until we run a command to copy over the default from the cache:

cp .cache/default-html.js src/html.js

That gives us html.js in the src directory. Open it up and add the required stylesheet and scripts:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.css"></link>
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.js"></script>  

Now let’s push the changes straight to our production URL:

vercel --prod

OK, let’s view the audit…

Screenshot of a Lighthouse report showing a score of 66 out of 100.
Zoikes! A 33% reduction!

We have reduced the speed of the site down to a score of 66. Remember that we are not even using this framework at the moment. All we have done is load the files in the head and that reduced the performance score by one-third. Our Time to Interactive (TTI) jumped from a quick 1.9 seconds to a noticeable 4.9 seconds. And look at the possible savings we could get with from Lighthouse’s recommendations.

Slow marketing dependencies

Next, we are going to look at marketing tags and how these third-party scripts can affect performance. Let’s pretend we work with a marketing department and they want to start measuring traffic with Google Analytics. They also have a Facebook campaign and want to track it as well. 

They give us the details of the scripts that we need to add to get everything working. First, for Google Analytics:

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-4369823-4"></script>
<script
  dangerouslySetInnerHTML={{ __html: `
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'UA-4369823-4');
  `}}
/>

Then for the Facebook campaign:

<script
  dangerouslySetInnerHTML={{ __html: `
    !function(f,b,e,v,n,t,s)
    {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};
    if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
    n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];
    s.parentNode.insertBefore(t,s)}(window, document,'script',
    'https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', '3180830148641968');
    fbq('track', 'PageView');
    `}}
/>

<noscript><img height="1" width="1" src="https://www.facebook.com/tr?id=3180830148641968&ev=PageView&noscript=1"/></noscript>

We’ll place these scripts inside html.js, again in the <head> section, before the closing </head> tag.

Just like before, let’s push to Vercel and re-run Lighthouse:

vercel --prod
Screenshot of a Lighthouse audit showing a score of 51 out of 100.

Wow, the site is already down to 51 and all we’ve done is tack on one framework and a couple of measly scripts. Together, they/ve reduced the score by a whopping 49 points, nearly half of where we started.

Slow images

We haven’t added any images to the site yet but we know we absolutely would in a real-life scenario. We are going to add 100 images to the page. Sure, 100 is a lot for a single page but, then again, we know that images are often the biggest culprits of bloated web pages so we might as well let them shine.

We’ll make things a little worse by hot loading the images directly from https://placeimg.com instead of serving them on our own server.

Let’s crack open index.js and drop this code in, which will loop through 100 instances of images:

const IndexPage = () => {
  const items = []
  for(var i = 0; i < 100; i++) {
    const url = `http://placeimg.com/640/360/any?=${i}`
    items.push(<img key={i} alt={i} src={url} />)
  }
  
  return (
    <Layout>
      // ...
      {items}
      // ...
    </Layout>
  )
}

The 100 images are all different and will all load as the page loads, thereby blocking the rendering. OK, let’s push to Vercel and see what’s up.

vercel --prod
Screenshot of a Lighthouse audit showing a score of 17 out of 100.
That score deserves a sad trombone. 🎺

OK, we now have a very slow Jamstack site. The images are blocking the rendering of the page and the TTI is now a whopping 16.5 seconds. We have taken a very fast Jamstack site and dropped it to a Lighthouse score of 17 — a reduction of 83 points!

Now, you may be think that you would never make these poor decisions when building an app. But you are missing the point. Every choice we make has an impact on performance. It’s a balance and performance does not come free. Even on Jamstack sites.

Making Jamstack fast again

You have seen that we cannot ignore client-side performance when using Jamstack. 

So why do people say that Jamstack is fast? Well, the main advantage of Jamstack — or using static site generators in general — is caching. Static files are cached on the edge reducing Time to First Byte (TTFB).

This is always going to be faster than going to a single-origin web server before generating the page. This is a great feature of Jamstack and gives you a fighting chance to create a page that can hit 100 in Lighthouse. (But, hey, as a side note, remember that great scores aren’t always indicative of an actual user experience.)


See, I told you we could make Jamstack slow! There are also many other things that can slow it down, but hopefully this drives home the point.

While we’re talking about performance, here are a few of my favorite performance articles on here at CSS-Tricks:



Source link

r/graphic_design - Rebranding - JM Logo
Strategy

Rebranding – JM Logo : graphic_design


Good day! I am in the means of rebranding myself as a graphic designer, especially as my previous design has been referenced as an Adidas rip off lol.

I have had this design for some time, and this comment, and the extra free time, has allowed me to change up my design into something a bit more playful. Please see my new logo design with a quick branding solution for a background. There is a subtle nod to my home country in the design as well.

I would love any feedback on how to better my new design. I am not convinced of the colouring but wanted to create something more modern and diverse.

r/graphic_design - Rebranding - JM Logo



Source link

Google reCAPTCHA admin console
Strategy

Adding Google reCAPTCHA v3 to Your Laravel App


Hi there. I want to share with you how I implemented Google’s reCAPTCHA v3 in my Laravel app.

Securing HTML forms from bots is an essential part of the security of any web app these days. One common and easy solution to this is implementing a captcha system. And Google’s reCAPTCHA v3 makes it quite easy to both implement as a developer and use as a user (v3 users do not have to select images to verify).

Let’s get started.

Check out BestOfLaravel.com – One place to learn all things Laravel

Registering a New Site

First off, we need to register our site in Google reCAPTCHA Admin and gain usage keys. When you add your site, also add localhost in the list of domains, this will allow you to use the same key for development.

Google reCAPTCHA admin console

Once you submit these details, you should see two keys generated for your domain. One is the SITE KEY which is used in the front-end and the other is the SECRET KEYfor usage in the server.

Front-End Setup

The front-end setup is pretty simple. Choose the page in which you want to implement reCAPTCHA, in my case I have a contact form on a page.

The below code shows a contact form with a hidden input named recaptcha (it can be any name). Then at the end of that page add the reCAPTCHA’s JS library and once it’s ready we get a token and set it to the recaptcha input.

Front-end setup

Backend Setup

Backend Setup

The above code checks if the current request is from a bot. We do this by sending a post request to Google’s reCAPTCHA API with the SECRET KEY and the TOKEN from the front-end.

The resulting JSON has a property (success) that is set to false when Google detects a request from a bot. Below is an example of what is returned.

JSON from Google Api

Optimizing the Setup

Here’s a list of optimizations you could do to the above setup.

  1. Move the configuration keys to the .env file.
  2. Move the verification logic to a custom validator.

Both of these are covered in the tutorial to which I’ve linked below.

Conclusion

There you have it. It’s pretty simple to add Google’s reCAPTCHA to your app. I would suggest you add this to all pages that can be visited by a bot. If you have any doubts, leave your questions below and I will try to help you.

Related Tutorials



Source link

Three CSS Alternatives to JavaScript Navigation
Strategy

Three CSS Alternatives to JavaScript Navigation


Hey quick! You’ve gotta create the navigation for the site and you start working on the mobile behavior. What pattern do you choose? If you’re like most folks, it’s probably the “hamburger” menu that, when clicked, uses a little JavaScript to expand a vertical list of navigation links.

But that’s not the only option.

Depending on the context and contents of the navigation, there may be a JavaScript-free method that gets the job done while providing a more accessible experience.

It is considered best practice to use a progressive enhancement approach, building webpages for users with the oldest and least capable technology first, then introducing additional enhancements as support allows. If you can provide a quality experience for users with basic technology, then you might consider whether or not your webpage even requires JavaScript functionality at all. Leaving JavaScript out of the navigation can ensure that users are able to navigate your website even if JavaScript is disabled or network issues prevent scripts from loading — which are definitely wins.

Let’s look at three alternative patterns to the JavaScript-powered hamburger menu.

Alternative 1: Put the menu on a separate page

Who said navigation has to be in the header of every page? If your front end is extremely lightweight or if you have a long list of menu items to display in your navigation, the most practical method might be to create a separate page to list them all. The lightweight WordPress theme Susty utilizes this method for its navigation.

This pattern is especially useful for static websites that use filesystem routing. If the project is built using a static site generator, the page load might be imperceptible to the user and have the added benefit of keeping your templates as modular as possible.

All this takes is basically replacing the “Menu” button with a close button instead when the user is on the menu page. When clicked, we can take the user back to the last page they were on in a couple of ways. If we are using a server-side CMS, like WordPress, then we can grab the last URL using $_SERVER['HTTP_REFERER'] and set it as the “close” button URL.

But if we’re not using a server-side setup then, yeah, we might need a few lines of JavaScript to get that last URL.

<a href="https://MyHomePage.com" onclick="handleClick(event)">×</a>


<script>
  function handleClick(event) {
    // Don't follow the link
    event.preventDefault();
    // Go back to last visited page  
    window.history.back(); 
    // Bail out of the function
    return false;
  }
</script>

So, while I like this method and pattern, it might require JavaScript depending on the project.

Alternative 2: The horizontal scroller

This approach is perfect for shorter link lists and allows users to access all of the navigation items without opening anything or clicking away from where they are. GitHub uses this approach for sub-menus.

Using flexbox combined with a scrolling overflow in CSS will do the trick! 

Alternative 3: The CSS-only hamburger menu

Just because the hamburger menu pattern is often done with JavaScript doesn’t mean we have to use JavaScript. Using CSS pseudo-selectors and an HTML <input>, we can create a rich mobile menu and save JavaScript for other functionality that actually requires it.


See? Just because a convention is popular doesn’t mean it is the only way to do things. There are often simpler, more accessible methods, especially when it comes to navigation. It’s not much work to create functional, lightweight, immersive navigation without JavaScript and we get some nice benefits along the way. If you’ve created any interesting CSS-only navigation patterns, I’d love to see them — please share in the comments!



Source link

Drill down table demo
Strategy

Introducing a Drill Down Table API in Cube.js


Since the release of drill down support in version 0.19.23, you can build interfaces to let users dive deeper into visualizations and data tables. The common use case for this feature is to let users click on a spike on the chart to find out what caused it, or to inspect a particular step of the funnel — who has converted and who has not.

In this blog post, I’ll show you how to define drill downs in the data schema and build an interface to let users explore the underlying chart’s data. If you’re just starting with Cube.js, I highly recommend beginning with this Cube.js 101 tutorial and then coming back here. Also, if you have any questions, don’t hesitate to ask them in our Slack community.

You can check the online demo of the example here, and the source code is available on GitHub.

Drill down table demo

Let’s start hacking! 

Defining a Drill Down in the Data Schema

Let’s start by setting up a new project with Cube.js and configuring drill down support in the data schema. We’ll use PostgresQL and our example e-commerce dataset for this tutorial. You can download and import it by running the following commands.

Next, install the Cube.js CLI if you don’t have it already, and create a new project.

Make sure you have the following credentials in the .env file.

Now, we’re ready to launch the Cube.js server and navigate to the playground running at http://localhost:4000.

Once you’re in the playground, navigate to the Schema tab. Then, select the orders and users tables and click Generate Schema, as in the screenshot below.

Cube.js playground

This will generate a basic data schema for users and orders tables, which already includes the drillMembers property on the count measure. The drillMembers property contains a list of dimensions that will be used to show the underlying data when drilling into that measure.

Let’s take a closer look at the Orders cube and its count measure.

It already has the basic dimensions listed in the drillMembers property: id and createdAt. We can add additional dimensions to that list. We also can reference dimensions from joined cubes—in our case, from Users.

Let’s add more dimensions to the drillMembers property.

That’s all we need in the data schema to build our drill down. On the frontend, we’re going to make a bar chart to display orders over time. When a user clicks on the bar, our app will display the table inside the modal window, with details about the orders in that bar.

Building the Drill Down UI

We’ll use Cube.js templates to generate a frontend app. Navigate to the Dashboard App tab and select the Material-UI React Dashboard. It will take several minutes to set up the Dashboard App and install all the dependencies inside the dashboard-app folder in your project.

Please note: although we use React in this example, you can build the same drill down in Vue.js, Angular, or Vanilla JS.

The first step is to render a bar chart. We’re going to plot the count of orders over time, grouped by the status. Eventually, we want to let users click on a specific group and day to explore the underlying orders— e.g., orders created on June 20 and already shipped.

Let’s create a dashboard-app/src/DrillDownExample.js file with the following content.

The code snippet above is pretty straightforward. First, we load data with the useCubeQuery hook and render it later with Recharts. Next, let’s add some interactivity and let users click on the bars!

To be able to show the underlying data, we first need to figure out where the user clicked on the chart, and then construct a query to Cube.js to load that data. The user can click on any day in our bar chart and on any status of the order within that day. To describe that location, Cube.js uses two variables: xValues and yValues.

For example, the following values mean that the user wants to explore processing orders on June 6:

To generate a query that returns data for a drill down table, we need to use the ResultSet#drillDown() method. If we run it with the above values, like this:

it will return the query, which has all the dimensions from the drillMembers property in the data schema, as well as all required filters to specifically load processing orders on June 6.

Once we have the drill down query, we can use it to load data from the Cube.js API.

To get the values for xValues and yValues properties, we will use the ResultSet#chartPivot() and ResultSet#seriesNames() methods. chartPivot() returns xValues for every data row, and seriesNames() returns yValues per series. We’re going to use these methods to pass xValues and yValues to the Recharts to make sure we have them in the onClick handler.

First, let’s create a click handler, which will accept xValues and yValues, generate a drill down query, and store it in the state.

Now we need to make sure we pass both xValues and yValues to the handleBarClick. Since we pass resultSet.chartPivot() to the Recharts <BarChart /> component as a data property, the xValues will be available as the property on the event object in the onClick callback. To pass yValues, we need to make the following changes:

Now, as we have drillDownQuery in the state, we can query it in our component.

Later, you can use drillDownResponse to render the drill down data however you want. In our example, we use Material-UI Kit and render it as a table within the modal window.

Table rendered with MaterialUI

I hope you found this tutorial helpful for adding interactive drill downs to your application! You can check the online demo of the example here, and the source code is available on GitHub.

If you have any questions, please don’t hesitate to reach out to me in Cube.js Slack community.



Source link

r/graphic_design - Washington RedTails Concept
Strategy

Washington RedTails Concept : graphic_design


Heard about the name change so I drafted a concept for the new #Redskins potential name: The #RedTails. Watermark for art reasons.
“Red Tails” was the nickname for the P-51 Mustangs flown by Tuskegee Airmen, the first black military aviators in the U.S. Army Air Corps (AAC), during WWII.
This concept encapsulates the red “tails”, the mountainous terrain of D.C., and a patriotic palette. 🛩🏔🇺🇸

Logo work: Me
Background image: ©Peter Aiken/Getty Images

r/graphic_design - Washington RedTails Concept
r/graphic_design - Washington RedTails Concept





Source link