Skip to content

Commit

Permalink
[NTP Next] Add updated NTP with background support
Browse files Browse the repository at this point in the history
  • Loading branch information
zenparsing committed Nov 25, 2024
1 parent c5b9edd commit 15d255c
Show file tree
Hide file tree
Showing 61 changed files with 3,135 additions and 13 deletions.
7 changes: 7 additions & 0 deletions browser/about_flags.cc
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,13 @@
kOsDesktop, \
FEATURE_VALUE_TYPE(features::kBraveNtpSearchWidget), \
}, \
{ \
"brave-use-updated-ntp", \
"Use the updated New Tab Page", \
"Uses an updated version of the New Tab Page", \
kOsDesktop, \
FEATURE_VALUE_TYPE(features::kBraveUseUpdatedNTP), \
}, \
{ \
"brave-adblock-cname-uncloaking", \
"Enable CNAME uncloaking", \
Expand Down
3 changes: 3 additions & 0 deletions browser/brave_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ using extensions::ChromeContentBrowserClientExtensionsPart;
#if !BUILDFLAG(IS_ANDROID)
#include "brave/browser/new_tab/new_tab_shows_navigation_throttle.h"
#include "brave/browser/ui/geolocation/brave_geolocation_permission_tab_helper.h"
#include "brave/browser/ui/webui/brave_new_tab/new_tab_ui.h"
#include "brave/browser/ui/webui/brave_news_internals/brave_news_internals_ui.h"
#include "brave/browser/ui/webui/brave_rewards/rewards_page_top_ui.h"
#include "brave/browser/ui/webui/brave_rewards/rewards_panel_ui.h"
Expand Down Expand Up @@ -836,6 +837,8 @@ void BraveContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
content::RegisterWebUIControllerInterfaceBinder<
commands::mojom::CommandsService, BraveSettingsUI>(map);
}
content::RegisterWebUIControllerInterfaceBinder<
brave_new_tab::mojom::NewTabPageHandler, brave_new_tab::NewTabUI>(map);
#endif

auto* prefs =
Expand Down
25 changes: 25 additions & 0 deletions browser/resources/brave_new_tab/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (c) 2024 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

import("//brave/components/common/typescript.gni")
import("//mojo/public/tools/bindings/mojom.gni")

assert(!is_android)

transpile_web_ui("brave_new_tab") {
entry_points = [ [
"new_tab",
rebase_path("new_tab.tsx"),
] ]
resource_name = "brave_new_tab"
output_module = true
deps = [ "//brave/browser/ui/webui/brave_new_tab:mojom_js" ]
}

pack_web_resources("generated_resources") {
resource_name = "brave_new_tab"
output_dir = "$root_gen_dir/brave/browser/resources/brave_new_tab"
deps = [ ":brave_new_tab" ]
}
94 changes: 94 additions & 0 deletions browser/resources/brave_new_tab/components/app.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import { color, font } from '@brave/leo/tokens/css/variables'
import { scoped, global } from '../lib/scoped_css'

export const style = scoped.css`
.settings {
--leo-icon-size: 20px;
position: absolute;
inset-block-start: 4px;
inset-inline-end: 4px;
block-size: 20px;
inline-size: 20px;
opacity: 0.5;
color: #fff;
filter: drop-shadow(0px 1px 4px rgba(0, 0, 0, 0.60));
&:hover {
opacity: 0.7;
cursor: pointer;
}
}
main {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
padding-top: 40px;
}
.topsites-container {
min-height: 32px;
}
.searchbox-container {
flex: 1 1 auto;
margin: 16px 0;
}
.background-caption-container {
margin: 8px 0;
}
.widget-container {
min-height: 8px;
}
`

global.css`
@scope (${style.selector}) {
& {
font: ${font.default.regular};
color: ${color.text.primary};
}
button {
margin: 0;
padding: 0;
background: 0;
border: none;
text-align: unset;
width: unset;
font: inherit;
cursor: pointer;
&:disabled {
cursor: default;
}
}
h2 {
font: ${font.heading.h2};
margin: 0;
}
h3 {
font: ${font.heading.h3};
margin: 0;
}
h4 {
font: ${font.heading.h4};
margin: 0;
}
}
`
45 changes: 45 additions & 0 deletions browser/resources/brave_new_tab/components/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import * as React from 'react'
import Icon from '@brave/leo/react/icon'

