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
75 changes: 40 additions & 35 deletions packages/app/src/app/components/Create/CreateBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,20 @@ import {
SandboxAlternative,
} from './elements';
import { TemplateList } from './TemplateList';
import { useTemplateCollections } from './hooks/useTemplateCollections';
import { useOfficialTemplates } from './hooks/useOfficialTemplates';
import { useTeamTemplates } from './hooks/useTeamTemplates';
import { CreateParams, SandboxToFork } from './utils/types';
import { SearchBox } from './SearchBox';
import { ImportTemplate } from './ImportTemplate';
import { CreateBoxForm, PrivacyLevel } from './CreateBox/CreateBoxForm';
import { CreateBoxForm } from './CreateBox/CreateBoxForm';
import { TemplateInfo } from './CreateBox/TemplateInfo';
import { useFeaturedTemplates } from './hooks/useFeaturedTemplates';
import { useAllTemplates } from './hooks/useAllTemplates';
import { mapSandboxGQLResponseToSandboxToFork } from './utils/api';
import {
getTemplatesInCollections,
getAllMatchingTemplates,
mapSandboxGQLResponseToSandboxToFork,
parsePrivacy,
} from './utils/api';
import { WorkspaceSelect } from '../WorkspaceSelect';
import { FEATURED_IDS } from './utils/constants';

