preface

Before this to rax.js official documents to learn to read a general understanding of the Rax framework, after the actual project practice and familiarity, the following is the source code warehouse of the whole project:

github

gitee

background

Because there is really no practical project tutorial or video about RAx. js framework online (except for fees), I have found a more appropriate React actual project video based on the package of React. Js, “Build a responsive travel website through React, Gatsby, GraphQL”. P】, rax.js + Ts + ESLint simple refactoring, with detailed comments on each page function point.

During this time, I was reading the React official website documents simultaneously, which really made sense by analogy.

Project overview

PC

The mobile terminal

The main directory

Interpret the main contents of the project

. ├ ─ ─ the README. Md ├ ─ ─ package. The json ├ ─ ─ SRC / / home directory │ ├ ─ ─ app. Json │ ├ ─ ─ app. Ts │ ├ ─ ─ assets / / static file directory │ │ ├ ─ ─ images / / picture │ │ │ ├ ─ ─ 1. JPG │ │ │ ├ ─ ─ 2. JPG │ │ │ ├ ─ ─ 21062901. Jpeg │ │ │ ├ ─ ─ 21062902. Jpeg │ │ │ ├ ─ ─ 21063001. Jpeg │ │ │ ├ ─ ─ 3. JPG │ │ │ └ ─ ─ 4. JPG │ │ └ ─ ─ SVG / / navigation bar │ │ └ ─ ─ bar. The SVG │ ├ ─ ─ the components / / head and tail components │ │ ├ ─ ─ Footer │ │ │ ├ ─ ─ Index. The module. The CSS │ │ │ └ ─ ─ index. The TSX │ │ └ ─ ─ the Header │ │ ├ ─ ─ index. The module. The CSS │ │ └ ─ ─ index. The TSX │ ├ ─ ─ config. Ts │ ├ ─ ─ │ ├─ Heavy Metal Exercises // Heavy metal exercises // Heavy metal exercises // Heavy metal exercises Has nothing to do with this project │ │ │ ├ ─ ─ components │ │ │ ├ ─ ─ index. The module. The CSS │ │ │ └ ─ ─ index. The TSX │ │ ├ ─ ─ Email │ │ │ ├ ─ ─ index. The module. The CSS │ │ │ └ ─ ─ index. The TSX │ │ ├ ─ ─ Hero │ │ │ ├ ─ ─ index. The module. The CSS │ │ │ └ ─ ─ index. The TSX │ │ ├ ─ ─ Home / / main page │ │ │ └ ─ ─ index. The TSX │ │ ├ ─ ─ Stats │ │ │ ├ ─ ─ index. The module. The CSS │ │ │ └ ─ ─ index. The TSX │ │ ├ ─ ─ Testimonials │ │ │ ├ ─ ─ index. The module. The CSS │ │ │ └ ─ ─ Index. The TSX │ │ └ ─ ─ Trips │ │ ├ ─ ─ index. The module. The CSS │ │ └ ─ ─ index. The TSX │ ├ ─ ─ typings. Which s / / ts configuration file │ └ ─ ─ utils / / │ ├ ─ index.ts │ ├ ─ ch.txtCopy the code

The project of actual combat

Before the actual project, we need to build the rax.js framework first.

The built-in configuration for personal choice is

  • App (Build universal application)
  • Web single-page application
  • TypeScript

configuration

app.json

The application configures routing information

{
  "routes": [{"path": "/"."source": "pages/Home/index"}]."window": {
    "title": "Suzuki 🎈"}}Copy the code

global.css

Global Style configuration

