Skip to content

Commit 5130d5b

Browse files
authored
Merge branch 'develop' into prune-files
2 parents 34ae2d5 + 94401a6 commit 5130d5b

File tree

19 files changed

+359
-259
lines changed

19 files changed

+359
-259
lines changed

E2E Overview.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
To run the end-to-end tests using Playwright, you need to configure your environment and follow these steps:
44

5-
6-
75
### Session and User Setup
86

97
First, you need to add your E2E test user to your locally running database. Do this by running the following script if you haven't already:

ISSUE_TEMPLATE.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
## Context
22

3-
Please provide any relevant information about your setup
3+
<!-- Please provide any relevant information about your setup. -->
44

55
## Expected Behavior
66

7-
Please describe the behavior you are expecting
7+
<!-- Please describe the behavior you are expecting. -->
88

99
## Current Behavior
1010

11-
What is the current behavior?
11+
<!-- What is the current behavior? -->
1212

1313
## Screenshots
1414

15-
Drag and drop screenshots here to better describe your issue
15+
<!-- Drag and drop screenshots here to better describe your issue. -->
1616

1717
## Steps to reproduce
1818

19-
Please provide detailed steps for reproducing the issue
20-
19+
<!-- Please provide detailed steps for reproducing the issue:
2120
1. Step 1
2221
2. Step 2
23-
3. etc
22+
3. etc.
23+
-->
2424

2525
## Additional info
2626

