Skip to content

jeremy-step/next-laravel-cms-front

Repository files navigation

Ask DeepWiki

Next.js Interface for the Laravel Next Headless CMS

Developer Docs:

Installation

  • Read the Next.js 15 docs to see what is required for development (Next.js Docs)
  • Install the API CMS repository - Repo Here
    • For now, both repositories must be installed in the same directory
  • Duplicate the env.local.example file and rename it to env.local
    • Configure the application URLs
    • Configure fetch delay simulation
      • null means the simulation will execute if in dev mode
      • true means the simulation will allways execute
      • false means the simulation will never execute
  • Do the following:
    • Run pnpm install or npm install
    • Run pnpm dev or npm run dev
  • Default hosts for frontend and api are localhost:3000 and localhost:8000 respectively

App Router

The frontend / public area can be found in src/app/(front).

The backend / control panel can be found in src/app/(back).

Sitemap / Robots.txt

Both are autogenerated by Next.js with data provided by the CMS.

Should you need the modify them, the appropiate files are in src/app/sitemap.ts and src/app/robots.ts.


UI

Both the frontend and backend have separate UI files found in src/ui/_front and src/ui/_back respectively.

Shared components are in src/ui/components.

Favicons must be included in the src/app directory. For more information, checkout the Favicon Next.js docs.


Helpers and Hooks

Object Helpers (@cms/helpers)

The following multidimensional object helpers are available:

  • type SimpleObject<T = unknown> = { [key: string]: T }
  • setObject(object: SimpleObject, path: string, value: unknown): SimpleObject

    Allows to set a mutidimensional element in the provided object using the dot notation.

    If we provide an empty object and set a value of Hello there! to the foo.bar path, then the updated object is returned:

    { foo: { bar: "Hello there!" } }

  • findInObject(object: SimpleObject, path: string): unknown

    Allows to find a mutidimensional element in the provided object using the dot notation.

    If we have the following object: { foo: { bar: "Hello there!" } } and provide the following path: foo.bar, then the Hello there! value is returned.

    If the path is incorrect, undefined is returned.

  • formDataToObject(formData: FormData, ...fields: string[]): SimpleObject

    Converts FormData fields to a simple object. For multidimensional fiels, use the dot notation instead of the stardard array notation.

    field[items][item1] - incorrect
    
    field.items.item1 - correct
    

    If you need an equivalent to field[], you can use field.*. However, only 1 star is supported.

    field.*
    field.*
    field.*
    
    Will result in:
    
    field.0
    field.1
    field.2
    

    Deeper levels can be chained afterwards: field.*.item.

    Accepts the FormData object as the first argument and an enumeration of fields that should be included in the returned object.

  • formDataToJson(formData: FormData, ...fields: string[]): string

    Same as the formDataToObject, except it returns a JSON string of the object.

Forms

  • type FormMessage = { message?: string; }
  • type FormErrors = { errors?: SimpleObject<string[]>; }
  • type FormState = (SimpleObject & FormMessage & FormErrors) | null | undefined

Sleep (@cms/helpers)

  • async sleep(seconds: number): Promise<void>

    Allows to add a delay in seconds before continuing the code execution.

UI Hooks (@cms/hooks)

  • type WindowSize = { width: number | undefined; height: number | undefined; };
  • useWindowSize(): WindowSize

    Returns the inner window size. Values are updated on resize.

    {
        width: number | undefined,
        height: number | undefined
    }
    
  • useSetSourceMedia(...pictures: React.RefObject<HTMLPictureElement | null>[]): void

    Accepts React Refs of <picture /> elements that contain images that should change depending on the current theme (dark or light).

    Automatically changes the image if the theme is manually toggled.

