mirror of
https://github.com/muerwre/vault-frontend.git
synced 2025-04-25 12:56:41 +07:00
actually getting event about adding account
This commit is contained in:
parent
5396cf7611
commit
e94d776ee5
12 changed files with 252 additions and 136 deletions
|
@ -22,9 +22,9 @@ const UserButton: FC<IProps> = ({ user: { username, photo }, authOpenProfile, on
|
||||||
authOpenProfile(username, 'settings');
|
authOpenProfile(username, 'settings');
|
||||||
}, [authOpenProfile, username]);
|
}, [authOpenProfile, username]);
|
||||||
|
|
||||||
// const onMessagesOpen = useCallback(() => {
|
const onAccountsOpen = useCallback(() => {
|
||||||
// authOpenProfile(username, 'messages');
|
authOpenProfile(username, 'accounts');
|
||||||
// }, [authOpenProfile, username]);
|
}, [authOpenProfile, username]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrap}>
|
<div className={styles.wrap}>
|
||||||
|
@ -42,6 +42,7 @@ const UserButton: FC<IProps> = ({ user: { username, photo }, authOpenProfile, on
|
||||||
<div className={styles.menu}>
|
<div className={styles.menu}>
|
||||||
<div onClick={onProfileOpen}>Профиль</div>
|
<div onClick={onProfileOpen}>Профиль</div>
|
||||||
<div onClick={onSettingsOpen}>Настройки</div>
|
<div onClick={onSettingsOpen}>Настройки</div>
|
||||||
|
<div onClick={onAccountsOpen}>Аккаунты</div>
|
||||||
<div onClick={onLogout}>Выдох</div>
|
<div onClick={onLogout}>Выдох</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
120
src/components/profile/ProfileAccounts/index.tsx
Normal file
120
src/components/profile/ProfileAccounts/index.tsx
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
import React, { FC, Fragment, useCallback, useEffect } from 'react';
|
||||||
|
import { ISocialProvider } from '~/redux/auth/types';
|
||||||
|
import styles from './styles.scss';
|
||||||
|
import { Placeholder } from '~/components/placeholders/Placeholder';
|
||||||
|
import { Icon } from '~/components/input/Icon';
|
||||||
|
import { Button } from '~/components/input/Button';
|
||||||
|
import { Group } from '~/components/containers/Group';
|
||||||
|
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
||||||
|
import { selectAuthProfile } from '~/redux/auth/selectors';
|
||||||
|
import { IState } from '~/redux/store';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { API } from '~/constants/api';
|
||||||
|
|
||||||
|
const mapStateToProps = (state: IState) => selectAuthProfile(state).socials;
|
||||||
|
const mapDispatchToProps = {
|
||||||
|
authGetSocials: AUTH_ACTIONS.authGetSocials,
|
||||||
|
authDropSocial: AUTH_ACTIONS.authDropSocial,
|
||||||
|
};
|
||||||
|
|
||||||
|
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||||
|
|
||||||
|
const SOCIAL_ICONS: Record<ISocialProvider, string> = {
|
||||||
|
vkontakte: 'vk',
|
||||||
|
google: 'google',
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProfileAccountsUnconnected: FC<IProps> = ({
|
||||||
|
authGetSocials,
|
||||||
|
authDropSocial,
|
||||||
|
accounts,
|
||||||
|
is_loading,
|
||||||
|
}) => {
|
||||||
|
const onMessage = useCallback(event => {
|
||||||
|
if (event?.data?.type !== 'oauth_attach' || !event?.data?.payload?.token) return;
|
||||||
|
const token = event?.data?.payload?.token;
|
||||||
|
console.log('GOT TOKEN!!!', token);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const openOauthWindow = useCallback(
|
||||||
|
(provider: ISocialProvider) => () => {
|
||||||
|
console.log(API.USER.OAUTH_WINDOW(provider));
|
||||||
|
window.open(API.USER.OAUTH_WINDOW(provider), '', 'width=600,height=400');
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
authGetSocials();
|
||||||
|
}, [authGetSocials]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener('message', onMessage);
|
||||||
|
return () => window.removeEventListener('message', onMessage);
|
||||||
|
}, [onMessage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group className={styles.wrap}>
|
||||||
|
<Group className={styles.info}>
|
||||||
|
<p>
|
||||||
|
Ты можешь входить в Убежище, используя аккаунты на других сайтах вместо ввода логина и
|
||||||
|
пароля.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Мы честно украдём и будем хранить твои имя, фото и адрес на этом сайте, но никому о них не
|
||||||
|
расскажем.
|
||||||
|
</p>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
{is_loading && (
|
||||||
|
<div className={styles.loader}>
|
||||||
|
{[...new Array(accounts.length || 1)].map((_, i) => (
|
||||||
|
<Fragment key={i}>
|
||||||
|
<Placeholder width="50%" />
|
||||||
|
<Placeholder width="auto" />
|
||||||
|
</Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!is_loading && accounts.length > 0 && (
|
||||||
|
<div className={styles.list}>
|
||||||
|
{!is_loading &&
|
||||||
|
accounts.map(it => (
|
||||||
|
<div className={styles.account} key={`${it.provider}-${it.id}`}>
|
||||||
|
<div
|
||||||
|
className={styles.account__photo}
|
||||||
|
style={{ backgroundImage: it.photo ? `url(${it.photo})` : 'none' }}
|
||||||
|
>
|
||||||
|
<div className={styles.account__provider}>
|
||||||
|
<Icon icon={SOCIAL_ICONS[it.provider]} size={12} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.account__name}>{it.name}</div>
|
||||||
|
|
||||||
|
<div className={styles.account__drop}>
|
||||||
|
<Icon icon="close" size={22} onClick={() => authDropSocial(it.provider, it.id)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Group horizontal className={styles.buttons}>
|
||||||
|
<Button size="small" iconLeft="vk" color="gray" onClick={openOauthWindow('vkontakte')}>
|
||||||
|
Вконтакте
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button size="small" iconLeft="google" color="gray" onClick={openOauthWindow('google')}>
|
||||||
|
Google
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProfileAccounts = connect(mapStateToProps, mapDispatchToProps)(ProfileAccountsUnconnected);
|
||||||
|
|
||||||
|
export { ProfileAccounts };
|
80
src/components/profile/ProfileAccounts/styles.scss
Normal file
80
src/components/profile/ProfileAccounts/styles.scss
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
.wrap {
|
||||||
|
padding: $gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
padding: $gap;
|
||||||
|
box-shadow: inset transparentize(white, 0.9) 0 0 0 2px;
|
||||||
|
border-radius: $radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
background: transparentize(black, 0.8);
|
||||||
|
border-radius: $radius;
|
||||||
|
padding: $gap / 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
//background-color: $content_bg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
display: grid;
|
||||||
|
grid-row-gap: $gap;
|
||||||
|
grid-column-gap: $gap * 4;
|
||||||
|
grid-template-columns: 1fr 32px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
height: 48px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20px auto 20px;
|
||||||
|
grid-column-gap: $gap * 1.5;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__photo {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
background: 50% 50% no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
border-radius: 2px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__provider {
|
||||||
|
position: absolute;
|
||||||
|
right: -2px;
|
||||||
|
bottom: -8px;
|
||||||
|
background: $content_bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
font: $font_16_semibold;
|
||||||
|
padding-left: $gap / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__drop {
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.25s;
|
||||||
|
fill: $red;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
padding: $gap;
|
||||||
|
font: $font_14_regular;
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import { InputText } from '~/components/input/InputText';
|
||||||
import reject from 'ramda/es/reject';
|
import reject from 'ramda/es/reject';
|
||||||
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
||||||
import { ERROR_LITERAL } from '~/constants/errors';
|
import { ERROR_LITERAL } from '~/constants/errors';
|
||||||
import { ProfileSettingsSocials } from '~/components/profile/ProfileSettingsSocials';
|
import { ProfileAccounts } from '~/components/profile/ProfileAccounts';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
user: selectAuthUser(state),
|
user: selectAuthUser(state),
|
||||||
|
@ -20,8 +20,6 @@ const mapStateToProps = state => ({
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
authPatchUser: AUTH_ACTIONS.authPatchUser,
|
authPatchUser: AUTH_ACTIONS.authPatchUser,
|
||||||
authSetProfile: AUTH_ACTIONS.authSetProfile,
|
authSetProfile: AUTH_ACTIONS.authSetProfile,
|
||||||
authGetSocials: AUTH_ACTIONS.authGetSocials,
|
|
||||||
authDropSocial: AUTH_ACTIONS.authDropSocial,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
type IProps = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||||
|
@ -31,8 +29,6 @@ const ProfileSettingsUnconnected: FC<IProps> = ({
|
||||||
profile: { patch_errors, socials },
|
profile: { patch_errors, socials },
|
||||||
authPatchUser,
|
authPatchUser,
|
||||||
authSetProfile,
|
authSetProfile,
|
||||||
authGetSocials,
|
|
||||||
authDropSocial,
|
|
||||||
}) => {
|
}) => {
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [new_password, setNewPassword] = useState('');
|
const [new_password, setNewPassword] = useState('');
|
||||||
|
@ -73,6 +69,7 @@ const ProfileSettingsUnconnected: FC<IProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={styles.wrap} onSubmit={onSubmit}>
|
<form className={styles.wrap} onSubmit={onSubmit}>
|
||||||
|
<Group>
|
||||||
<Group>
|
<Group>
|
||||||
<InputText
|
<InputText
|
||||||
value={data.fullname}
|
value={data.fullname}
|
||||||
|
@ -84,16 +81,10 @@ const ProfileSettingsUnconnected: FC<IProps> = ({
|
||||||
<Textarea value={data.description} handler={setDescription} title="Описание" />
|
<Textarea value={data.description} handler={setDescription} title="Описание" />
|
||||||
|
|
||||||
<div className={styles.small}>
|
<div className={styles.small}>
|
||||||
Описание будет видно на странице профиля. Здесь работают те же правила оформления, что и в
|
Описание будет видно на странице профиля. Здесь работают те же правила оформления, что и
|
||||||
комментариях.
|
в комментариях.
|
||||||
</div>
|
</div>
|
||||||
|
</Group>
|
||||||
<ProfileSettingsSocials
|
|
||||||
accounts={socials.accounts}
|
|
||||||
is_loading={socials.is_loading}
|
|
||||||
authGetSocials={authGetSocials}
|
|
||||||
authDropSocial={authDropSocial}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Group className={styles.pad}>
|
<Group className={styles.pad}>
|
||||||
<InputText
|
<InputText
|
||||||
|
@ -133,6 +124,8 @@ const ProfileSettingsUnconnected: FC<IProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
|
<Filler />
|
||||||
|
|
||||||
<Group horizontal>
|
<Group horizontal>
|
||||||
<Filler />
|
<Filler />
|
||||||
<Button title="Сохранить" type="submit" />
|
<Button title="Сохранить" type="submit" />
|
||||||
|
|
|
@ -12,3 +12,6 @@
|
||||||
font: $font_12_regular;
|
font: $font_12_regular;
|
||||||
padding: 0 $gap $gap;
|
padding: 0 $gap $gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
}
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
import React, { FC, useEffect, Fragment } from 'react';
|
|
||||||
import * as AUTH_ACTIONS from '~/redux/auth/actions';
|
|
||||||
import { IAuthState, ISocialProvider } from '~/redux/auth/types';
|
|
||||||
import styles from './styles.scss';
|
|
||||||
import { Placeholder } from '~/components/placeholders/Placeholder';
|
|
||||||
import { Icon } from '~/components/input/Icon';
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
accounts: IAuthState['profile']['socials']['accounts'];
|
|
||||||
is_loading: boolean;
|
|
||||||
authGetSocials: typeof AUTH_ACTIONS.authGetSocials;
|
|
||||||
authDropSocial: typeof AUTH_ACTIONS.authDropSocial;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SOCIAL_ICONS: Record<ISocialProvider, string> = {
|
|
||||||
vkontakte: 'vk',
|
|
||||||
google: 'google',
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProfileSettingsSocials: FC<IProps> = ({
|
|
||||||
authGetSocials,
|
|
||||||
authDropSocial,
|
|
||||||
accounts,
|
|
||||||
is_loading,
|
|
||||||
}) => {
|
|
||||||
useEffect(() => {
|
|
||||||
authGetSocials();
|
|
||||||
}, [authGetSocials]);
|
|
||||||
|
|
||||||
if (!accounts.length) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.wrap}>
|
|
||||||
{is_loading && (
|
|
||||||
<div className={styles.loader}>
|
|
||||||
{[...new Array(accounts.length || 1)].map((_, i) => (
|
|
||||||
<Fragment key={i}>
|
|
||||||
<Placeholder width="50%" />
|
|
||||||
<Placeholder width="auto" />
|
|
||||||
</Fragment>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!is_loading &&
|
|
||||||
accounts.map(it => (
|
|
||||||
<div className={styles.account}>
|
|
||||||
<div className={styles.account__provider}>
|
|
||||||
<Icon icon={SOCIAL_ICONS[it.provider]} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.account__name}>{it.name}</div>
|
|
||||||
|
|
||||||
<div className={styles.account__drop}>
|
|
||||||
<Icon icon="close" size={22} onClick={() => authDropSocial(it.provider, it.id)} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { ProfileSettingsSocials };
|
|
|
@ -1,36 +0,0 @@
|
||||||
.wrap {
|
|
||||||
padding: $gap,
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader {
|
|
||||||
display: grid;
|
|
||||||
grid-row-gap: $gap;
|
|
||||||
grid-column-gap: $gap * 4;
|
|
||||||
grid-template-columns: 1fr 32px;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
height: 22px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.account {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 20px auto 20px;
|
|
||||||
grid-column-gap: $gap;
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
font: $font_16_semibold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__drop {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.5;
|
|
||||||
transition: opacity 0.25s;
|
|
||||||
fill: $red;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,12 @@
|
||||||
import { INode, IComment } from '~/redux/types';
|
import { INode, IComment } from '~/redux/types';
|
||||||
|
import { ISocialProvider } from '~/redux/auth/types';
|
||||||
|
|
||||||
export const API = {
|
export const API = {
|
||||||
BASE: process.env.API_HOST,
|
BASE: process.env.API_HOST,
|
||||||
USER: {
|
USER: {
|
||||||
LOGIN: '/user/login',
|
LOGIN: '/user/login',
|
||||||
|
OAUTH_WINDOW: (provider: ISocialProvider) =>
|
||||||
|
`${process.env.API_HOST}oauth/${provider}/redirect`,
|
||||||
VKONTAKTE_LOGIN: `${process.env.API_HOST}/oauth/vkontakte/redirect/login`,
|
VKONTAKTE_LOGIN: `${process.env.API_HOST}/oauth/vkontakte/redirect/login`,
|
||||||
ME: '/user/',
|
ME: '/user/',
|
||||||
PROFILE: (username: string) => `/user/user/${username}/profile`,
|
PROFILE: (username: string) => `/user/user/${username}/profile`,
|
||||||
|
|
|
@ -11,11 +11,13 @@ import { IAuthState } from '~/redux/auth/types';
|
||||||
import pick from 'ramda/es/pick';
|
import pick from 'ramda/es/pick';
|
||||||
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
|
import { CoverBackdrop } from '~/components/containers/CoverBackdrop';
|
||||||
import { ProfileSettings } from '~/components/profile/ProfileSettings';
|
import { ProfileSettings } from '~/components/profile/ProfileSettings';
|
||||||
|
import { ProfileAccounts } from '~/components/profile/ProfileAccounts';
|
||||||
|
|
||||||
const TAB_CONTENT = {
|
const TAB_CONTENT = {
|
||||||
profile: <ProfileDescription />,
|
profile: <ProfileDescription />,
|
||||||
messages: <ProfileMessages />,
|
messages: <ProfileMessages />,
|
||||||
settings: <ProfileSettings />,
|
settings: <ProfileSettings />,
|
||||||
|
accounts: <ProfileAccounts />,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
@ -59,9 +61,6 @@ const ProfileDialogUnconnected: FC<IProps> = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ProfileDialog = connect(
|
const ProfileDialog = connect(mapStateToProps, mapDispatchToProps)(ProfileDialogUnconnected);
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(ProfileDialogUnconnected);
|
|
||||||
|
|
||||||
export { ProfileDialog };
|
export { ProfileDialog };
|
||||||
|
|
|
@ -23,12 +23,21 @@ const ProfileTabs: FC<IProps> = ({ tab, is_own, setTab }) => (
|
||||||
Сообщения
|
Сообщения
|
||||||
</div>
|
</div>
|
||||||
{is_own && (
|
{is_own && (
|
||||||
|
<>
|
||||||
<div
|
<div
|
||||||
className={classNames(styles.tab, { [styles.active]: tab === 'settings' })}
|
className={classNames(styles.tab, { [styles.active]: tab === 'settings' })}
|
||||||
onClick={() => setTab('settings')}
|
onClick={() => setTab('settings')}
|
||||||
>
|
>
|
||||||
Настройки
|
Настройки
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={classNames(styles.tab, { [styles.active]: tab === 'accounts' })}
|
||||||
|
onClick={() => setTab('accounts')}
|
||||||
|
>
|
||||||
|
Аккаунты
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -49,7 +49,7 @@ export type IAuthState = Readonly<{
|
||||||
};
|
};
|
||||||
|
|
||||||
profile: {
|
profile: {
|
||||||
tab: 'profile' | 'messages' | 'settings';
|
tab: 'profile' | 'messages' | 'settings' | 'accounts';
|
||||||
is_loading: boolean;
|
is_loading: boolean;
|
||||||
is_loading_messages: boolean;
|
is_loading_messages: boolean;
|
||||||
is_sending_messages: boolean;
|
is_sending_messages: boolean;
|
||||||
|
|
|
@ -228,6 +228,13 @@ const Sprites: FC<{}> = () => (
|
||||||
<path d="m 149.9375,79.222656 c 0,0 -63.218849,5.9e-5 -79.085938,4.123047 -8.495787,2.373802 -15.491408,9.3695 -17.865234,17.990237 -4.122953,15.8671 -4.123047,48.72656 -4.123047,48.72656 0,0 9.4e-5,32.9842 4.123047,48.60156 2.373826,8.62062 9.244506,15.49138 17.865234,17.86524 15.99203,4.24788 79.085938,4.24804 79.085938,4.24804 0,0 63.34418,-5e-5 79.21094,-4.12304 8.62079,-2.37381 15.49133,-9.11966 17.74023,-17.86524 4.24793,-15.74232 4.24805,-48.60156 4.24805,-48.60156 0,0 0.12484,-32.98446 -4.24805,-48.85156 -2.2489,-8.620737 -9.11944,-15.491334 -17.74023,-17.740237 -15.86676,-4.372847 -79.21094,-4.373047 -79.21094,-4.373047 z m -20.11523,40.480464 52.59961,30.35938 -52.59961,30.23438 0,-60.59376 z" />
|
<path d="m 149.9375,79.222656 c 0,0 -63.218849,5.9e-5 -79.085938,4.123047 -8.495787,2.373802 -15.491408,9.3695 -17.865234,17.990237 -4.122953,15.8671 -4.123047,48.72656 -4.123047,48.72656 0,0 9.4e-5,32.9842 4.123047,48.60156 2.373826,8.62062 9.244506,15.49138 17.865234,17.86524 15.99203,4.24788 79.085938,4.24804 79.085938,4.24804 0,0 63.34418,-5e-5 79.21094,-4.12304 8.62079,-2.37381 15.49133,-9.11966 17.74023,-17.86524 4.24793,-15.74232 4.24805,-48.60156 4.24805,-48.60156 0,0 0.12484,-32.98446 -4.24805,-48.85156 -2.2489,-8.620737 -9.11944,-15.491334 -17.74023,-17.740237 -15.86676,-4.372847 -79.21094,-4.373047 -79.21094,-4.373047 z m -20.11523,40.480464 52.59961,30.35938 -52.59961,30.23438 0,-60.59376 z" />
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
|
<g id="google" stroke="none">
|
||||||
|
<path
|
||||||
|
d="M896 786h725q12 67 12 128 0 217-91 387.5t-259.5 266.5-386.5 96q-157 0-299-60.5t-245-163.5-163.5-245-60.5-299 60.5-299 163.5-245 245-163.5 299-60.5q300 0 515 201l-209 201q-123-119-306-119-129 0-238.5 65t-173.5 176.5-64 243.5 64 243.5 173.5 176.5 238.5 65q87 0 160-24t120-60 82-82 51.5-87 22.5-78h-436v-264z"
|
||||||
|
transform="scale(0.011) translate(120, 120)"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue