Skip to content

Projeto final da formação de CSS proposto pela dio.me, aproveitando o layout fiz a minha própria aplicação transformando-a em uma SPA (Router própio sem frameworks), utilizando web components, convenções de pastas e nomenclatura ITCSS e BEMIT, e usufluindo dos recursos do sass criando mixins.

Notifications You must be signed in to change notification settings

JoseAlvesdev/hbomax

Repository files navigation

Site HBO Max

Clone com modificações

O projeto é um clone do site HBO Max, com o intuito de reproduzir a interface, com algumas modificações, aplicando os temas abordados ao longo das aulas de CSS da plataforma da Digital Innovation One.

Eu utilizando como base o projeto da dio.me proposto pela Instrutora: Michele Ambrosio, implentei uma Single Page Aplication, utilizando-se de várias técnologias adicionais, como por exemplo a utilização de componentes nativos do JavaScript, também convenções de nomenclatura e estruturação.

📎 Sumário

✨ Features

  • Menu de navegação
  • Cabeçalho com animação gradiente
  • Cards com os planos de assinatura animados
  • Lista de filmes e séries disponíveis na plataforma
  • Formulário de login
  • Rodapé com links importantes
  • UI Responsiva

As features são visuais, não possuindo integração com nenhuma API. O intuito do projeto é reproduzir a interface do site original, com algumas modificações.

📦 Temas abordados

O projeto possui como intuito aplicar os conceitos abordados na Trilha de CSS da DIO, ministrada pela instrutora Michele Ambrosio.

Recursos CSS presentes no projeto:

  • Fundamentos do CSS
  • Grid Layout
  • Flexbox
  • Responsividade
  • Pseudo-elementos
  • Pseudo-classes
  • Transformações 2D e 3D
  • Transições e animações
  • Tratamento de campos inválidos no formulário

Melhorias na:

  • Responsividade
  • Estruturação
  • nomenclaturas

Implementações:

  • ViteJs
  • TypeScript
  • Web Components
  • SASS
  • SCSS
  • SPA
  • Página de não econtrada 404

Convenções utilizadas:

  • ITCSS
  • BEMIT

❗ Mixin utilizando SCSS

Cria uma lista de URL's, com o @each itera item por item, e por fim foi criadas seis classes, utilizando a variável counter para definir a posição específica de cada card.

$urls: (
  '/images/hbo-hover_0.webp',
  '/images/MAX-Hover.webp',
  '/images/DC-Hover.webp',
  '/images/WB-Hover.webp',
  '/images/CN-Hover.png',
  '/images/UCL-Hover.webp'
);

@mixin generate-hover-backgrounds($urls) {
  $counter: 1;

  @each $url in $urls {
    .c-contents__card:nth-child(#{$counter}):hover {
      cursor: pointer;
      background-image: url(#{$url});
    }

    $counter: $counter + 1;
  }
}

🔡 Router implementado

Router desenvolvido utilizando recursos nativos do JavaScript e do navegador.

// Views
import HomeView from './views/home.view';
import NotFoundView from './views/not-found.view';
import SignInView from "./views/signin.view";

// Interfaces
import IRoute from "./interfaces/IRoute.interface";
import IPotentialMatch from "./interfaces/IPotentialMatch.interface";

// Utils
import getElement from './utils/get-element.util';
import setClasses from './utils/set-classes.util';
import sleep from './utils/sleep.util';

const navigateTo = (url: string): void => {
  window.location.hash = url; // Muda o hash da URL
  router();
};

const router: () => Promise<void> = async (): Promise<void> => {
  const routes: IRoute[] = [
    { path: "#/", view: HomeView },
    { path: "#/signin", view: SignInView },
    { path: '#/404', view: NotFoundView }
  ];

  // Test each route potential match
  const potentialMatches: IPotentialMatch[] = routes.map((route: IRoute): IPotentialMatch => {
    return {
      route: route,
      isMatch: location.hash === route.path // Verifica o hash
    }
  });

  let match: IPotentialMatch | undefined = potentialMatches
    .find((potentialMatch: IPotentialMatch): boolean => potentialMatch.isMatch);

  if (!match) {
    // Verifica se o hash corresponde a um ID existente
    const hashId = location.hash.substring(1);
    const element = document.getElementById(hashId);
    
    if (element) {
      // Se o ID existir, não redireciona para 404
      match = { route: { path: '', view: HomeView }, isMatch: true }; // Usa uma view padrão
    } else {
      match = {
        route: routes.find((route: IRoute): boolean => route.path === '#/404') || routes[routes.length - 1],
        isMatch: true
      };
    }
  }

  const root: HTMLElement = getElement('#root');
  const view = new match.route.view();

  const init: () => Promise<void> = async (): Promise<void> => {
    root.innerHTML = await view.getHtml();
    setClasses(['main'], true, 'is-rendered');

    const isRendered: boolean 
      = getElement('main').classList.contains('is-rendered');

    if (isRendered) {
      getElement('#loader').classList.add('is-hidden');
      setClasses(['max-navbar', 'max-footer'], true, 'is-visible');
      await sleep(.3);
      setClasses(['#root'], false, 'is-show');
    }

    // Rolagem para o ID especificado no hash
    const hash: string = window.location.hash.substring(1); // Remove o '#'
    
    if (hash) {
      const element: HTMLElement | null = document.getElementById(hash);

      if (element) element.scrollIntoView({ behavior: 'smooth' }); // Rola suavemente para o elemento
      else console.warn(`Elemento com ID "${hash}" não encontrado.`);
    }
  }

  init();
};

window.addEventListener('hashchange', router); // Escuta mudanças no hash

document.addEventListener('DOMContentLoaded', (): void => {
  // Defina o hash padrão se estiver vazio
  if (!window.location.hash) window.location.hash = "#/"; // Defina o hash inicial como a página inicial

  document.body.addEventListener('click', (e: MouseEvent): void => {
    const target = e.target as HTMLElement;

    if (target.matches('[data-link]')) {
      e.preventDefault(); // Sempre prevenir o comportamento padrão
      const currentUrl: string = window.location.hash; // Obtém o hash atual
      const linkUrl: string = (target as HTMLAnchorElement).href.split('#')[1]; // Obtém o hash do link
      
      // Navega para o novo hash
      if (`#${linkUrl}` !== currentUrl) navigateTo(linkUrl); 
    }
  });

  router(); // Chama o router na inicialização
});

🔡 Inspiração

✅ Deploy

Você pode acessar ao resultado final do projeto clicando aqui.

💻 Autor

   Jose Alves
   Instagram | GitHub | LinkedIn




✔️ Por Jose Alves 🫡

About

Projeto final da formação de CSS proposto pela dio.me, aproveitando o layout fiz a minha própria aplicação transformando-a em uma SPA (Router própio sem frameworks), utilizando web components, convenções de pastas e nomenclatura ITCSS e BEMIT, e usufluindo dos recursos do sass criando mixins.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published