Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions assets/bluesky-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
158 changes: 85 additions & 73 deletions components/common/Markdown/remarkGithub.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,90 +12,102 @@ const remarkGithub = (options) => {
/https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/(issues|pull)\/(\d+)/g;
const compareUrlRegex =
/https:\/\/github\.com\/([\w-]+)\/([\w-]+)\/compare\/([\w.-]+)\.\.\.([\w.-]+)/g;
const usernameRegex = /@([\w-]+)/g; // Regex to match @username
const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
const usernameRegex = /@([\w-]+)(?![@.]\w)/g; // Negative lookahead to prevent matching email addresses

return (tree) => {
visit(tree, 'text', (node, index, parent) => {
if (!isInsideLink(node, [])) {
const children = [];
let lastIndex = 0;
let match;
// Skip if we're inside a link or if the parent is a link
if (isInsideLink(node, []) || parent?.type === 'link') {
return;
}

const children = [];
let lastIndex = 0;
let match;

function addText(text, start, end) {
if (start < end) children.push(u('text', text.slice(start, end)));
}
function addText(text, start, end) {
if (start < end) children.push(u('text', text.slice(start, end)));
}

// TODO: Handle my-org/my-repo#123 and my-repo#123
// First check for email addresses
while ((match = emailRegex.exec(node.value)) !== null) {
const [email] = match;
addText(node.value, lastIndex, match.index);
children.push(
u('link', { url: `mailto:${email}` }, [u('text', email)])
);
lastIndex = match.index + email.length;
}

// Handle issue numbers
while ((match = issueRegex.exec(node.value)) !== null) {
const [fullMatch, issueNumber] = match;
addText(node.value, lastIndex, match.index);
children.push(
u(
'link',
{
url: `https://github.com/${defaultOrg}/${defaultRepo}/issues/${issueNumber}`,
},
[u('text', `#${issueNumber}`)]
)
);
lastIndex = match.index + fullMatch.length;
}
// Handle issue numbers
while ((match = issueRegex.exec(node.value)) !== null) {
const [fullMatch, issueNumber] = match;
addText(node.value, lastIndex, match.index);
children.push(
u(
'link',
{
url: `https://github.com/${defaultOrg}/${defaultRepo}/issues/${issueNumber}`,
},
[u('text', `#${issueNumber}`)]
)
);
lastIndex = match.index + fullMatch.length;
}

// Handle full GitHub URLs
while ((match = fullUrlRegex.exec(node.value)) !== null) {
const [fullMatch, org, repo, type, number] = match;
addText(node.value, lastIndex, match.index);
const linkText = `${org === defaultOrg ? '' : `${org}/`}${
org === defaultOrg && repo === defaultRepo ? '' : repo
}#${number}`;
children.push(
u(
'link',
{ url: `https://github.com/${org}/${repo}/${type}/${number}` },
[u('text', linkText)]
)
);
lastIndex = match.index + fullMatch.length;
}
// Handle full GitHub URLs
while ((match = fullUrlRegex.exec(node.value)) !== null) {
const [fullMatch, org, repo, type, number] = match;
addText(node.value, lastIndex, match.index);
const linkText = `${org === defaultOrg ? '' : `${org}/`}${
org === defaultOrg && repo === defaultRepo ? '' : repo
}#${number}`;
children.push(
u(
'link',
{ url: `https://github.com/${org}/${repo}/${type}/${number}` },
[u('text', linkText)]
)
);
lastIndex = match.index + fullMatch.length;
}

// Handle GitHub compare URLs
while ((match = compareUrlRegex.exec(node.value)) !== null) {
const [fullMatch, org, repo, tag1, tag2] = match;
addText(node.value, lastIndex, match.index);
children.push(
u(
'link',
{
url: `https://github.com/${org}/${repo}/compare/${tag1}...${tag2}`,
},
[u('text', `${tag1}...${tag2}`)]
)
);
lastIndex = match.index + fullMatch.length;
}
// Handle GitHub compare URLs
while ((match = compareUrlRegex.exec(node.value)) !== null) {
const [fullMatch, org, repo, tag1, tag2] = match;
addText(node.value, lastIndex, match.index);
children.push(
u(
'link',
{
url: `https://github.com/${org}/${repo}/compare/${tag1}...${tag2}`,
},
[u('text', `${tag1}...${tag2}`)]
)
);
lastIndex = match.index + fullMatch.length;
}

// Handle GitHub usernames
while ((match = usernameRegex.exec(node.value)) !== null) {
const [fullMatch, usernameOrOrg] = match;
addText(node.value, lastIndex, match.index);
children.push(
u('link', { url: `https://github.com/${usernameOrOrg}` }, [
u('text', fullMatch),
])
);
lastIndex = match.index + fullMatch.length;
}
// Handle GitHub usernames (only if not part of an email)
while ((match = usernameRegex.exec(node.value)) !== null) {
const [fullMatch, usernameOrOrg] = match;
addText(node.value, lastIndex, match.index);
children.push(
u('link', { url: `https://github.com/${usernameOrOrg}` }, [
u('text', fullMatch),
])
);
lastIndex = match.index + fullMatch.length;
}

addText(node.value, lastIndex, node.value.length);
addText(node.value, lastIndex, node.value.length);

if (
children.length > 1 ||
(children.length === 1 && children[0].type !== 'text')
) {
parent.children.splice(index, 1, ...children);
}
if (
children.length > 1 ||
(children.length === 1 && children[0].type !== 'text')
) {
parent.children.splice(index, 1, ...children);
}
});
};
Expand Down
16 changes: 10 additions & 6 deletions components/pages/blog/post/ArticleHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,16 @@ const ArticleHeader = ({ frontmatter, author }) => {
<div className="category component">
<div className="component-content">
<div className="category-eyebrow">
<span className="category-eyebrow__category">
{config.categories[frontmatter.category ?? "updates"]?.title ?? config.categories.updates.title}
</span>
<span className="category-eyebrow__date">
{formatDate(frontmatter.date)}
</span>
{frontmatter.category && (
<span className="category-eyebrow__category">
{config.categories[frontmatter.category]?.title ?? config.categories.updates.title}
</span>
)}
{frontmatter.date && (
<span className="category-eyebrow__date">
{formatDate(frontmatter.date)}
</span>
)}
</div>
</div>
</div>
Expand Down
58 changes: 42 additions & 16 deletions components/pages/blog/post/ShareSheet.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useRef } from "react";
import XSvg from '@/assets/x-icon.svg';
import BlueSkySvg from '@/assets/bluesky-icon.svg';
import FacebookSvg from '@/assets/facebook-icon.svg';
import { Link, Mail } from 'react-feather';
import styled from "styled-components";
Expand Down Expand Up @@ -111,6 +112,18 @@ const ShareSheetWrap = styled.div`

const ShareSheet = () => {
const shareLinkInputRef = useRef();

const sanitizeUrl = (url) => {
if (!url) return '';
try {
const urlObj = new URL(url);
return encodeURIComponent(urlObj.toString());
} catch (e) {
console.error('Error sanitizing URL:', e);
return '';
}
};

const shareViaMail = () => {
var subject = 'CodeEdit Blog Post';
var body = window.location.href;
Expand All @@ -122,12 +135,13 @@ const ShareSheet = () => {
};

function shareViaLink() {
navigator.clipboard.writeText(window.location.href).then(
function (data) {
console.log('Copying to clipboard was successful!', data);
const url = window.location.href;
navigator.clipboard.writeText(url).then(
function () {
console.log('Copying to clipboard was successful!');
},
function (err) {
console.log('Could not copy text: ', err);
console.error('Could not copy text: ', err);
}
);
}
Expand All @@ -144,7 +158,7 @@ const ShareSheet = () => {
aria-label="Share this article via Facebook (opens in new window)"
onClick={() =>
window.open(
`https://www.facebook.com/sharer/sharer.php?u=${window.location.href}`
`https://www.facebook.com/sharer/sharer.php?u=${sanitizeUrl(window.location.href)}`
)
}
>
Expand All @@ -153,18 +167,32 @@ const ShareSheet = () => {
</li>
<li className="social-option">
<button
className="icon icon-twitter social-icon"
title="Share via Twitter"
aria-label="Share this article via Twitter (opens in new window)"
className="icon icon-x social-icon"
title="Share via X"
aria-label="Share this article via X (opens in new window)"
onClick={() =>
window.open(
`https://x.com/intent/tweet?url=${window.location.href}`
`https://x.com/intent/tweet?url=${sanitizeUrl(window.location.href)}`
)
}
>
<XSvg />
</button>
</li>
<li className="social-option">
<button
className="icon icon-bluesky social-icon"
title="Share via BlueSky"
aria-label="Share this article via BlueSky (opens in new window)"
onClick={() =>
window.open(
`https://bsky.app/intent/compose?text=${sanitizeUrl(window.location.href)}`
)
}
>
<BlueSkySvg />
</button>
</li>
<li className="social-option">
<button
className="icon icon-mail social-icon"
Expand All @@ -191,19 +219,17 @@ const ShareSheet = () => {
<input
ref={shareLinkInputRef}
className="link-text"
value={
typeof window !== 'undefined' ? window.location.href : ''
}
tabindex="-1"
readonly=""
value={typeof window !== 'undefined' ? window.location.href : ''}
tabIndex="-1"
readOnly
aria-hidden="true"
disabled="disabled"
disabled
/>
<button
className="icon icon-close sharesheet-link-close"
title="close"
aria-label="close link"
tabindex="-1"
tabIndex="-1"
aria-hidden="true"
role="button"
></button>
Expand Down
3 changes: 3 additions & 0 deletions components/pages/blog/post/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const BlogPost = ({ frontmatter, markdownBody, author }) => {
} Blog`;
const description = frontmatter.description ?? frontmatter.subhead;

console.log(frontmatter);
console.log(markdownBody);

return (
<Section gutter={false}>
<Head>
Expand Down
37 changes: 37 additions & 0 deletions data/pizza.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
title: 'You Ship Code, We Ship 🍕!'
image: 'https://media1.tenor.com/m/VWAZosGBC6AAAAAd/hellmo-pizza.gif'
---

![Pizza](https://media1.tenor.com/m/VWAZosGBC6AAAAAd/hellmo-pizza.gif)

At Deep Dish Swift, we're not only here to talk Swift, but to also serve pizza!
Think your code's got the secret sauce? Let's see what you've got.

We're cooking up a native Mac code editor called [CodeEdit](https://github.com/CodeEditApp/CodeEdit) (you may have heard of it), and if you contribute, we'll send you a pizza — no strings attached, except for cheese.

Make a pull request, climb the leaderboard, claim your pie. Let's get saucy!

## Rules

Here's how to claim your slice:

1. Comment "I'll take this slice! 🍕" on any issue in [our repos](https://github.com/CodeEditApp) on GitHub.
2. Make a PR solving that issue.
3. Email your name, GitHub username, a link to your merged PR to [codeforpizza@codeedit.app](mailto:codeforpizza@codeedit.app), along with your preferred pizza delivery service.

Once your PR is merged and you've sent us an email, we'll send you a digital gift card to order a pizza — on us.

Hurry, this won't last long, [get started](https://github.com/CodeEditApp/CodeEdit/issues)!

> [!NOTE]
> We reserve the right to only reward completed and meaningful contributions (but we'll still love you for trying).

## Leaderboard

| Name | PRs Merged / 🍕 Received |
|:------------------------------------------------------|------------------------:|
| [thecoolwinter](https://github.com/thecoolwinter) | 2 |
| [tom-ludwig](https://github.com/tom-ludwig) | 1 |
| [FastestMolasses](https://github.com/FastestMolasses) | 1 |
| [austincondiff](https://github.com/austincondiff) | 1 |
21 changes: 21 additions & 0 deletions pages/pizza.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import matter from 'gray-matter';
import BlogPost from '@/components/pages/blog/post';

export async function getStaticProps() {
const content = await import('@/data/pizza.md');
const data = await matter(content.default);

return {
props: {
frontmatter: {
...data.data,
date: new Date().toISOString(),
},
markdownBody: data.content,
}
};
}

export default function Pizza({ frontmatter, markdownBody }) {
return <BlogPost frontmatter={frontmatter} markdownBody={markdownBody} />;
}
Loading