Events (@cms/events)

  • type EventTarget = Element | Document | Window
  • type EventListener = EventListenerOrEventListenerObject
  • type EventOptions = boolean | AddEventListenerOptions
  • eventListener.add(target: EventTarget, event: string, listener: EventListener, options?: EventOptions): void

    Add an event listener to a target. Supports named (jQuery style) events: click.primary-button. This makes managing multiple events of the same type on one element easier.

    First argument is the target, rest are the same as the default addEventListener method (MDN Docs).

    const options = ...;
    
    eventListener.add(element, 'click.myClickEvent', (e) => alert(e.type), options);
    
  • eventListener.remove(target: EventTarget, event: string): void

    Remove an event listener from a target by named event.

    eventListener.remove(element, 'click.myClickEvent');
    

Router (@cms/router)

App URLs defined in the .env.local config are exported as ApiUrl and FrontUrl constants.

Links

  • type LinkParams = SimpleObject | URLSearchParams
  • link(name: RouteName, params?: LinkParams, absolute = false): string

    Generates a front url (relative by default) from a route name. The route names are defined in the RouteName type.

    Accepts a params parameter, can be either a simple or URLSearchParams object. Params are either included as route segments or URL query, depending on the route definition.

    If a param is required and not included, an exception is thrown.

    For example, the link for the route /users/{userId} with { userId: 'random-id', only: 'first-name' } params would look like this: /users/random-id?only=first-name

  • permalink(page: Page, params?: LinkParams, absolute = false): string

    Helper to generate a page permalink (relative by default). Works the same as the link function, but instead of a route name, it accepts a Page object.

  • linkApi(name: RouteName, params?: LinkParams): string

    Same as link except it generates API URLs, always absolute.

  • searchParamsToObject(searchParams: URLSearchParams): SimpleObject

    Helper to convert URLSearchParams to a simple object.

Routes

  • type Route
    {
        name: RouteName;
        data: SimpleObject & {
            uri: string;
            pattern: string;
            methods: string[];
            parameters?: string[];
            wheres?: SimpleObject<string>;
            middleware?: string[];
        };
        pattern: URLPattern;
        segments?: RouteSegments;
    }
    
  • getRoutes(): Route[]

    Gets all front routes.

    This can also be accessed from the exported routes constant.

  • getRoute(name: RouteName): Route

    Gets a front route by name.

  • routeExists(name: string): boolean

    Checks if a front route exists by name.

  • getRouteByUrl(url: string): Route | null

    Gets a front route from a url string (can be relative or absolute).


Fetching (@cms/fetch)

Server only fetching. Automatically sets headers neccessary for correct communication between the frontend and API, such as: Content Type and AJAX headers, XSRF Token, Correct IP and User Agent and Cookies.

Because it's a server to server communication (the Next.js server acts as a proxy), the IP and User Agent need to be set manually. Otherwise the API will receive the IP and User Agent of the Next.js server instead of the client.

Delay Simulation

In any server action you can call an async function to simulate a longer response time of a fetch. By default it will only run in development mode. You can force it globally by setting the SIMULATE_FETCH_DELAY env variable to true. Or disable it completely by setting it to false.

  • async simulateDelay(seconds: number, force = false): Promise<void>

    Accepts a number of seconds the delay should last. You can also individually force the delay in production by setting the force argument to true.

Headers

  • async defaultHeaders(freshCookies: boolean): Promise<HeadersInit>

    Returns a HeadersInit object with all the necessary default headers for fetching the API.
    Accepts a freshCookies boolean parameter to refresh the cookies used in the fetch request, including the XSRF token.

Fetch

  • async fetchCsrf(): Promise<Response>

    Fetches a fresh XSRF token from the API.

  • async fetchApi(url: string, init?: RequestInit, freshCookies = false): Promise<Response>

    Fetches a specific API endpoint. Automatically includes default headers and cookies. Additional request configuration can be included by passing a RequestInit object to the init parameter. To refresh the cookies before the request, set the freshCookies parameter to true.

  • async apiData(url: string, init?: RequestInit): Promise<Response>

    Helper fetchApi function to get API data. Does not refresh cookies. Default method is GET.

  • async apiAction(url: string, init?: RequestInit): Promise<Response>

    Helper fetchApi function to perform an API action. Refreshes cookies. Default method is POST.