/* Global */
* {
  font-family: 'Roboto', sans-serif;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
a {
  color: red;
}
p {
  color: #000;
}

.button {
  white-space: nowrap;
  font-weight: bold;
  color: #fff;
  outline: none;
  border: none;
  min-width: 100px;
  cursor: pointer;
  text-decoration: none;
  transition: 0.3s ! important; } .button:hover {transform: translateY(-2px);
}
.buttonPrimary {
  background: #f26a2e;
}
.buttonPrimary:hover {
  background: #077bf1;
}
.buttonNoPrimary {
  background: #077bf1;
}
.buttonNoPrimary:hover {
  background: #f26a2e;
}
.buttonBig {
  padding: 16px 40px;
  font-size: 20px;
}
.buttonNoBig {
  padding: 10px 32px;
  font-size: 16px;
}
.buttonRound {
  border-radius: 50px;
}
.buttonNoRound {
  border-radius: 4px;
}
.icon {
  font-size: 1.4rem ! important; } .color1 {color: #047bf1;
}
.color2 {
  color: #f3a82e;
}
.color3 {
  color: #f34f2e;
}
.color4 {
  color: #3af576;
}
Copy the code

typings.d.ts

Used by ts to declare file types (such as image types)

declare module '*.module.css' {
  const classes: { [key: string] :string };
  export default classes;
}
// Configure the TS file suffix
declare module '*.jpg';
declare module '*.jpeg';
Copy the code

page

Home

A container for the entire project

src/pages/Home/

index.tsx

import { createElement } from 'rax';
import View from 'rax-view';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import Hero from '.. /Hero';
import Trips from '.. /Trips';
import Testimonials from '.. /Testimonials';
import State from '.. /Stats';
import Email from '.. /Email';

function Home() {
  // The project container
  return (
    <View id="home">
      <Header />
      <main>
        <Hero />
        <Trips />
        <Testimonials />
        <State />
        <Email />
      </main>
      <Footer />
    </View>
  );
}

export default Home;
Copy the code

Header

Item header navigation bar

src/components/Header/

index.tsx

import { createElement, useEffect, useState } from 'rax';
import styles from './index.module.css';
import { routerLink } from '@/utils/index';

function Header() {
  / / navigation
  const menuData: {
    title: string;
    link: string;
  }[] = [
    {
      title: 'Trips'.link: 'trips'}, {title: 'About'.link: 'about'}, {title: 'Careers'.link: 'careers'}, {title: 'Contact'.link: 'contact',},];// Listen for events
  const [hasVerticalScrolled, setState] = useState(false);
  useEffect(() = > {
    window.addEventListener('scroll', bindHandleScroll);
    return () = > {
      window.removeEventListener('scroll', bindHandleScroll);
    };
  });
  const bindHandleScroll = (event) = > {
    // The height of the roll
    const scrollTop =
      (event.srcElement ? event.srcElement.documentElement.scrollTop : false) | |window.pageYOffset ||
      (event.srcElement ? event.srcElement.body.scrollTop : 0);
    window.console.log(scrollTop, scrollTop > 100);
    setState(() = > scrollTop > 100);
  };
  return (
    / / header bar
    <div className={` ${styles.navContainer} ${hasVerticalScrolled ? styles.navContainer2 :"'} `} >{labels / * * /}<div className={styles.navLink} onClick={()= > routerLink('home')}>
        EXPLORIX
      </div>{/* Respond back bar icon */}<div className={styles.navBar} />
      {/* navMenu */}
      <div className={styles.navMenu}>
        {menuData.map((item) => {
          return (
            <div className={styles.navLink} key={item.link} onClick={()= > routerLink(item.link)}>
              {item.title}
            </div>
          );
        })}
      </div>
      {/* navBtn */}
      <div className={styles.navBtn}>
        <div className="button buttonPrimary buttonNoBig buttonRound" onClick={()= > routerLink('trips')}>
          Book a Flight
        </div>
      </div>
    </div>
  );
}

export default Header;

Copy the code

index.module.css

.navContainer {
  background: transparent;
  height: 80rpx;
  display: flex;
  justify-content: space-evenly;
  padding: 0.5 rem calc((100vw - 1300rpx) / 2);
  z-index: 100;
  position: relative;
}
.navContainer2 {
  background: rgba(0.0.0.0.4);
  position: sticky;
  top: 0;
}

.navLink {
  color: #fff;
  display: flex;
  font-size: 20px;
  align-items: center;
  text-decoration: none;
  padding: 0 2rem;
  height: 100%;
  cursor: pointer;
}

.navBar {
  background: url('.. /.. /assets/svg/bar.svg')  no-repeat;
  background-size: 1.8 rem;
  display: block;
  color: #fff;
}
@media screen and (max-width: 768px) {
  .navBar {
    display: block;
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    right: 0;
    transform: translate(90%.40%); }}.navMenu {
  display: flex;
  align-items: center;
  margin-right: 48rpx;
}
@media screen and (max-width: 768px) {
  .navMenu {
    display: none; }}.navBtn {
  display: flex;
  align-items: center;
  margin-right: 24px;
}
@media screen and (max-width: 768px) {
  .navBtn {
    display: none; }}Copy the code

src/utils/

index.ts

Changes the jump of the hash route to a native anchor point jump

/ * * *@description Jump anchor point *@param url* /
export const routerLink = (url: string) = > {
  if (url) {
    // Find the anchor point
    const anchorElement = document.getElementById(url);
    // Jump to the anchor point if the corresponding id exists
    if (anchorElement) {
      anchorElement.scrollIntoView({ block: 'start'.behavior: 'smooth'}); }}};Copy the code

src/assets/svg/

bar.svg

Hero

Giant screen video and project introduction on the home page

src/pages/Hero/

index.tsx

import { createElement } from 'rax';
import { history } from 'rax-app';
import View from 'rax-view';
import styles from './index.module.css';

function Hero() {
  return (
    // Home screen
    <View id="hero">
      <div className={styles.HeroContainer}>{/* Background video */}<div className={styles.HeroBg}>
          <video src="https://mp4.vjshi.com/2020-11-19/34b1f460a8a9fcc283c4edc8fe43b32f.mp4" type="video/mp4" autoPlay loop muted playsInline className={styles.VideoBg} />
        </div>Content of {/ * * /}<div className={styles.HeroContent}>
          <div className={styles.HeroItems}>
            <h1 className={styles.HeroH1}>On the way to your dreams</h1>
            <p className={styles.HeroP}>Out of this world!</p>
            <span onClick={()= >History.push ('/trips')} className="button buttonPrimary buttonBig buttonNoRound"</span>
          </div>
        </div>
      </div>
    </View>
  );
}

export default Hero;

Copy the code

An attempt to import a local background video failed. Asked the corresponding community, the suggestion is to use online links, CDN and other forms of introduction

index.module.css

.HeroContainer {
  background: #0c0c0c;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  padding: 0 1rem;
  position: relative;
  margin-top: -80rpx;
  color: #fff;
}
.HeroContainer::before {
  content: ' ';
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  z-index: 2;
  background: linear-gradient(180deg.rgba(0.0.0.0.2) 0%.rgba(0.0.0.0.6) 100%),
    linear-gradient(180deg.rgba(0.0.0.0.2) 0%, transparent 100%);
}

.HeroBg {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.VideoBg {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
  object-fit: cover;
}

.HeroContent {
  z-index: 3;
  height: calc(100vh - 80rpx);
  max-width: 100%;
  padding: 0 calc((100vw - 1300rpx) / 2);
}

.HeroItems {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  height: 100vh;
  max-height: 100%;
  padding: 0;
  color: beige;
  line-height: 1.1;
  font-weight: bold;
}

.HeroH1 {
  font-size: clamp(1.5 rem.6vw.4rem);
  margin-bottom: 1.5 rem;
  letter-spacing: 3px;
  padding: 0 1rem;
}

.HeroP {
  font-size: clamp(1rem.3vw.3rem);
  margin-bottom: 2rem;
  color: #fff;
  font-weight: 400;
}
Copy the code

Trips

Travel page

src/pages/Trips/

index.tsx

import { createElement } from 'rax';
import View from 'rax-view';
import Image from 'rax-image';
import styles from './index.module.css';
import { Icon } from '@alifd/meet';
import img1 from '@/assets/images/1.jpg';
import img2 from '@/assets/images/2.jpg';
import img3 from '@/assets/images/3.jpg';
import img4 from '@/assets/images/4.jpg';

function Trips() {
  / / attractions
  const trips: {
    id: number;
    img: any;
    alt: string;
    name: string;
    button: string;
  }[] = [
    {
      id: 1.img: img1,
      alt: 'Snow Mountain '.name: 'Snow Mountain '.button: 'View Destination'}, {id: 2.img: img2,
      alt: 'Snow Mountain '.name: 'Snow Mountain '.button: 'View Destination'}, {id: 3.img: img3,
      alt: 'Aurora BeiJi'.name: 'Aurora BeiJi'.button: 'View Destination'}, {id: 4.img: img4,
      alt: 'Church '.name: 'Church '.button: 'View Destination',},];return (
    <View id="trips">
      <div className={styles.productsContainer}>The title * /} {/ *<div className={styles.productsHeading}>Our Favorite Destinations</div>{/* picture card */}<div className={styles.productsWrapper}>
          {trips.map((item) => (
            <div key={item.id} className={styles.productCard}>Picture * /} {/ *<Image className={styles.productsImg} source={{ uri: item.img }} alt={item.alt} />Content of {/ * * /}<div className={styles.productInfo}>
                <div className={styles.textWrap}>
                  {/* icon */}
                  <Icon className="icon" type="heart-filling" />
                  <div className={styles.productTitle}>
                    {item.name}
                  </div>
                </div>* /} {/ * button<span className={` ${styles.tripBtn} button buttonPrimary buttonNoBig buttonRound`} >
                  {item.button}
                </span>
              </div>
            </div>
          ))}
        </div>
      </div>
    </View>
  );
}

export default Trips;

Copy the code

You cannot import images directly in JSX. Use import to import image files, and you need to set the declaration image files because of TS

index.module.css

.productsContainer {
  min-height: 100vh;
  padding: 5rem calc((100vw - 1300rpx) / 2);
  color: #fff;
}

.productsHeading {
  font-size: clamp(1.2 rem.5vw.3rem);
  text-align: center;
  margin-bottom: 5rem;
  color: # 000;
}

.productsWrapper {
  display: grid;
  grid-template-columns: repeat(4.1fr);
  grid-gap: 10px;
  justify-items: center;
  padding: 0 3rem;
} 
@media screen and (max-width: 1200px) {
  .productsWrapper {
    grid-template-columns: 1fr 1fr; }}@media screen and (max-width: 868px) {
  .productsWrapper {
    display: grid;
    grid-template-columns: 1fr; }}.productCard {
  line-height: 2;
  display: flex;
  justify-content: center;
  width: 100%;
  height: 70vh;
  position: relative;
  border-radius: 10px;
  transition: 0.2 s ease;
}

.productsImg {
  height: 100%;
  max-width: 100%;
  position: absolute;
  border-radius: 10px;
  filter: brightness(70%);
  transition: 0.4 s cubic-bezier(0.075.0.82.0.165.1);
}

.productsImg:hover {
  filter: brightness(100%);
}

.productInfo {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 3rem;
}
@media screen and (max-width: 280px) {
  .productInfo {
    padding: 0 1.5 rem; }}.textWrap {
  display: flex;
  align-items: center;
  position: absolute;
  top: 360px;
} 

.productTitle {
  font-weight: 400;
  font-size: 1rem;
  margin-left: 0.5 rem;
}

.tripBtn {
  position: absolute;
  top: 420px;
  font-size: 14px;
}

Copy the code

src/assets/images/

Tourism image

Testimonials

Customer evaluation recommendation page

src/pages/Testimonials/

index.tsx

import { createElement } from 'rax';
import View from 'rax-view';
import styles from './index.module.css';
import { Icon } from '@alifd/meet';
import Image from 'rax-image';
import img1 from '@/assets/images/21062901.jpeg';
import img2 from '@/assets/images/21062902.jpeg';

function Testimonials() {
  / / picture
  const images: {
    id: number;
    img: any;
  }[] = [
    {
      id: 1.img: img1,
    },
    {
      id: 2.img: img2,
    },
  ];
  return (
    // About us
    <View id="about">
      <div className={styles.testimonialsContainer}>The title * /} {/ *<div className={styles.topLine}>Testimonials</div>
        <div className={styles.description}>What People are Saying</div>{/ * * / container}<div className={styles.contentWrapper}>
          <div className={styles.columnOne}>{/* Description 1 */}<div className={styles.testimonial}>
              <Icon className={` ${styles.color1} ${styles.icon} `}type="success" />
              <h3>Ling Mu</h3>
              <p>
                You have unique gifts and talents that no one else in this world has. Sometimes we feel that we needto
                be someone else in order to fit in be a better mother or wife or portray an image that we believele else
                will love. No matter how hard you try to be someone else you will never be good enoughYou will do the
                best and be the happiest only if you st op living by someone else&apos;s standards and startusing your
                unique potential to shine like a light in this world
              </p>
            </div>{/* Description 2 */}<div className={styles.testimonial}>
              <Icon className={` ${styles.color2} ${styles.icon} `}type="favorites-filling" />
              <h3>Qi Qiu</h3>
              <p>
                Sooner or later, the time comes when we all must become responsible adults and learn to give up what we
                want, so we can choose to do what is right. Of course, a lifetime of responsibility isn&apos;t always
                easy. And as the years go on, it&apos;s a burden that can become too heavy for some to bear. But still
                we try to do what is best, what is good. Not only for ourselves, but for those we love. Yes, sooner or
                later we must all become responsible adults. No one knows this better than the young.
              </p>
            </div>
          </div>Picture * /} {/ *<div className={styles.columnTwo}>
            {images.map((item) => (
              <div key={item.id}>
                <Image className={styles.Images} source={{ uri: item.img}} / >
              </div>
            ))}
          </div>
        </div>
      </div>
    </View>
  );
}

export default Testimonials;

Copy the code

You cannot import images directly in JSX. Use import to import image files, and you need to set the declaration image files because of TS

index.module.css

.testimonialsContainer {
  width: 100%;
  background: #fcfcfc;
  color: # 000;
  padding: 5rem calc((100vw - 1300rpx) / 2);
  height: 100%;
}

.topLine {
  color: #077bf1;
  font-size: 2rem;
  padding-left: 6rem;
  margin-bottom: 0.75 rem;
}

.description {
  text-align: start;
  padding-left: 6rem;
  margin-bottom: 4rem;
  font-size: clamp(1.5 rem.5vw.2rem);
  font-weight: bold;
}

.contentWrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 0 6rem;
}
@media screen and (max-width: 1200px) {
  .contentWrapper {
    grid-template-columns: 1fr; }}.columnOne {
  display: grid;
  grid-template-rows: 1fr 1fr;
}

.testimonial {
  padding-top: 1rem;
  padding-right: 2rem;
}

h3 {
  margin-bottom: 1rem;
  font-size: 2rem;
  font-style: italic;
}

p {
  color: #3b3b3b;
  font-size: 1.2 rem;
}

.columnTwo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-top: 2rem;
  grid-gap: 10rpx;
}
@media screen and (max-width: 1200px) {
  .columnTwo {
    grid-template-columns: 1fr; }}.Images {
  border-radius: 10px;
  height: 100%;
  width: 100%;
}