import { Background } from './background'
import { BackgroundCaption } from './background_caption'
import { SettingsDialog, SettingsView } from './settings/settings_dialog'

import { style } from './app.style'

export function App() {
const [settingsView, setSettingsView] =
React.useState<SettingsView | null>(null)

return (
<div {...style}>
<button
className='settings'
onClick={() => setSettingsView('background')}
>
<Icon name='settings' />
</button>
<main>
<div className='topsites-container' />
<div className='searchbox-container' />
<div className='background-caption-container'>
<BackgroundCaption />
</div>
<div className='widget-container' />
</main>
<Background />
{
settingsView &&
<SettingsDialog
initialView={settingsView}
onClose={() => setSettingsView(null)}
/>
}
</div>
)
}
47 changes: 47 additions & 0 deletions browser/resources/brave_new_tab/components/background.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import { scoped } from '../lib/scoped_css'

export const style = scoped.css`
& {
pointer-events: none;
position: fixed;
inset: 0;
z-index: -1;
display: flex;
animation-name: fade-in;
animation-timing-function: ease-in-out;
animation-duration: 350ms;
animation-delay: 0s;
animation-fill-mode: both;
> div {
flex: 1 1 auto;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
}
}
.image-background {
background:
linear-gradient(
rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0) 80%,
rgba(0, 0, 0, 0.6) 100%),
var(--ntp-background);
}
.color-background {
background: var(--ntp-background);
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
`
71 changes: 71 additions & 0 deletions browser/resources/brave_new_tab/components/background.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import * as React from 'react'

import { useNewTabState } from './new_tab_context'
import { useCallbackWrapper } from '../lib/use_callback_wrapper'
import { loadImage } from '../lib/image_loader'

import { style } from './background.style'

function setBackgroundVariable(value: string) {
if (value) {
document.body.style.setProperty('--ntp-background', value)
} else {
document.body.style.removeProperty('--ntp-background')
}
}

function ImageBackground(props: { url: string }) {
const wrapCallback = useCallbackWrapper()

// In order to avoid a "flash-of-unloaded-image", load the image in the
// background and only update the background CSS variable when the image has
// finished loading.
React.useEffect(() => {
loadImage(props.url).then(wrapCallback((loaded) => {
if (loaded) {
setBackgroundVariable(`url(${CSS.escape(props.url)})`)
}
}))
}, [props.url])

return <div className='image-background' />
}

function ColorBackground(props: { colorValue: string }) {
React.useEffect(() => {
setBackgroundVariable(props.colorValue)
}, [props.colorValue])

return <div className='color-background' />
}

export function Background() {
const currentBackground = useNewTabState((state) => state.currentBackground)

function renderBackground() {
if (!currentBackground) {
return <ColorBackground colorValue='transparent' />
}

switch (currentBackground.type) {
case 'brave':
case 'custom':
case 'sponsored':
return <ImageBackground url={currentBackground.imageUrl} />
case 'solid':
case 'gradient':
return <ColorBackground colorValue={currentBackground.cssValue} />
}
}

return (
<div {...style}>
{renderBackground()}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* Copyright (c) 2024 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

import { color, font } from '@brave/leo/tokens/css/variables'
import { scoped } from '../lib/scoped_css'

export const style = scoped.css`
a {
text-decoration: none;
color: inherit;
}
.photo-credits {
color: ${color.white};
font: ${font.xSmall.regular};
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.10);
opacity: .5;
}
.sponsored-logo {
--leo-icon-size: 20px;
display: flex;
flex-direction: column;
align-items: end;
color: ${color.white};
leo-icon {
opacity: 0;
transition: opacity 200ms;
}
img {
margin: 2px 20px 0 20px;
width: 170px;
height: auto;
}
&:hover {
leo-icon {
opacity: .7;
}
}
}
`
Loading

0 comments on commit 15d255c

Please sign in to comment.