Cookies (@cms/cookies)

Get Cookies

  • async getCookieStore(): Promise<ReadonlyRequestCookies>

    Returns the Next.js Cookie Store. (Next.js Cookies Docs)

  • async getCookie(name: string): Promise<RequestCookie>

    Returns a specific cookie by name from the Next.js Cookie Store.

  • async getCookies(): Promise<RequestCookie[]>

    Returns an array of all cookies, in the format of the Next.js RequestCookie object.

  • async getCookies(...names: string[]): Promise<(RequestCookie | undefined)[]>

    Returns an array of specific cookies by their names, in the format of the Next.js RequestCookie object or undefined if the cookie does not exist.

  • async getCookieString(): Promise<string>

    Returns a properly formatted cookie string that can be included in the Cookies request header.

Set Cookies

  • async setCookie(cookie: string, response?: NextResponse): Promise<void>

    Set a single cookie with key=value; string notation.

    my_cookie=value; expires=Thu, 01 Dec 2024 12:00:00 GMT; Max-Age=7200; path=/; domain=.domain.tld; httponly; samesite=lax
    

    By default, the current request cookie storage is used to set the cookie. Optionally, a NextResponse response object can be passed as a second argument. In that case, the response cookie storage will be used instead.

    This is usefull for changing responses in middleware, for example.

  • async setCookies(cookie: string[], response?: NextResponse): Promise<void>

    Set multiple cookies at once. First argument accepts an array of cookie strings.
    Second argument accepts a NextResponse object. Refer to setCookie for more info.


Middleware (@cms/middleware)

...


Server Actions

...


User Docs:

First Usage

After the installation, the administration is available under the /control-panel URL path. For example:
If the website address is https://www.example.com, then the https://www.example.com/control-panel URL should be visited to access the administration.

You will need to login first, if you try to access the administration without an authenticated session, you will be redirected to the login page.

The default username and password after the first installation are admin and admin. You should change the e-mail and password as soon as you login for the first time.


Dashboard

The Dashboard contains a table with all current active user sessions. The following information is displayed:

  • User name
  • Last activity
  • Time of login
  • Browser
  • Device
  • IP address

Users

All users registered are displayed in a paginated table / list (15 users per page). From here every profile can be accessed.

Every user has the ability to modify their own profile. That includes information such as their full name, the name displayed with any resource they created, e-mail, phone number, login username and password.

The owner of the website also has the ability to invite and delete users. The invite section is displayed next to the users table. Simply introduce a valid e-mail address and the user receives an invitation link to register. Only invited users can register and they must use the same e-mail address on which they received the invitation link.


Pages

All created pages are displayed in a paginated table / list (15 pages per page). Each page can be visited, edited and delete from here. In the top right corner of the table can be found a "create" button.

Create Page

To create a new page, simply introduce the title and text / content, optionally you can also mark the page as "not published" above the main form. The content supports the markdown syntax. In the future, a visual editor will be added for easier content management. On the right side, the meta data section can be found. This becomes editable once the page is created. The page link is automatically generated based on the title. If the title already exists, random characters are added to the page link.

Edit Page

Same as the "create page" form, except now you can edit the meta data of the page. The page link must always be unique, otherwise random characters will be added automatically at the end. It is recommended to introduce unique page title and description in the meta data section for better SEO performance.

Search Engine crawling can be adjusted with the "Robots" field.

Additionally you can include or ommit the page from the sitemap, set the frequency of changes and the priority of the page in the sitemap.

Visit Page

Each "published" page can be visited in the "public" are of the website using the link associated with the page.

If the link is incorrect or the page is not published, a "not found" error page will be displayed instead.


Settings

The Settings area is accessible only to the owner of the website. Here you can set the default front page and website name.

It is also necessary to configure the e-mail settings. The "Log" mailer option is meant for testing purposes. In order to send e-mails, including user invitations, it is necessary to configure a SMTP server. Your domain / e-mail provider should make that information available to you.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published