.icon {
  font-size: 2rem;
  margin-bottom: 1rem;
}

.color1 {
  color: #3fffa8;
}

.color2 {
  color: #f9b19b;
}
Copy the code

src/assets/images/

State

The characteristics of the page

src/pages/State/

index.tsx

import styles from './index.module.css';
import { createElement } from 'rax';
import View from 'rax-view';
import { Icon } from '@alifd/meet';

function State() {
  / / Icon Icon
  const statsData: {
    id: number;
    icon: string;
    title: string;
    desc: string;
  }[] = [
    {
      id: 1.icon: 'camera'.title: 'Over 100 Destinations'.desc: 'Travel to over 100 unique places'}, {id: 2.icon: 'exit'.title: '1 Million Trips Made'.desc: 'Over 1 million trips completed last year'}, {id: 3.icon: 'dashboard'.title: 'Fastest Support'.desc: 'Access our support team 24/7'}, {id: 4.icon: 'smile'.title: 'Best Deals'.desc: 'We offer the best prices',},];return (
    / / features
    <View id="careers">
      <div className={styles.statsContainer}>Description * /} {/ *<h1 className={styles.heading}>Why choose us ?</h1>{/* Icon container */}<div className={styles.statsWrapper}>
          {statsData.map((item, index) => {
            return (
              <div className={styles.statsBox} key={item.id}>
                <Icon type={item.icon} className={` ${styles.icon} colorThe ${index + 1} `} / >
                <p className={styles.title}>{item.title}</p>
                <p className={styles.desc}>{item.desc}</p>
              </div>
            );
          })}
        </div>
      </div>
    </View>
  );
}

