update
This commit is contained in:
+5
-24
@@ -1,28 +1,8 @@
|
||||
//go:build !wireinject
|
||||
// +build !wireinject
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate go run github.com/google/wire/cmd/wire
|
||||
//go:build !wireinject
|
||||
// +build !wireinject
|
||||
|
||||
package answercmd
|
||||
|
||||
@@ -169,7 +149,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||
collectionCommon := collectioncommon.NewCollectionCommon(collectionRepo)
|
||||
answerCommon := answercommon.NewAnswerCommon(answerRepo)
|
||||
metaRepo := meta.NewMetaRepo(dataData)
|
||||
metaService := meta2.NewMetaService(metaRepo)
|
||||
metaService := meta2.NewMetaService(metaRepo, userCommon)
|
||||
questionCommon := questioncommon.NewQuestionCommon(questionRepo, answerRepo, voteRepo, followRepo, tagCommonService, userCommon, collectionCommon, answerCommon, metaService, configService, activityQueueService, revisionRepo, dataData)
|
||||
userService := content.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, siteInfoCommonService, userRoleRelService, userCommon, userExternalLoginService, userNotificationConfigRepo, userNotificationConfigService, questionCommon)
|
||||
captchaRepo := captcha.NewCaptchaRepo(dataData)
|
||||
@@ -250,7 +230,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
||||
permissionController := controller.NewPermissionController(rankService)
|
||||
userPluginController := controller.NewUserPluginController(pluginCommonService)
|
||||
reviewController := controller.NewReviewController(reviewService, rankService, captchaService)
|
||||
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController)
|
||||
metaController := controller.NewMetaController(metaService)
|
||||
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController)
|
||||
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
|
||||
uiRouter := router.NewUIRouter(controllerSiteInfoController, siteInfoCommonService)
|
||||
authUserMiddleware := middleware.NewAuthUserMiddleware(authService, siteInfoCommonService)
|
||||
|
||||
@@ -103,6 +103,7 @@ const (
|
||||
AddBulkUsersFormatError = "error.user.add_bulk_users_format_error"
|
||||
AddBulkUsersAmountError = "error.user.add_bulk_users_amount_error"
|
||||
InvalidURLError = "error.common.invalid_url"
|
||||
MetaObjectNotFound = "error.meta.object_not_found"
|
||||
)
|
||||
|
||||
// user external login reasons
|
||||
|
||||
@@ -49,4 +49,5 @@ var ProviderSetController = wire.NewSet(
|
||||
NewUserPluginController,
|
||||
NewReviewController,
|
||||
NewCaptchaController,
|
||||
NewMetaController,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/apache/incubator-answer/internal/base/handler"
|
||||
"github.com/apache/incubator-answer/internal/base/middleware"
|
||||
"github.com/apache/incubator-answer/internal/schema"
|
||||
"github.com/apache/incubator-answer/internal/service/meta"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type MetaController struct {
|
||||
metaService *meta.MetaService
|
||||
}
|
||||
|
||||
func NewMetaController(
|
||||
metaService *meta.MetaService,
|
||||
) *MetaController {
|
||||
return &MetaController{
|
||||
metaService: metaService,
|
||||
}
|
||||
}
|
||||
|
||||
// AddOrUpdateReaction add or update reaction
|
||||
// @Summary add or update reaction
|
||||
// @Description update reaction. if not exist, add one
|
||||
// @Tags Meta
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Param data body schema.ReactionReq true "reaction"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/api/v1/meta/reaction [put]
|
||||
func (mc *MetaController) AddOrUpdateReaction(ctx *gin.Context) {
|
||||
req := &schema.ReactionReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
|
||||
|
||||
resp, err := mc.metaService.AddOrUpdateReaction(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
QuestionCloseReasonKey = "question.close.reason"
|
||||
AnswerEditSummaryKey = "answer.edit.summary"
|
||||
TagEditSummaryKey = "tag.edit.summary"
|
||||
ObjectReactSummaryKey = "object.react.summary"
|
||||
)
|
||||
|
||||
// Meta meta
|
||||
|
||||
@@ -54,6 +54,7 @@ type AnswerAPIRouter struct {
|
||||
permissionController *controller.PermissionController
|
||||
userPluginController *controller.UserPluginController
|
||||
reviewController *controller.ReviewController
|
||||
metaController *controller.MetaController
|
||||
}
|
||||
|
||||
func NewAnswerAPIRouter(
|
||||
@@ -84,6 +85,7 @@ func NewAnswerAPIRouter(
|
||||
permissionController *controller.PermissionController,
|
||||
userPluginController *controller.UserPluginController,
|
||||
reviewController *controller.ReviewController,
|
||||
metaController *controller.MetaController,
|
||||
) *AnswerAPIRouter {
|
||||
return &AnswerAPIRouter{
|
||||
langController: langController,
|
||||
@@ -113,6 +115,7 @@ func NewAnswerAPIRouter(
|
||||
permissionController: permissionController,
|
||||
userPluginController: userPluginController,
|
||||
reviewController: reviewController,
|
||||
metaController: metaController,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,6 +288,9 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
|
||||
r.GET("/user/plugin/configs", a.userPluginController.GetUserPluginList)
|
||||
r.GET("/user/plugin/config", a.userPluginController.GetUserPluginConfig)
|
||||
r.PUT("/user/plugin/config", a.userPluginController.UpdatePluginUserConfig)
|
||||
|
||||
// meta
|
||||
r.PUT("/meta/reaction", a.metaController.AddOrUpdateReaction)
|
||||
}
|
||||
|
||||
func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package schema
|
||||
|
||||
type ReactionReq struct {
|
||||
ObjectID string `validate:"required" form:"object_id" json:"object_id"` // object id
|
||||
Emoji string `validate:"required" form:"emoji" json:"emoji"` // emoji
|
||||
Type string `validate:"required" form:"type" json:"type"` // type
|
||||
UserID string `json:"-"`
|
||||
}
|
||||
|
||||
type ReactSummaryMeta map[string][]string
|
||||
|
||||
type ReactionResp ReactSummaryMeta
|
||||
@@ -23,9 +23,10 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/apache/incubator-answer/internal/service/activity_common"
|
||||
"strings"
|
||||
|
||||
"github.com/apache/incubator-answer/internal/service/activity_common"
|
||||
|
||||
"github.com/apache/incubator-answer/internal/base/constant"
|
||||
"github.com/apache/incubator-answer/internal/base/handler"
|
||||
"github.com/apache/incubator-answer/internal/entity"
|
||||
|
||||
@@ -21,10 +21,14 @@ package meta
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/apache/incubator-answer/internal/base/reason"
|
||||
"github.com/apache/incubator-answer/internal/entity"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"github.com/apache/incubator-answer/internal/schema"
|
||||
usercommon "github.com/apache/incubator-answer/internal/service/user_common"
|
||||
myErrors "github.com/segmentfault/pacman/errors"
|
||||
)
|
||||
|
||||
// MetaRepo meta repository
|
||||
@@ -38,12 +42,14 @@ type MetaRepo interface {
|
||||
|
||||
// MetaService user service
|
||||
type MetaService struct {
|
||||
metaRepo MetaRepo
|
||||
metaRepo MetaRepo
|
||||
userCommon *usercommon.UserCommon
|
||||
}
|
||||
|
||||
func NewMetaService(metaRepo MetaRepo) *MetaService {
|
||||
func NewMetaService(metaRepo MetaRepo, userCommon *usercommon.UserCommon) *MetaService {
|
||||
return &MetaService{
|
||||
metaRepo: metaRepo,
|
||||
metaRepo: metaRepo,
|
||||
userCommon: userCommon,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +85,7 @@ func (ms *MetaService) GetMetaByObjectIdAndKey(ctx context.Context, objectID, ke
|
||||
return
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.UnknownError)
|
||||
return nil, myErrors.BadRequest(reason.MetaObjectNotFound)
|
||||
}
|
||||
return meta, nil
|
||||
}
|
||||
@@ -92,3 +98,136 @@ func (ms *MetaService) GetMetaList(ctx context.Context, objID string) (metas []*
|
||||
}
|
||||
return metas, err
|
||||
}
|
||||
|
||||
// GetReactionByObjectId get reaction
|
||||
func (ms *MetaService) GetReactionByObjectId(ctx context.Context, objectID string) (resp schema.ReactionResp, err error) {
|
||||
reactionMeta, err := ms.GetMetaByObjectIdAndKey(ctx, objectID, entity.ObjectReactSummaryKey)
|
||||
|
||||
// if not exist, return nil
|
||||
if err != nil {
|
||||
var pacmanErr *myErrors.Error
|
||||
if errors.As(err, &pacmanErr) && pacmanErr.Reason == reason.MetaObjectNotFound {
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var reaction schema.ReactSummaryMeta
|
||||
err = json.Unmarshal([]byte(reactionMeta.Value), &reaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ms.convertToReactionResp(ctx, reaction)
|
||||
}
|
||||
|
||||
// AddOrUpdateReaction add or update reaction
|
||||
func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.ReactionReq) (resp schema.ReactionResp, err error) {
|
||||
// get reaction for this object
|
||||
reactionMeta, err := ms.GetMetaByObjectIdAndKey(ctx, req.ObjectID, entity.ObjectReactSummaryKey)
|
||||
|
||||
var reaction schema.ReactSummaryMeta
|
||||
if err != nil {
|
||||
var pacmanErr *myErrors.Error
|
||||
if errors.As(err, &pacmanErr) && pacmanErr.Reason == reason.MetaObjectNotFound {
|
||||
// create new reaction summary
|
||||
reaction = schema.ReactSummaryMeta{}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// json unmarshal reactionMeta.Value to reaction
|
||||
err = json.Unmarshal([]byte(reactionMeta.Value), &reaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// update reaction
|
||||
ms.updateReaction(req, reaction)
|
||||
|
||||
// write back to meta repo
|
||||
reactSumBytes, err := json.Marshal(reaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reactionMeta == nil {
|
||||
err = ms.AddMeta(ctx, req.ObjectID, entity.ObjectReactSummaryKey, string(reactSumBytes))
|
||||
} else {
|
||||
err = ms.UpdateMeta(ctx, reactionMeta.ID, entity.ObjectReactSummaryKey, string(reactSumBytes))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err = ms.convertToReactionResp(ctx, reaction)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// updateReaction update reaction
|
||||
func (ms *MetaService) updateReaction(req *schema.ReactionReq, reaction schema.ReactSummaryMeta) {
|
||||
emojiUserIds, ok := reaction[req.Emoji]
|
||||
|
||||
if !ok {
|
||||
emojiUserIds = make([]string, 0)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, item := range emojiUserIds {
|
||||
if item == req.UserID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
removeItem := func(arr []string, target string) []string {
|
||||
result := make([]string, 0, len(arr))
|
||||
|
||||
for _, item := range arr {
|
||||
if item != target {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
if req.Type == "activate" && !found {
|
||||
emojiUserIds = append(emojiUserIds, req.UserID)
|
||||
} else if req.Type == "deactivate" && found {
|
||||
emojiUserIds = removeItem(emojiUserIds, req.UserID)
|
||||
} else if req.Type == "toggle" {
|
||||
if found {
|
||||
emojiUserIds = removeItem(emojiUserIds, req.UserID)
|
||||
} else {
|
||||
emojiUserIds = append(emojiUserIds, req.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
reaction[req.Emoji] = emojiUserIds
|
||||
}
|
||||
|
||||
func (ms *MetaService) convertToReactionResp(ctx context.Context, reaction schema.ReactSummaryMeta) (schema.ReactionResp, error) {
|
||||
resp := schema.ReactionResp{}
|
||||
// traverse map and convert to user name
|
||||
for emoji, userIds := range reaction {
|
||||
userNames := make([]string, 0)
|
||||
userBasicInfos, err := ms.userCommon.BatchUserBasicInfoByID(ctx, userIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// get user name
|
||||
for _, userBasicInfo := range userBasicInfos {
|
||||
userNames = append(userNames, userBasicInfo.Username)
|
||||
}
|
||||
resp[emoji] = userNames
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import { scrollToElementTop, bgFadeOut } from '@/utils';
|
||||
import { AnswerItem } from '@/common/interface';
|
||||
import { acceptanceAnswer } from '@/services';
|
||||
import { useRenderHtmlPlugin } from '@/utils/pluginKit';
|
||||
import Reactions from '../Reactions';
|
||||
|
||||
interface Props {
|
||||
data: AnswerItem;
|
||||
@@ -198,6 +199,8 @@ const Index: FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Reactions />
|
||||
|
||||
<Comment
|
||||
objectId={data.id}
|
||||
mode="answer"
|
||||
|
||||
@@ -37,6 +37,7 @@ import { useRenderHtmlPlugin } from '@/utils/pluginKit';
|
||||
import { formatCount, guard } from '@/utils';
|
||||
import { following } from '@/services';
|
||||
import { pathFactory } from '@/router/pathFactory';
|
||||
import Reactions from '../Reactions';
|
||||
|
||||
interface Props {
|
||||
data: any;
|
||||
@@ -212,6 +213,8 @@ const Index: FC<Props> = ({ data, initPage, hasAnswer, isLogged }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Reactions />
|
||||
|
||||
<Comment
|
||||
objectId={data?.id}
|
||||
mode="question"
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { FC, memo } from 'react';
|
||||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
|
||||
import { Icon } from '@/components';
|
||||
|
||||
interface Props {}
|
||||
|
||||
interface Data {
|
||||
title: string;
|
||||
icon: string;
|
||||
className: string;
|
||||
}
|
||||
|
||||
const data: Data[] = [
|
||||
{ title: 'hello', icon: 'heart-fill', className: 'text-danger' },
|
||||
{ title: 'hello', icon: 'emoji-laughing-fill', className: 'text-warning' },
|
||||
{ title: 'hello', icon: 'emoji-frown-fill', className: 'text-warning' },
|
||||
];
|
||||
|
||||
const Index: FC<Props> = () => {
|
||||
const renderTooltip = (props) => (
|
||||
<Tooltip id="reaction-button-tooltip" {...props} bsPrefix="tooltip">
|
||||
<div className="d-block d-md-flex flex-wrap m-0 p-0">
|
||||
{data.map((d) => (
|
||||
<Button
|
||||
key={d.icon}
|
||||
variant="light"
|
||||
size="sm"
|
||||
onClick={() => alert('hellob')}>
|
||||
<Icon name={d.icon} className={d.className} />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="d-block d-md-flex flex-wrap mt-4 mb-3">
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
className="rounded-pill answer-reaction-btn"
|
||||
size="sm">
|
||||
<Icon name="chat-text-fill" />
|
||||
<span className="ms-1">{6} comments</span>
|
||||
</Button>
|
||||
|
||||
<OverlayTrigger trigger="click" placement="top" overlay={renderTooltip}>
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
size="sm"
|
||||
className="rounded-pill ms-2 answer-reaction-btn">
|
||||
<Icon name="emoji-smile-fill" />
|
||||
<span className="ms-1">+</span>
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
|
||||
{/* <div className="arrow" /> */}
|
||||
|
||||
{data.map((d) => (
|
||||
<OverlayTrigger
|
||||
placement="top"
|
||||
// trigger="hover"
|
||||
trigger="click"
|
||||
overlay={
|
||||
<Tooltip>
|
||||
<div className="text-start">
|
||||
<b>heart</b> <br /> fenbox, joyqi, robin, andrus, jackathon and
|
||||
7 more...
|
||||
</div>
|
||||
</Tooltip>
|
||||
}>
|
||||
<Button
|
||||
title="hahah"
|
||||
variant="outline-secondary"
|
||||
className="rounded-pill ms-2 answer-reaction-btn"
|
||||
size="sm">
|
||||
<Icon name={d.icon} className={d.className} />
|
||||
<span className="ms-1">{3}</span>
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
||||
@@ -16,15 +16,53 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
|
||||
.answer-item {
|
||||
border-top: 1px solid var(--an-answer-item-border-top);
|
||||
.answer-reaction-btn {
|
||||
padding-top: 0.2rem;
|
||||
padding-bottom: 0.2rem;
|
||||
border: 1px solid $gray-300;
|
||||
}
|
||||
|
||||
#reaction-button-tooltip {
|
||||
.tooltip-inner {
|
||||
padding: 0.2rem;
|
||||
background-color: $white;
|
||||
border: 1px solid $gray-300;
|
||||
.btn {
|
||||
background-color: $white;
|
||||
border: none;
|
||||
&:hover {
|
||||
background-color: $gray-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
overflow: hidden;
|
||||
bottom: calc(-1 * $tooltip-arrow-height + 1px);
|
||||
// width: calc($tooltip-arrow-width + 4px);
|
||||
// height: calc($tooltip-arrow-height + 2px);
|
||||
// box-sizing: content-box;
|
||||
&::before {
|
||||
border: 1px solid $gray-300;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
transform: translate(-50%, -50%) rotate(-45deg);
|
||||
// transform: rotate(-45deg);
|
||||
box-sizing: content-box;
|
||||
left: 50%;
|
||||
bottom: 50%;
|
||||
background-color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.questionDetailPage {
|
||||
h1.h3 {
|
||||
font-size: calc(1.275rem + .3vw)!important;
|
||||
font-size: calc(1.275rem + 0.3vw) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user