27-
Provide any additional information here
27+
<!-- Provide any additional information here. -->
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
Tuesday, November 5th, 2024 • Niall Maher
2+
3+
# ⚡️ Better Image Loading + React Native's New Architecture
4+
5+
[Read online](https://www.codu.co/letters/is-your-domain-haunted)
6+
7+
My tip of the week is something I just learned about. A property called `fetchpriority` that drastically improved our Core Web Vitals. While most developers know about lazy loading, combining a few loading properties can make a big difference. You can further boost the priority of fetching an image using the `fetchpriority` property.
8+
9+
Here's what it looks like in action:​​​​​​​
10+
11+
```html
12+
rel="preload" as="image" href="hero.webp" fetchpriority="high" > src="hero.webp"
13+
loading="eager" fetchpriority="high" decoding="async" >
14+
```
15+
16+
Let's break down why this works so well:
17+
18+
- The `<link rel="preload">` tells browsers to start downloading the image immediately, even before they discover the tag while parsing HTML
19+
- `fetchpriority="high"` bumps the image to the top of the browser's resource queue, making it download before less critical resources
20+
- `loading="eager"` disables lazy loading for this specific image (crucial for above-the-fold content)
21+
- `decoding="async"` lets the browser optimize image decode timing without blocking other tasks
22+
23+
**Just remember:** use this pattern sparingly for critical above-the-fold images directly impacting LCP. For everything else, stick with regular lazy loading.
24+
25+
And a **Pro tip:** Combine this with the `srcset` attribute to handle responsive images, and you've got a bulletproof image-loading strategy. I wrote a little article on it this week. [Read it here](https://www.codu.co/articles/responsive-images-in-html-using-srcset-lyb6r6r0).
26+
27+
## 📚 This Week's Picks
28+
29+
**[Creating Custom VS Code Snippets for Faster Development](https://www.codu.co/articles/creating-custom-vs-code-snippets-for-faster-development-kgjv1ct)** (4 min)\
30+
Let's explore how to create custom snippets that will boost your productivity.
31+
32+
**[Introduction to C# and .NET](https://www.codu.co/articles/introduction-to-c-and-net-w0hc8gz3)** (4 min)\
33+
What is C#, and what is .NET? The first article in a series Adrián is writing to teach you C#.
34+
35+
**[Enhanced local IDE experience for AWS Lambda developers](https://aws.amazon.com/blogs/compute/introducing-an-enhanced-local-ide-experience-for-aws-lambda-developers/)** (8 min)\
36+
AWS Lambda is introducing an improved local IDE experience to simplify Lambda-based application development. The new features help developers to author, build, debug, test, and deploy Lambda applications more efficiently in their local IDE.
37+
38+
**[25 crazy software bugs explained](https://www.youtube.com/watch?v=Iq_r7IcNmUk)** (video)\
39+
Fireship dives into 25 crazy software bugs that changed the world.
40+
41+
**[React Native - New Architecture is here](https://reactnative.dev/blog/2024/10/23/the-new-architecture-is-here)** (22 min)\
42+
The 0.76 release blog post shared a list of significant changes in this version. It provides an overview of the New Architecture and how it shapes the future of React Native.
43+
44+
**[Lessons learned from a successful Rust rewrite](https://gaultier.github.io/blog/lessons_learned_from_a_successful_rust_rewrite.html)** (12 min)\
45+
A great deep dive into some important lessons when migrating a C++ codebase to Rust.
46+
47+
## 📖 Book of the Week
48+
49+
**[The Engineering Executive's Primer: Impactful Technical Leadership](https://amzn.to/4fj5bWf)**
50+
51+
This book is essential for technical leaders navigating the complexities of engineering management. Drawing from his extensive experience at companies like Stripe and Uber, Larson offers practical frameworks for scaling engineering organizations, developing talent, and driving technical strategy. What sets this book apart is its focused approach to the unique challenges faced by senior engineering leaders, from managing organizational design to balancing technical debt with business growth. Particularly valuable are the actionable insights on building effective engineering processes and fostering a culture of technical excellence.
52+
53+
Whether you're an engineering executive or aspiring to become one, this book provides the strategic toolkit needed for impactful technical leadership.
54+
55+
## 🛠️ Something Cool
56+
57+
**[Posthog](https://posthog.com/)**
58+
59+
This is not a sponsored post (I am mentioning it because I do see Posthog sponsors a lot of content). I've been using this tool again recently for a couple of projects, and it's just fantastic.
60+
61+
PostHog offers the full package---session recordings, feature flags, A/B testing, and product analytics. Whether you're running early experiments or want to systemize your product decisions, PostHog provides the data and tools needed to make data-driven choices. It has a very generous free tier (which I haven't been lucky enough to hit just yet with any of my side projects).
62+
63+
## 🔗 Quick Links
64+
65+
- [Codú TikTok](https://www.tiktok.com/@codu.co)
66+
- [Hacktoberfest GitHub Issues](https://github.com/codu-code/codu/issues)
67+
- [Our YouTube channel](https://www.youtube.com/@codu)
68+
- [Find us on Twitch](https://www.twitch.tv/codudotco)
69+
70+
**If you have any ideas or feedback, reply to this email.**
71+
72+
Thanks, and stay awesome,
73+
74+
Niall
75+
76+
Founder @ [Codú](https://www.codu.co/?ref=newsletter)

app/(editor)/create/[[...paramsArr]]/_client.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ const Create = ({ session }: { session: Session | null }) => {
557557
type="button"
558558
className="relative flex w-full focus:outline-none focus:ring-2 focus:ring-pink-300 focus:ring-offset-2 active:hover:bg-neutral-50 disabled:opacity-50"
559559
>
560-
<div className="input-base flex max-w-full flex-1 overflow-hidden border text-left">
560+
<div className="flex w-full max-w-full flex-1 overflow-hidden border px-2 py-2 text-left text-black shadow-sm ring-offset-1 focus:border-pink-500 focus:outline-none focus:ring-2 focus:ring-neutral-300 disabled:opacity-50 dark:border-white dark:bg-black dark:text-white sm:text-sm">
561561
{PREVIEW_URL}
562562
</div>
563563
<div className="absolute bottom-0 right-0 top-0 w-[120px] border border-neutral-300 bg-white px-4 py-2 font-medium text-neutral-600 shadow-sm">

components/ArticleMenu/ArticleMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ const ArticleMenu = ({
150150
</div>
151151

152152
<button
153-
className="focus-style-rounded rounded-full p-1 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
153+
className="rounded-full p-1 hover:bg-neutral-300 focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600 dark:hover:bg-neutral-800 lg:mx-auto"
154154
aria-label="bookmark-trigger"
155155
onClick={() => {
156156
if (!session) {

components/ArticlePreview/ArticlePreview.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ const ArticlePreview: NextPage<Props> = ({
155155
<div className="flex gap-x-2">
156156
{showBookmark && (
157157
<button
158-
className="focus-style-rounded rounded-full p-2 hover:bg-neutral-300 dark:hover:bg-neutral-800 lg:mx-auto"
158+
className="rounded-full p-2 hover:bg-neutral-300 focus:outline-none focus:ring-white focus-visible:ring-2 focus-visible:ring-pink-600 focus-visible:ring-offset-pink-600 dark:hover:bg-neutral-800 lg:mx-auto"
159159
onClick={() => {
160160
if (!session) {
161161
return signIn();

components/Footer/Footer.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,25 @@ const navigation = {
1919
social: [
2020
{
2121
name: "Twitter",
22+
customStyle: "hover:bg-twitter focus:bg-twitter",
2223
href: twitterUrl,
2324
icon: Twitter,
2425
},
2526
{
2627
name: "GitHub",
28+
customStyle: "hover:bg-github focus:bg-github",
2729
href: githubUrl,
2830
icon: Github,
2931
},
3032
{
3133
name: "Discord",
34+
customStyle: "hover:bg-discord focus:bg-discord",
3235
href: discordInviteUrl,
3336
icon: Discord,
3437
},
3538
{
3639
name: "Youtube",
40+
customStyle: "hover:bg-youtube focus:bg-youtube",
3741
href: youtubeUrl,
3842
icon: Youtube,
3943
},
@@ -77,7 +81,7 @@ const Footer = () => {
7781
href={item.href}
7882
target="_blank"
7983
rel="noopener noreferrer"
80-
className={`focus-style rounded-md p-1 transition-all duration-300 hover:scale-105 hover:text-white hover:brightness-110 focus:scale-105 focus:text-white focus:brightness-110 ${item.name.toLowerCase()}`}
84+
className={`focus-style rounded-md p-1 transition-all duration-300 hover:scale-105 hover:text-white hover:brightness-110 focus:scale-105 focus:text-white focus:brightness-110 ${item.customStyle.toLowerCase()}`}
8185
>
8286
<span className="sr-only">{item.name}</span>
8387
<item.icon className="h-6 w-6" aria-hidden="true" />

components/editor/editor/components/bubble-menu.tsx

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { useState } from "react";
55
import {
66
BoldIcon,
77
ItalicIcon,
8-
CodeIcon,
98
} from "lucide-react";
109

1110
import { NodeSelector } from "./node-selector";
@@ -25,22 +24,16 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
2524
const items: BubbleMenuItem[] = [
2625
{
2726
name: "bold",
28-
isActive: () => props.editor.isActive("bold"),
29-
command: () => props.editor.chain().focus().toggleBold().run(),
27+
isActive: () => props.editor?.isActive("bold") ?? false,
28+
command: () => props.editor?.chain().focus().toggleBold().run(),
3029
icon: BoldIcon,
3130
},
3231
{
3332
name: "italic",
34-
isActive: () => props.editor.isActive("italic"),
35-
command: () => props.editor.chain().focus().toggleItalic().run(),
33+
isActive: () => props.editor?.isActive("italic") ?? false,
34+
command: () => props.editor?.chain().focus().toggleItalic().run(),
3635
icon: ItalicIcon,
3736
},
38-
{
39-
name: "code",
40-
isActive: () => props.editor.isActive("code"),
41-
command: () => props.editor.chain().focus().toggleCode().run(),
42-
icon: CodeIcon,
43-
},
4437
];
4538

4639
const bubbleMenuProps: EditorBubbleMenuProps = {
@@ -79,22 +72,16 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
7972
{...bubbleMenuProps}
8073
className="flex w-fit divide-x divide-stone-200 rounded border border-stone-200 bg-white shadow-xl"
8174
>
82-
<NodeSelector
83-
editor={props.editor}
84-
isOpen={isNodeSelectorOpen}
85-
setIsOpen={() => {
86-
setIsNodeSelectorOpen(!isNodeSelectorOpen);
87-
setIsLinkSelectorOpen(false);
88-
}}
89-
/>
90-
<LinkSelector
91-
editor={props.editor}
92-
isOpen={isLinkSelectorOpen}
93-
setIsOpen={() => {
94-
setIsLinkSelectorOpen(!isLinkSelectorOpen);
95-
setIsNodeSelectorOpen(false);
96-
}}
97-
/>
75+
{props.editor && (
76+
<NodeSelector
77+
editor={props.editor}
78+
isOpen={isNodeSelectorOpen}
79+
setIsOpen={() => {
80+
setIsNodeSelectorOpen(!isNodeSelectorOpen);
81+
setIsLinkSelectorOpen(false);
82+
}}
83+
/>
84+
)}
9885
<div className="flex">
9986
{items.map((item, index) => (
10087
<button
@@ -110,6 +97,15 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props) => {
11097
/>
11198
</button>
11299
))}
100+
{props.editor && (
101+
<LinkSelector
102+
editor={props.editor}
103+
isOpen={isLinkSelectorOpen}
104+
setIsOpen={() => {
105+
setIsLinkSelectorOpen(!isLinkSelectorOpen);
106+
}}
107+
/>
108+
)}
113109
</div>
114110
</BubbleMenu>
115111
);

components/editor/editor/components/link-selector.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { cn, getUrlFromString } from "@/utils/utils";
22
import type { Editor } from "@tiptap/core";
3-
import { Check, Trash } from "lucide-react";
3+
import { Link } from "lucide-react";
44
import type { Dispatch, FC, SetStateAction } from "react";
55
import { useEffect, useRef, useCallback } from "react";
66

@@ -60,14 +60,11 @@ export const LinkSelector: FC<LinkSelectorProps> = ({
6060
className="flex h-full items-center space-x-2 px-3 py-1.5 text-sm font-medium text-stone-600 hover:bg-stone-100 active:bg-stone-200"
6161
onClick={setLink}
6262
>
63-
<p className="text-base"></p>
64-
<p
65-
className={cn("underline decoration-stone-400 underline-offset-4", {
63+
<Link
64+
className={cn("h-4 w-4", {
6665
"text-blue-500": editor.isActive("link"),
6766
})}
68-
>
69-
Link
70-
</p>
67+
/>
7168
</button>
7269
{/* {isOpen && (
7370
<form

components/editor/editor/components/node-selector.tsx

Lines changed: 8 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,8 @@ import type { Editor } from "@tiptap/core";
22
import {
33
Check,
44
ChevronDown,
5-
Heading1,
6-
Heading2,
7-
Heading3,
85
TextQuote,
9-
ListOrdered,
106
TextIcon,
11-
Code,
12-
CheckSquare,
137
Heading,
148
} from "lucide-react";
159
import type { Dispatch, FC, SetStateAction } from "react";
@@ -28,17 +22,6 @@ export const NodeSelector: FC<NodeSelectorProps> = ({
2822
setIsOpen,
2923
}) => {
3024
const items: BubbleMenuItem[] = [
31-
{
32-
name: "Text",
33-
icon: TextIcon,
34-
command: () =>
35-
editor.chain().focus().toggleNode("paragraph", "paragraph").run(),
36-
// I feel like there has to be a more efficient way to do this – feel free to PR if you know how!
37-
isActive: () =>
38-
editor.isActive("paragraph") &&
39-
!editor.isActive("bulletList") &&
40-
!editor.isActive("orderedList"),
41-
},
4225
{
4326
name: "Heading",
4427
icon: Heading,
@@ -51,6 +34,13 @@ export const NodeSelector: FC<NodeSelectorProps> = ({
5134
command: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
5235
isActive: () => editor.isActive("heading", { level: 3 }),
5336
},
37+
{
38+
name: "Text",
39+
icon: TextIcon,
40+
command: () =>
41+
editor.chain().focus().toggleNode("paragraph", "paragraph").run(),
42+
isActive: () => editor.isActive("paragraph"),
43+
},
5444
{
5545
name: "Quote",
5646
icon: TextQuote,
@@ -63,24 +53,6 @@ export const NodeSelector: FC<NodeSelectorProps> = ({
6353
.run(),
6454
isActive: () => editor.isActive("blockquote"),
6555
},
66-
{
67-
name: "Code",
68-
icon: Code,
69-
command: () => editor.chain().focus().toggleCodeBlock().run(),
70-
isActive: () => editor.isActive("codeBlock"),
71-
},
72-
{
73-
name: "Bullet List",
74-
icon: ListOrdered,
75-
command: () => editor.chain().focus().toggleBulletList().run(),
76-
isActive: () => editor.isActive("bulletList"),
77-
},
78-
{
79-
name: "Numbered List",
80-
icon: ListOrdered,
81-
command: () => editor.chain().focus().toggleOrderedList().run(),
82-
isActive: () => editor.isActive("orderedList"),
83-
},
8456
];
8557

8658
const activeItem = items.filter((item) => item.isActive()).pop() ?? {
@@ -93,6 +65,7 @@ export const NodeSelector: FC<NodeSelectorProps> = ({
9365
type="button"
9466
className="flex h-full items-center gap-1 whitespace-nowrap p-2 text-sm font-medium text-stone-600 hover:bg-stone-100 active:bg-stone-200"
9567
onClick={() => setIsOpen(!isOpen)}
68+
aria-expanded={isOpen}
9669
>
9770
<span>{activeItem?.name}</span>
9871
<ChevronDown className="h-4 w-4" />

0 commit comments

Comments
 (0)