type CreateBoxProps = ModalContentProps & {
collectionId?: string;
Expand All @@ -51,30 +53,19 @@ type CreateBoxProps = ModalContentProps & {
isStandalone?: boolean;
};

function parsePrivacy(privacy: string | undefined): PrivacyLevel | undefined {
if (privacy === 'public') {
return 0;
}

if (privacy === 'unlisted') {
return 1;
}

if (privacy === 'private') {
return 2;
}

return undefined;
}

export const CreateBox: React.FC<CreateBoxProps> = ({
collectionId: initialCollectionId,
sandboxIdToFork,
type = 'devbox',
closeModal,
isStandalone,
}) => {
const { hasLogIn, activeTeam } = useAppState();
const {
hasLogIn,
activeTeam,
officialDevboxTemplates,
officialSandboxTemplates,
} = useAppState();
const effects = useEffects();
const actions = useActions();
const { isFrozen } = useWorkspaceLimits();
Expand Down Expand Up @@ -106,32 +97,44 @@ export const CreateBox: React.FC<CreateBoxProps> = ({
false
);

const { collections } = useTemplateCollections({ type });
const { templates: officialTemplates } = useOfficialTemplates({ type });
const officialTemplates =
type === 'devbox' ? officialDevboxTemplates : officialSandboxTemplates;

const collections = getTemplatesInCollections(officialTemplates, [
{ tag: 'frontend', title: 'Frontend frameworks' },
{ tag: 'backend', title: 'Backend frameworks' },
{ tag: 'playground', title: 'Code playgrounds' },
{ tag: 'starter', title: 'Project starters' },
]);

const { teamTemplates, recentTemplates } = useTeamTemplates({
teamId: activeTeam,
hasLogIn,
type,
});

const recentlyUsedTemplates = recentTemplates.slice(0, 3);
const featuredTemplates = useFeaturedTemplates({
officialTemplates,
recentTemplates,
});
const hasRecentlyUsedTemplates = recentlyUsedTemplates.length > 0;
const recentlyUsedTemplatesIds = recentlyUsedTemplates.map(t => t.id);

const allTemplates = useAllTemplates({
featuredTemplates,
const featuredTemplates = FEATURED_IDS.map(id =>
officialTemplates.find(
t => t.id === id && !recentlyUsedTemplatesIds.includes(t.id)
)
)
.filter(Boolean)
.slice(0, hasRecentlyUsedTemplates ? 6 : 9);

const allTemplates = getAllMatchingTemplates({
officialTemplates,
teamTemplates,
collections,
searchQuery,
});

/**
* Only show the team templates if the list is populated.
*/
const hasRecentlyUsedTemplates = recentlyUsedTemplates.length > 0;

const showTeamTemplates = teamTemplates.length > 0;
const showImportTemplates = hasLogIn && activeTeam && type === 'devbox';

Expand Down Expand Up @@ -224,7 +227,8 @@ export const CreateBox: React.FC<CreateBoxProps> = ({
const selectTemplate = (sandbox: SandboxToFork, trackingSource: string) => {
if (!hasLogIn) {
// Open template in editor for anonymous users
window.location.href = sandboxUrl(sandbox, hasBetaEditorExperiment);
window.location.href =
sandbox.editorUrl || sandboxUrl(sandbox, hasBetaEditorExperiment);
return;
}

Expand All @@ -239,7 +243,8 @@ export const CreateBox: React.FC<CreateBoxProps> = ({
};

const openTemplate = (sandbox: SandboxToFork, trackingSource: string) => {
const url = sandboxUrl(sandbox, hasBetaEditorExperiment);
const url =
sandbox.editorUrl || sandboxUrl(sandbox, hasBetaEditorExperiment);
window.open(url, '_blank');

track(`Create ${type} - Open template`, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
PathedSandboxesFoldersQuery,
PathedSandboxesFoldersQueryVariables,
} from 'app/graphql/types';
import { CreateParams } from '../utils/types';
import { CreateParams, PrivacyLevel } from '../utils/types';

interface CreateBoxFormProps {
type: 'sandbox' | 'devbox';
Expand All @@ -35,8 +35,6 @@ interface CreateBoxFormProps {
onClose: () => void;
}

export type PrivacyLevel = 0 | 1 | 2;

export const CreateBoxForm: React.FC<CreateBoxFormProps> = ({
type,
initialPrivacy,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
import { getTemplateIcon } from '@codesandbox/common/lib/utils/getTemplateIcon';
import { Stack, Text, Icon } from '@codesandbox/components';
import { formatNumber } from '@codesandbox/components/lib/components/Stats';
import React from 'react';
import { SandboxToFork } from '../utils/types';
import { TemplateIcon } from '../TemplateIcon';

interface TemplateInfoProps {
template: SandboxToFork;
}

export const TemplateInfo = ({ template }: TemplateInfoProps) => {
const { UserIcon } = getTemplateIcon(
template.title,
template.iconUrl,
template.sourceTemplate
);

const title = template.title || template.alias;
const owner = template.owner;
const owner = template.author;

return (
<Stack direction="vertical" gap={4}>
<UserIcon />
<TemplateIcon template={template} />
<Stack direction="vertical" gap={1}>
<Text size={3} weight="500">
{title}
Expand Down
12 changes: 3 additions & 9 deletions packages/app/src/app/components/Create/TemplateCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { formatNumber, Icon, Stack, Text } from '@codesandbox/components';
import { getTemplateIcon } from '@codesandbox/common/lib/utils/getTemplateIcon';
import { VisuallyHidden } from 'reakit/VisuallyHidden';
import { TemplateButton } from './elements';
import { SandboxToFork } from './utils/types';
import { TemplateIcon } from './TemplateIcon';

interface TemplateCardProps {
disabled?: boolean;
Expand All @@ -22,14 +22,8 @@ export const TemplateCard = ({
padding,
forks,
}: TemplateCardProps) => {
const { UserIcon } = getTemplateIcon(
template.title,
template.iconUrl,
template.sourceTemplate
);

const sandboxTitle = template.title || template.alias;
const teamName = template.owner;
const teamName = template.author;

return (
<TemplateButton
Expand Down Expand Up @@ -72,7 +66,7 @@ export const TemplateCard = ({
<Stack
css={{ justifyContent: 'space-between', alignItems: 'flex-start' }}
>
<UserIcon height="20" width="20" />
<TemplateIcon template={template} />
</Stack>
<Stack direction="vertical" gap={1}>
<Text
Expand Down
22 changes: 22 additions & 0 deletions packages/app/src/app/components/Create/TemplateIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { getTemplateIcon } from '@codesandbox/common/lib/utils/getTemplateIcon';
import { SandboxToFork } from './utils/types';

export const TemplateIcon: React.FC<{ template: SandboxToFork }> = ({
template,
}) => {
if (template.iconUrl?.startsWith('https://')) {
return (
<img src={template.iconUrl} width={20} height={20} alt={template.title} />
);
}

// Legacy way of handling Icon which I didn't want to tackle with this PR
const { UserIcon } = getTemplateIcon(
template.title,
template.iconUrl,
template.sourceTemplate
);

return <UserIcon height="20" width="20" />;
};
46 changes: 0 additions & 46 deletions packages/app/src/app/components/Create/hooks/useAllTemplates.ts

This file was deleted.

This file was deleted.

This file was deleted.

Loading