export default State;

Copy the code

The main use of Icon

index.module.css

.testimonialsContainer {
  width: 100%;
  background: #fcfcfc;
  color: # 000;
  padding: 5rem calc((100vw - 1300rpx) / 2);
  height: 100%;
}

.topLine {
  color: #077bf1;
  font-size: 2rem;
  padding-left: 6rem;
  margin-bottom: 0.75 rem;
}

.description {
  text-align: start;
  padding-left: 6rem;
  margin-bottom: 4rem;
  font-size: clamp(1.5 rem.5vw.2rem);
  font-weight: bold;
}

.contentWrapper {
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 0 6rem;
}
@media screen and (max-width: 1200px) {
  .contentWrapper {
    grid-template-columns: 1fr; }}.columnOne {
  display: grid;
  grid-template-rows: 1fr 1fr;
}

.testimonial {
  padding-top: 1rem;
  padding-right: 2rem;
}

h3 {
  margin-bottom: 1rem;
  font-size: 2rem;
  font-style: italic;
}

p {
  color: #3b3b3b;
  font-size: 1.2 rem;
}

.columnTwo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-top: 2rem;
  grid-gap: 10rpx;
}
@media screen and (max-width: 1200px) {
  .columnTwo {
    grid-template-columns: 1fr; }}.Images {
  border-radius: 10px;
  height: 100%;
  width: 100%;
}

.icon {
  font-size: 2rem;
  margin-bottom: 1rem;
}

.color1 {
  color: #3fffa8;
}

.color2 {
  color: #f9b19b;
}
Copy the code

src/assets/images/

Email

Email page

src/pages/Email/

index.tsx

import { createElement } from 'rax';
import View from 'rax-view';
import styles from './index.module.css';

function Email() {
  return (
    / / email
    <View>{/* container + image */}<div className={styles.emailContainer}>
        <div className={styles.emailContent}>Description * /} {/ *<h1 className={styles.emailH1}>Get Access to Exclusive Offers</h1>
          <p className={styles.emailP}>Sign up for your newsletter below to get $100 off your first trip!</p>{/* form */}<div className={styles.formWrap}>
            <label htmlFor="email">
              <input type="email" placeholder="Please enter your email address." id="email" />
            </label>
            <span className="button buttonPrimary buttonBig buttonRound">registered</span>
          </div>
        </div>
      </div>
    </View>
  );
}

export default Email;

Copy the code

index.module.css

.emailContainer {
  background: linear-gradient(
    180deg.rgba(0.0.0.0.5) 0%.rgba(0.0.0.0.5) 35%.rgba(0.0.0.0.1) 100%
  ),
    url('.. /.. /assets/images/21063001.jpeg') no-repeat center;
  background-size: cover;
  height: 650px;
  width: 100%;
  padding: 5rem calc((100vw - 1300px) / 2);
  color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

.emailContent {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.emailH1 {
  text-align: center;
  margin-bottom: 1rem;
  font-size: clamp(1rem.5vw.3rem);
  padding: 0 1rem;
}

.emailP {
  text-align: center;
  font-size: clamp(1rem.2.5 vw.1.5 rem);
  padding: 0 1rem;
  margin-bottom: 2rem;
  color: #fff;
}

form {
  z-index: 10;
}

input {
  padding: 1rem 1.5 rem;
  outline: none;
  width: 450px;
  height: 60px;
  border-radius: 50px;
  border: none;
  margin-right: 1rem;
}
@media screen and (max-width: 768px) {
  .formWrap {
    display: flex;
    flex-direction: column;
    padding: 0 1rem;
  }
  input {
    margin-bottom: 1rem;
    width: 100%;
    margin-right: 0; }}@media screen and (max-width: 768px) {
  .button {
    width: 100%;
    min-width: 450px; }}Copy the code

src/assets/images/

Email pictures

Footer

Item bottom bar

src/components/Footer/

index.tsx

import { createElement } from 'rax';
import View from 'rax-view';
import styles from './index.module.css';

function Footer() {
  return (
    / / at the bottom of the column
    <View id="contact">
      <div className={styles.footerContainer}>{/* First column */}<div className={styles.footerLinkWrapper}>{labels / * * /}<div className={styles.footerDesc}>
            <h1>Expel</h1>
            <p>We strive to create the best experiences for our customers</p>
          </div>
          <div className={styles.footerLinkItems}>
            <h2 className={styles.footerLinkTitle}>Contact us</h2>
            <div className={styles.footerLink}>
              Contact
            </div>
            <div className={styles.footerLink}>
              Support
            </div>
            <div className={styles.footerLink}>
              Destinations
            </div>
            <div className={styles.footerLink}>
              Sponsorships
            </div>
          </div>
        </div>{/* Second column */}<div className={styles.footerLinkWrapper}>
          <div className={styles.footerLinkItems}>
            <h2 className={styles.footerLinkTitle}>audio</h2>
            <div className={styles.footerLink}>
              Submit Video
            </div>
            <div className={styles.footerLink}>
              Ambassadors
            </div>
            <div className={styles.footerLink}>
              Agency
            </div>
            <div className={styles.footerLink}>
              Influencer
            </div>
          </div>

          <div className={styles.footerLinkItems}>
            <h2 className={styles.footerLinkTitle}>Content of the community</h2>
            <div className={styles.footerLink}>blog</div>
            <div className={styles.footerLink}>The Denver nuggets</div>
            <div className={styles.footerLink}>zhihu</div>
            <div className={styles.footerLink}>
              WeChat
            </div>
          </div>
        </div>
      </div>
    </View>
  );
}

export default Footer;

Copy the code

index.module.css

.footerContainer {
  padding: 5rem calc((100vw - 1100px) / 2);
  display: grid;
  grid-template-columns: repeat(2.1fr);
  color: # 000;
  background: #fafafb;
  font-size: 14px;
}

.footerDesc {
  padding: 0 2rem;
}
.footerDesc h1 {
  margin-bottom: 3rem;
  color: #f26a2e;
}
@media screen and (max-width: 400px) {
  .footerDesc {
    padding: 1rem; }}.footerLinkWrapper {
  display: grid;
  grid-template-columns: repeat(2.1fr);
}
@media screen and (max-width: 820px) {
  .footerLinkWrapper {
    grid-template-columns: 1fr; }}.footerLinkItems {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 1rem 2rem;
}
@media screen and (max-width: 400px) {
  .footerLinkItems {
    padding: 1rem; }}.footerLinkTitle {
  font-size: 18px;
  margin-bottom: 16px;
}

.footerLink {
  text-decoration: none;
  margin-bottom: 0.5 rem;
  font-size: 16px;
  color: #3d3d4e;
}
.footerLink:hover {
  color: #f26a2e;
  transition: 0.3 s ease-out;
}

Copy the code

After the speech

The final project

When the above content is completed, the final display effect of the project will be carried out again:

PC

mobile

The video tutorial technology stack is React, Gatsby and GraphQL. During this period, I used some skills to refactor Rax for this project, and some React peripheral plug-ins were also replaced with the Rax official website document examples.

During this period, I was familiar with JSX syntax, partial Hooks use, TS syntax and the basic content of Rax. But the weaknesses lie in several areas:

  • Communication of components, data flow, etc
  • Back-end network communication of Rax
  • Testing (which I am very poor at)
  • Build the deployment

In my opinion, the following areas can be optimized:

  • The CSS to sass
  • The transition of anchor points should be made using tranforms, etc., which have been tried but not well implemented
  • Home should be turned into a real layout
  • Further modular components
  • Package builds (weak)

In the end, I feel that to learn Rax well, I need to lay a good foundation of React. Although there are many things I can understand by analogy, I still need to study it carefully. After learning it, I need to be able to use it in appropriate scenarios.

If you want the source code below is the warehouse address ~ save rolling to the beginning of github Gitee if there are improvements please guide one or two oh! Thank~